Aula 8 Procedimentos e funções Procedimentos e Funções • Chamada CALL label • Retorno RET • Ex: ... ... Call TESTE ... ... TESTE: #codigo da funcao ret 1 Procedimentos e Funções • Chamada CALL label • Empilha a próxima instrução a ser executada e desvia para a função – PUSH ENDERECO_DA_PROXIMA_INSTRUCAO – JUMP FUNCAO Procedimentos e Funções • Chamada RET • EIP <= (%ESP) • %ESP <= %ESP – 4 • * Importante, quando manipular a pilha dentro de uma função, a mesma deverá estar no seu estado inicial antes da operação RET 2 Procedimentos - C • Utilizada no C* – Todos os parâmetros são passados usando a pilha – Todos os parâmetros são alinhados em 32 bits – Note que a ordem dos parâmetros é do último para o primeiro (pense como implementar o printf, se os parâmetros fossem passados em ordem diferente) – A instrução CALL armazena o endereço de retorno ESP return addr param 1 param 2 ... param N *SystemV ABI- http://www.caldera.com/developers/devspecs/abi386-4.pdf Convenção utilizada no C • Logo após a entrada na função o valor do ESP registrador EBP (base pointer) e colocado no topo da pilha • O novo EBP, recebe o valor do registrador ESP • Essa série de instruções é denominada prologue procA: push %EBP mov %ESP, %EBP OLD_EBP return addr param 1 param 2 ... param N 3 FRAME • O registrador EBP é utilizado para delimitar o ESP “frame” da função • A pilha é utilizada também para armazenar todas as variáveis locais, assim o registrador EBP é utilizado para endereçar tais variáveis EBP void PROC(){ int A, B; A= 1 } Em assembler: PROC: push %ESP mov %ESP, %EBP sub $8, %ESP #alocando espaço para as variaveis A e B B A OLD_EBP return addr param 1 param 2 ... mov $1, -4(%EBP) param N Retorno EBX ESP • Recuperar o antigo valor de EBP e ajustar o ponteiro da pilha • Essa série de instruções é denominada epilogue • Atenção: todos os registradores devem ter os valores preservados, portanto os mesmos devem ser salvos e recuperados antes de retornarem da função • Ex: PROC: push %ESP mov %ESP, %EBP sub $8, %ESP #alocando espaço para as variaveis A e B push %eax #salvando os antigos valores push %ebx #salvando os antigos valores ... ... ... Codigo da função pop %ebx pop %eax leave # (ESP <- EBP, POP EBP): restaura o frame ret EAX B A EBP OLD_EBP return addr param 1 param 2 ... param N 4 Retorno • Recuperar o antigo valor de EBP e ajustar o ponteiro da pilha • Atenção: todos os registradores devem ter os valores preservados, portanto os mesmos devem ESP ser salvos e recuperados antes de retornarem da função • Ex: PROC: push %ESP mov %ESP, %EBP sub $8, %ESP #alocando espaço para as variaveis A e B push %eax #salvando os antigos valores push %ebx #salvando os antigos valores ... ... ... Codigo da função pop %ebx pop %eax leave # (ESP <- EBP, POP EBP): restaura o frame ret EBP B A OLD_EBP return addr param 1 param 2 ... param N Retorno • Recuperar o antigo valor de EBP e ajustar o ponteiro da pilha • Atenção: todos os registradores devem ter os valores preservados, portanto os mesmos devem ser salvos e recuperados antes de retornarem da função • Ex: PROC: ESP EBP push %ESP mov %ESP, %EBP sub $8, %ESP #alocando espaço para as variaveis A e B push %eax #salvando os antigos valores push %ebx #salvando os antigos valores ... ... ... Codigo da função pop %ebx pop %eax leave # (ESP <- EBP, POP EBP): restaura o frame ret OLD_EBP return addr param 1 param 2 ... param N 5 Retorno • Recuperar o antigo valor de EBP e ajustar o ponteiro da pilha • Atenção: todos os registradores devem ter os valores preservados, portanto os mesmos devem ser salvos e recuperados antes de retornarem da função • Ex: PROC: push %ESP mov %ESP, %EBP sub $8, %ESP #alocando espaço para as variaveis A e B push %eax #salvando os antigos valores push %ebx #salvando os antigos valores ... ... ... Codigo da função pop %ebx pop %eax add $8, %ESP # elimando o espaco usado pelas var. locais pop %ebp ret ESP return addr param 1 param 2 ... param N Funções • Funções que retornam valores escalares ou ponteiros, utilizam o registrador %eax para armazenar o resultado int soma(int a, int b){ return (a+b) } Soma_2elementos: push %EBP mov %ESP, %EBP movl 8(%ESP), %EAX addl 12(%ESP),%EAX leave ret ESP #valor de a #valor de b OLD_EBP return addr A B ... ... 6 Funções • Funções que retornam struct/union, retornam o endereço através o registrador %EAX • Porém, neste caso, o endereço da struct deve ser passado através da pilha return addr ESP end. struct A B ... ... Funções • A função deve retirar o endereço, antes de executar a operação ret Após o retorno return addr ESP A A ESP B B ... ... ... ... 7 Prologue (struct/union) prologue: popl %eax / pop return address xchgl %eax,0(%esp) / swap return address /and return value address pushl %ebp / save frame pointer movl %esp, %ebp / set new frame pointer subl $80 , %esp / allocate local space pushl %edi / save local register pushl %esi / save local register pushl %ebx / save local register movl %eax , -4(%ebp) / save return value address Epilogue (struct/union) epilogue: movl -4(%ebp), %eax / setup return value popl %ebx / restore local register popl %esi / restore local register popl %edi / restore local register leave / restore frame pointer ret / pop return address 8 Usando gcc • Usando o gcc para compilar programas em assembler .section .data .section .text .global main .type main, @function main: push %ebp #salvando o frame anterior mov %esp, %ebp #novo frame # seu codigo leave ret # recupera o frame anterior # retorna Compilando gcc teste.s –o teste.x - a função _start é agora implementada por uma função padrão que inicializa a pilha de forma adequada, e a biblioteca libc Exercícios • Implemente uma função que some dois números • Implemente uma função que calcule o fatorial de um número 9