ORGANIZAÇÃO E ARQUITETURA DE COMPUTADORES I AULA 05: LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Prof. Max Santana Rolemberg Farias [email protected] Colegiado de Engenharia de Computação O QUE SÃO PROCEDIMENTOS? LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS • Procedimentos são um conjunto de instruções com função definida. – Realizam uma série de operações com base em valores passados por parâmetros. – Podem retornar valores (função). • A chamada de um procedimento, faz com que o programa execute as instruções contidas no procedimento. – Ao término da execução de um procedimento, o programa deve executar a instrução seguinte à chamada do procedimento. PARA QUE UTILIZAMOS PROCEDIMENTOS E FUNÇÕES? LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS • São utilizados para estruturar um programa. – Facilita entendimento – Aumenta reuso de código (reutilização do código) COMO UM PROCEDIMENTO É EXECUTADO? LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Existem 6 passos para a execução de um procedimento: 1. O programa coloca os parâmetros em um lugar onde o procedimento chamado possa acessá-los. 2. O programa transfere o controle para o procedimento. 3. O procedimento acessa os valores necessários para executar a sua tarefa. 4. O procedimento executa sua tarefa, gerando valores. 5. O procedimento (chamado) coloca os valores gerados em um local onde o programa (chamador) possa acessá-lo. 6. O procedimento transfere o controle de volta para o ponto do programa que o chamou. LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS • Uma CPU simples oferecem alguns registradores específicos para dá suporte a procedimentos. – Registradores para argumentos ($a0 - $a3): Quatro registradores usados como argumentos para passagem de parâmetros. – Registradores de retorno ($v0 - $v1): Dois registradores usados para retornar valores. – Registradores de endereço de retorno ($ra): Registrador que guarda o endereço de retorno (return address) para o ponto do programa que chamou o procedimento. LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS • Uma CPU simple oferecem duas instruções para dá suporte a procedimentos. – Instrução Jump And Link (jal): Pula para o endereço inicial do procedimento e salva o endereço de retorno (endereço da próxima instrução após chamada). $ra <- PC + 4 – Instrução Jump Refister (jr): Pula para o endereço armazenado no registrador. No caso de retorno de procedimentos, o registrador deve ser o $ra. jr $ra LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Formato das Instruções jal • Salta para o endereço especificado, salvando o endereço da próxima instrução em $ra. jal addr $ra <- PC + 4 Assembly jal 0x200C Opcode IMM 0x2 0x200C Linguagem de Máquina 0000 1000 0000 0000 0010 0000 0000 1100 (0x0800200C) LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Formato das Instruções jr • Desvio incondicional para endereço guardado em registradores. Para suporte a procedimento o registrador é o $ra. jr $ra Assembly Jr $ra Opcode RS RT RD Shamt Funct 0x0 31 0 0 0x0 0x8 Linguagem de Máquina 0000 0011 1110 0000 0000 0000 0000 1000 (0x03E00008) COMO PRESERVAR O CONTEXTO DO PROGRAMA? LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS • Restaurar os valores dos registradores usados pelo procedimento para o valor que tinha antes da chamada. – Para isso o conteúdo dos registradores deve ser salvo na memória. E depois da execução do procedimento, estes registradores devem ter seus valores restaurados. • Se as chamadas forem recursivas, é conveniente o uso de uma pilha. LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Implementação com Pilha • A implementação com pilha é uma solução comum, visto que muitos procedimentos precisam de mais registradores que os especificados para o procedimento. – Pode se utilizar parte da memória como pilha. • Utilizando o apontador de pilha (Stack Pointer), que é um registrador especifico ($sp) usado para guardar o endereço do topo da pilha da chamada de procedimentos (o registrador guarda o endereço do topo). • A pilha cresce do endereço mais alto para o mais baixo. LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Organização da memória • Segmento de texto (text) – Código. • Dados estáticos (static data) – Variáveis globais. – Variáveis estáticas. – Em uma CPU simples o registrador $gp guarda o início do segmento. • Dados dinâmicos (heap) – O malloc da linguagem C • Pilha (stack) – Variáveis locais – Registradores LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Implementação com Pilha • Inserir dado na pilha (Push) $sp <- $sp – 4 • remover dado na pilha (Pop) $sp <- $sp + 4 LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Procedimento simples Linguagem de Alto Nível int main(){ simples(); ... } void simples(){ return; } Linguagem de Montagem 0x00400200 jal 0x00401020 #simples() 0x00400204 ... 0x00401020 jr $ra #return LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Procedimento com argumentos Linguagem de Alto Nível int main(){ int y; ... y = diff_sums(2,3,4,5); ... } int diff_sums(int f, int g, int h, int i){ int result; result = (f + g) – (h + i); return result; } A variável y é armazenada nos registrador $s0 Linguagem de Montagem 0x00400200 0x00401020 0x00401024 0x00401028 0x0040102C 0x00401030 0x00401034 0x00401038 0x00401048 0x0040104C 0x00401050 0x00401054 0x00401058 ... addi $a0 $zero 2 #arg0=2 addi $a1 $zero 3 #arg1=3 addi $a2 $zero 4 #arg2=4 addi $a3 $zero 5 #arg3=5 jal 0x00401048 #diff_sums add $s0 $v0 $zero #return ... add $t0 $a0 $a1 #t0=f+g add $t1 $a2 $a3 #t1=h+i sub $s0 $t0 $t1 #s0=t0-t1 add $v0 $s0 $zero #return jr $ra LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Procedimento usando a pilha Linguagem de Alto Nível int main(){ int y; ... y = media(2,3,5,6); ... } int media(int x, int y, int z, int w){ int result; result = (x + y + z + w)/4; return result; } Linguagem de Montagem 0x00400200 0x00401020 0x00401024 0x00401028 0x0040102C 0x00401030 0x00401034 0x00401038 ... addi $a0 $zero 2 #arg0=2 addi $a1 $zero 3 #arg1=3 addi $a2 $zero 5 #arg2=5 addi $a3 $zero 6 #arg3=6 jal 0x00401048 #media add $s0 $v0 $zero #return ... 0x00401048 0x0040104C 0x00401050 0x00401054 addi $sp $sp -12 #reservando sw $t1, 8($sp) #salva $t1 sw $t0, 4($sp) #salva $t0 sw $s0, 0($sp) #salva $s0 $t1 (0x5) $t0 (0x4) $s0 (0x3) A variável y é armazenada no registrador $s0. Os valores de $s0, $t0, $t1 são: 0x3, 0x4 e 0x5. LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Procedimento usando a pilha (Continuação) Linguagem de Alto Nível int main(){ int y; ... y = media(2,3,5,6); ... } int media(int x, int y, int z, int w){ int result; result = (x + y + z + w)/4; return result; } Linguagem de Montagem 0x00401038 ... 0x00401048 0x0040104C 0x00401050 0x00401054 0x00401058 0x0040105C 0x00401060 0x00401064 0x00401068 addi $sp $sp -12 #reservando sw $t1, 8($sp) #salva $t1 sw $t0, 4($sp) #salva $t0 sw $s0, 0($sp) #salva $s0 add $t0 $a0 $a1 #t0=x+y add $t1 $a2 $a3 #t1=z+w add $s0 $t0 $t1 #s0=x+y+z+w srl $s0 $s0 2 #(x+y+z+w)/4 add $v0 $s0 $zero #return $t1 (0x5) $t0 (0x4) $s0 (0x3) LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Procedimento usando a pilha (Continuação) Linguagem de Alto Nível int main(){ int y; ... y = media(2,3,5,6); ... } int media(int x, int y, int z, int w){ int result; result = (x + y + z + w)/4; return result; } Linguagem de Montagem 0x00401038 ... 0x00401058 0x0040105C 0x00401060 0x00401064 0x00401068 0x0040106C 0x00401070 0x00401074 0x00401078 0x0040107C add $t0 $a0 $a1 #t0=x+y add $t1 $a2 $a3 #t1=z+w add $s0 $t0 $t1 #s0=x+y+z+w srl $s0 $s0 2 #(x+y+z+w)/4 add $v0 $s0 $zero #return lw $s0 0($sp) #recupera $s0 lw $t0 4($sp) #recupera $t0 lw $t1 8($sp) #recupera $t1 addi $sp $sp, 12 #ajusta top jr $ra #retorna para main $t1 (0x5) $t0 (0x4) $s0 (0x3) É POSSÍVEL PROCEDIMENTOS RECURSIVOS? LINGUAGEM DE MONTAGEM: SUPORTE A PROCEDIMENTOS Linguagem de Alto Nível Linguagem de Montagem Procedimento recursivo int main(){ y = fatorial(3); ... } int fatorial(int n){ if (n <= 1) return 1; else return (n * fatorial(n – 1); } 0x00400200 jal 0x00401020 #fatorial(3) 0x00400204 add $s0 $v0 $zero #y=return 0x0040101C 0x00401020 0x00401024 0x00401028 0x0040102C 0x00401030 0x00401034 0x00401038 0x0040103C 0x00401040 0x00401044 0x00401048 0x0040104C 0x00401050 0x00401054 0x00401058 0x0040105C addi $a0 $zero 3 #arg0=3 addi $sp $sp -8 #ajusta a pilha sw $a0 4($sp) #salva $a0 sw $ra 0($sp) #salva $ra addi $t0 $zero 2 #t0=2 slt $t0 $a0 $t0 #a0<t0?1:0 beq $t0 $zero 0x00401048 addi $v0 $zero 1 #return 1 addi $sp $sp 8 #restaura pilha jr $ra #return addi $a0 $ao -1 #n=n-1 jal 0x00401020 #chamada recursiva lw $ra 0($sp) #recupera $ra lw $a0 4($sp) #recupera $a0 addi $sp $sp 8 restaura $sp mul $v0 $a0 $v0 #n*fatorial(n-1) jr $ra