Programar em Assembly com GAS/Pilha

Pilha (stack)

editar

A pilha é uma região da memoria central do tipo LIFO (Last In First Out) que significa : o último elemento inserido é o primeiro removido.

Todas as inserções e remoções de elemento só podem ser feitos em uma extremidade chamada topo.

A pilha vai crescendo em direção a endereços menores.

Ela é utilizada principalmente para:

  • Guardar dados temporários de um registrador.
  • Passar parâmetros para uma rotina.

A pilha da direita mostra o estado da pilha depois da instrução push, a pilha é incrementada de 2 bytes ou um word.

 

Guardar o contexto

editar

Quando um programa usa uma outra rotina essa novo contexto não sabe qual são os registros usados pelo programa que faz a chamada. Exemplo:

movl $5, %ecx
call rotina
add $1,%ecx
rotina:
movl $9,%ecx
ret

O programa principal não sabe que a rotina modificou o valor de %ecx no final da execução. Assim, %ecx contém 10 e não 6.

Para evitar esse problema podemos usar a pilha para guarda o valor dos registros que não devem ser modificados.

Exemplo:

movl $5, %ecx
call rotina
add $1,%ecx
rotina:
pushl %ecx
mov $9,%ecx
popl %ecx
ret

Agora no programa que fez a chamada %ecx continua sendo 5.

Passagem de parâmetros

editar
 

Para passar os parâmetros de uma programa para uma rotina colocamos os parâmetros desejados na pilha e executamos a instrução call que por sua vez vai colocar o endereço de retorno na pilha.

Vamos ao exemplo:

pushl %eax  # Na imagem ao lado "Param1"
pushl %ebx  # Na imagem ao lado "Param2"
call rotina # Coloca o endereço de retorno na pilha
addl $8,%esp # coloca a pilha no estado inicial

Quando a rotina usa a instrução ret ela tira da pilha o endereço de retorno mais não atualiza o registro %esp por isso que adicionamos 8 octetos, para colocar %esp no estado inicial.

Para acessar os parâmetros da pilha podemos usar o registro %esp mais esse registro é usado para colocar os dados na pilha. Existe uma solução mais fácil que é usar o registrador %ebp, para isso colocamos o endereço do registro %esp em %ebp mais antes colocamos %ebp na pilha.

rotina:
      pushl %ebp
      movl  %esp,%ebp
      movl  8(%ebp),%eax # Move Param2, igual a %esp + 8 octetos
      addl 12(%ebp),%eax # Adiciona Param1 , igual a %esp + 12 octetos
      movl  %ebp,%esp
      popl  %ebp
      ret