Baixe o app para aproveitar ainda mais
Prévia do material em texto
Interface Hardware-Software Intel x86 – Integração C - ASM Camadas de Software Camada de SW de baixo nível Camada de SW de Baixo Nível Mais dependente do HW – Embora haja muitas partes que sejam independentes Permite acesso controlado e gerenciamento de dispositivos de HW – E/S – Escalonamento de Processo – Inicialização de dispositivos Código mais complexo de escrever e depurar – Deve levar em conta detalhes de HW – Se linguagem de programação utilizada for de baixo nível, mais linhas de código são necessárias Linguagens de Programação Utilizadas Mesmo sendo código de baixo nível, não implica que o código deve ser escrito todo em assembly Maior parte do código é escrita em linguagens de alto nível - Pequenas partes específicas escritas em assembly Existem muitas bibliotecas ou rotinas que permitem acesso baixo nível a linguagens de alto nível – POSIX – Rotinas referentes a processos – C newlib – Acesso a periféricos em sistemas embarcados Quando Usar Assembly? Controle total de que partes do hardware devem ser acessadas – Registradores específicos Garantir que uma rotina execute de forma mais determinística - Compiladores de linguagem de alto nível podem modificar a forma de execução pretendida pelo programador - Importante para sistemas de tempo real Rotinas específicas que linguagens de alto nível não dão suporte – Ex: Partes do Boot loader Rotinas pequenas onde deseja-se otimização Por Que Não Usar Assembly em Todo Código ? Baixa produtividade – Muitas linhas de código para fazer o que poucas linhas de código em alto nível fazem – Depuração mais lenta e complexa Alto custo de manutenção Baixa portabilidade – Códigos específicos a uma ISA – Nem todo código de baixo nível é dependente do HW Alternativa: Uso conjunto de assembly e linguagem de alto nível Integração C-Assembly Podemos combinar C e Assembly de diferentes formas Módulos C e Assembly separados – Integração através de chamadas de rotinas – Durante a link-edição é feita a integração Código assembly inline – Inserção de código assembly em um código C Integrando Módulos C e Assembly Separados extern imprimir SECTION .data var dq 3.5 SECTION .text global main main: push dword [var+4] push dword [var] call imprimir add esp, 8 void imprimir(double valor){ printf(“%lf”,valor); } Montador Compilador Link-editor Teste1.asm Teste2.c Teste1.exe Teste1.o Teste2.o Duas Formas de Integrar Módulos C e Assembly extern imprimir SECTION .data var dq 3.5 SECTION .text global main main: push dword [var+4] push dword [var] call imprimir add esp, 8 void imprimir(double valor){ printf(“%lf”,valor); } SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int,int); int main() int a,b,c,value; value = soma(a,b,c); } Assembly chamando C C chamando Assembly Chamando Rotinas Assembly em C SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int, int); int main() int a,b,c,value; value = soma(a,b,c); } C chamando Assembly Existem convenções para a passagem de parâmetros do código C para assembly e valores de retorno Algumas regras devem ser seguidas no código assembly quanto ao uso de registradores ESP ESP Passagem de Parâmetros em C End - 16 End - 12 End - 8 End -4 End soma(a,b,c) ESP ESP ESP a b c EIP Em C os parâmetros são inseridos na pilha da direita para a esquerda (Right-pusher) Stack Frame Stack frame contém as variáveis locais da função chamada – Stack frame cresce de endereços maiores para menores – Guarda também o começo do stack frame da rotina que chamou a função Por convenção, o registrador EBP guarda o endereço do começo do stack frame – Conhecido como o Frame Pointer (FP) O Que Acontece na Chamada de Rotina Assembly SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } C chamando Assembly mov eax,1 mov [ebp-4],eax; a=1 mov eax,4 mov [ebp-8],eax; b=4 mov eax,5 mov [ebp-12],eax; c=5 push [ebp-12] push [ebp-8] push [ebp-4] call soma add esp,12 mov [ebp-16],eax Equivalentes Convenção de Retorno de Funções Funções em C utilizam determinados registradores para retorno, portanto o código C sempre assume que as rotinas em assembly também utilizem estes registradores – Valores de 8,16 e 32 bits são devolvidos em EAX – Valores de 64 bits são devolvidos em EDX:EAX – Valores de ponto flutuante são devolvidos em ST(0) – Endereços (ponteiros) são devolvidos em EAX Regras de Escrita do Código Assembly O código assembly chamado por C pode utilizar qualquer registrador, porém deve preservar EBP,EBX,ESI e EDI – Preservar significa colocar na pilha (salvar em memória), antes da utilização O assembly deve utilizar para retorno os registradores de retorno padrão É aconselhável começar a rotina com a instrução enter e antes do retorno colocar a instrução leave – Ou colocar instruções similares Instrução ENTER Instrução para preparar um novo stack frame Empilha EBP (ponteiro do stack frame anterior), move o valor de ESP(topo da pilha) para EBP e aloca bytes para armazenar variáveis locais (subtrai bytes de ESP e atualiza ESP) nivel informa o aninhamento da rotina, sendo 0 o maior nível – Informa a quantidade de stack frames pointers (FPs) devem ser copiados para o novo stack frame – Permite o acesso de rotinas de menor nível a variáveis de maior nível Forma Geral enter bytes, nivel Exemplo: ENTER enter 16, 0 push ebp; (1) mov ebp,esp; (2) sub esp,16; (3) Equivalentes End End - 12 End - 8 End - 4 End - 16 ESP EBPa ESP EBP ESP EBPa = EBP antigo (1) (2) (3) Instrução LEAVE Instrução para reverter as ações do enter Copia EBP para ESP para liberar espaço alocado, e então restaura valor antigo do EBP – Como consequencia, restaura valor antigo de ESP antes de entrar na rotina Forma Geral leave Exemplo: LEAVE leave mov esp,ebp; (1) pop ebp; (2) Equivalentes End End - 4 End - 8 End - 12 End - 16 ESP EBPa ESP EBP ESP EBPa = EBP antigo (2) (2) EBPa EBP ESP (1) End + 4 Compilando e Linkando os MódulosSECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } Para toda rotina em um módulo externo deve-se utilizar a palavra extern Para a rotina externa chamada deve-se utilizar a palavra global main.c soma.asm Para compilar e linkar: nasm –f elf soma.asm gcc –o programa main.c soma.o Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } End End - 24 End - 20 End - 16 End - 12 5 ESP EBPa EBP End - 8 End - 4 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 5 4 ESP EBPa EBP End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 ESP EBPa EBP End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP ESP EBPa EBP End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP EBPa ESP,EBP - EAX End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP EBPa ESP,EBP 1 EAX End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP EBPa ESP,EBP 5 EAX End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP EBPa ESP,EBP 10 EAX End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP EBPa ESP End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 10 EBPa EBP EAX Execução do Código SECTION .text global soma soma: enter 0,0 mov eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] leave ret #include <stdio.h> extern int soma(int,int,int); int main() int a=1,b=4,c=5,value; value = soma(a,b,c); } 4 1 EIP EBPa ESP End End - 24 End - 20 End - 16 End - 12 End - 8 End - 4 5 10 EBPa EBP EAX Outro Exemplo: Soma de Vetor SECTION .text global somaVetor somaVetor: enter 0,0 mov edx,[ebp+8]; vetor mov ecx,[ebp+12]; SIZE push ebx; preservar mov ebx,0 mov eax,0 add_loop: add eax,[edx+ebx*4] inc ebx loop add_loop pop ebx leave ret #include <stdio.h> #define SIZE 4 extern int somaVetor(int*,int); int main() int vetor[]= {4,8,10,12}; int soma; soma = somaVetor(vetor,SIZE); printf(“Soma = %d”,soma); } Chamando Funções C em Assembly SECTION .data vetor dd 5,10,2 SIZE dd 3 SECTION .text extern min global main main: push dword [SIZE] push dword vetor call min add esp,8 int min(int* vetor, int size){ int i, menor = vetor[0]; for (i = 0; i<size; i++){ if (menor > vetor[i]) menor = vetor[i]; } return menor; } Assembly chamando C Utilizam-se as mesmas convenções para a passagem de parâmetros do código C para assembly e valores de retorno ESP ESP Passagem de Parâmetros em C End End - 4 End - 8 End - 12 End - 16 int min(vetor,size) ESP ESP size vetor EIP No código assembly deve-se empilhar os parâmetros da direita para a esquerda call min Exemplo: Chamando a Função min e printf SECTION .data vetor dd 5,10,2 SIZE dd 3 Msg db “min = %d",0x0a,0x00 SECTION .text extern min, printf global main main: push dword [SIZE] push dword vetor call min add esp,8 push eax push dword Msg call printf add esp,8 int min(int*vetor, int size){ int i, menor = vetor[0]; for (i = 0; i<size; i++){ if (menor > vetor[i]) menor = vetor[i]; } return menor; } Código Assembly Inline Podemos também inserir código assembly diretamente no código C Aconselhável apenas para pequenos trechos de código – Senão o código fica bastante ilegível Contudo, a sintaxe aceita pela maioria dos compiladores C é a sintaxe AT&T Algumas Diferenças da Sintaxe AT&T (1) Para utilizar registradores, deve-se preceder o nome do registrador com % Os lugares dos operandos destino e fonte na instrução são invertidos Deve-se especificar na instrução, o tamanho dos operandos NASM AT&T mov eax,ebx movl %ebx,%eax mov dx, ax movw %ax, %dx inc cl incb %cl add eax,ebx addl %ebx,%eax Algumas Diferenças da Sintaxe AT&T (2) Constantes e imediatos devem ser precedidos $ Para especificar endereçamento indireto deve-se utilizar (), em vez de [] Para utilizar endereçamento de base indexado escalar, deve-se colocar (base,indice,escala) NASM AT&T mov eax,5 movl $5,%eax add bx, word[bp] addw (%bp),%bx add eax, [ecx+ebx*4] addl (%ecx,%ebx,4),%eax Exemplo: Calculando Soma Vetor Inline #include <stdio.h> int vetor[] = {4,8,10,12}; int soma = 0; int main() { asm("movl $vetor,%edx;" "movl $0,%ebx;" "movl $4,%ecx;" "movl $0,%eax;" "add_loop: addl (%edx,%ebx,4),%eax;" "incl %ebx;" "loop add_loop;" "movl %eax,soma" ); printf("\nA soma do vetor eh = %d\n",soma); return 0; } Código Assembly Inline
Compartilhar