Convenções de passagem de parâmetros a funções

Este artigo mostra como invocar de funções e passar parâmetros a essas funções, em assembly x86. São apresentadas as convenções do C e do Pascal.

Segue um exemplo de um programa em C e de uma solução equivalente em assembly.

C Assembly
int main() {
int x=5, y=7, z;
z = soma(x,y);
}
section  .data
x    dd                  5
y    dd                  7
z    dd                  0
section  .text
push              dword[y]
push              dword[x]
call                 soma
add                esp, 8
mov               dword[z], eax
int soma(int a, int b) {
return a+b;
}
soma:
push              ebp
mov               ebp, esp
mov               eax, [ebp+8]
add                eax, [ebp+12]
pop                ebp
ret

Como se pode ver no exemplo acima, o C carrega os parâmetros da direita para a esquerda. Assim, o primeiro parâmetro a ser carregado em stack é o y e depois o x. Por fim, invoca a função.

Quando o controlo retorna da função, o programa de chamada tem que acertar a stack. Isso é feito, adicionando 8 unidades ao stack pointer, 4 unidades por cada parâmetro carregado, pois num máquina a 32 bits, todos os movimentos em stack são a 32 bits.

De seguida, apresenta-se um exemplo de um programa em Pascal e de uma solução equivalente em assembly.

Pascal Assembly
program somar;
var
x, y, z: integer;function soma(a,b: integer): integer;
begin
soma := a+b;
end;begin
x := 5;
y := 7;
z := soma(x,y);
end.
section   .data
x   dd                 5
y   dd                 7
z   dd                 0
section  .text
push            dword[x]
push            dword[y]
call               soma
mov             dword[z], eax
soma:
push            ebp
mov             ebp, esp
mov             eax, [ebp+12]
add              eax, [ebp+8]
pop              ebp
ret                8

Como se pode ver no exemplo acima, o Pascal carrega os parâmetros da esquerda para a direita. Assim, o primeiro parâmetro a ser carregado em stack é o x e depois o y. Por fim, invoca a função.

Na convenção do Pascal, o acerto da stack é feito dentro da função, na instrução ret. O ret 8 adiciona 8 unidades ao stack pointer, 4 unidades por cada parâmetro carregado.

Como o acerto da stack é feito dentro da função, é obrigatório passar exatamente 2 parâmetros quando se invoca esta função.

Em C, por outro lado, como o acerto da stack é feito no programa de chamada, podemos passar o número de parâmetros que entendermos, mesmo que sejam diferentes, em número, do que a função espera.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *