Buscar

Interface Hardware-Software - 13 Aula IHS C ASM

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

Continue navegando