Programar em Assembly com GAS/Pilha
Pilha (stack)
[editar | editar código-fonte]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 | editar código-fonte]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 | editar código-fonte]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