MINICURSO DE PROGRAMAÇÃO EM
LINGUAGEM ASSEMBLY x86
Procedimentos II
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Moldura de Pilha ou Registro de Ativação
• Área da pilha, definida a parte, depois do endereço de
retorno do procedimento, contendo
• Parâmetros Passados
• Registradores Salvos
• Variáveis Locais
• Criada pelos seguintes passos:
• Chamada para o programa empilhar argumentos na pilha e chamar
o procedimento
• O procedimento chamado empilha(salva) EBP na pilha e define EBP
apontando para ESP
• Se variáveis locais são necessárias, uma constante é subtraída de
ESP para reservar espaço na pilha
1. PUSH EBP
2. MOV EBP, ESP
3. ...
4. MOV ESP, EBP
5. POP EBP Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Principal vantagem → Utilizar a pilha de forma segura
• Experimente fazer um PUSH e não fazer um POP
• O programar vai terminar de forma abrupta
• Experimente chamar um procedimento com parâmetros
• Ao realizar POP dentro do procedimento
• Resultado → Endereço de Retorno
• O programa deve terminar com ESP na mesma posição que
começou
• Mais conveniente que parâmetros por registradores
• Duas formas de chamar DumpMen, qual mais fácil?
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• EBP → Referenciar os parâmetros do procedimento e
variáveis locais no atual Stack Frame
• ESP ⇋ Manipulado Implicitamente
• EBP ⇋ Manipulado Explicitamente
• Podemos chamar EBP de Frame Pointer
• Dizemos que EBP representa a base da Stack Frame
• Ao começo do programa, EBP geralmente é igual a ESP
• EBP a base da pilha
• ESP o topo da pilha
• Em resumo
• Manipular de maneira mais fácil os parâmetros
• Proteger dados da pilha
• Acesso a variáveis locais
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
Parâmetros por Valor:
• Coloque os parâmetros do procedimento na pilha
• Use apenas valores de 32-bits para manter a pilha alinhada
• Chame o procedimento
• Por convenção, caso haja retorno, que seja colocado em EAX
• Remova argumentos da pilha se o procedimento chamado
não os removeu
SECTION .data
val1 DD 5
val2 DD 6
SECTION .text
PUSH DWORD[val2]
PUSH DWORD[val1]
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
Parâmetros por Referência:
• Coloque os parâmetros do procedimento na pilha
• Chame o procedimento
• Por convenção, caso haja retorno, que seja colocado em EAX
• Remova argumentos da pilha se o procedimento chamado
não os removeu
SECTION .data
val1 DD 5
val2 DD 6
SECTION .text
PUSH val2
PUSH val1
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Podemos operar a pilha por instruções específicas ou
gerais
• A partir de ESP
• PUSH EAX ⇋ SUB ESP, 4 e depois MOV [ESP], EAX
• POP EAX ⇋ MOV EAX, [ESP] e depois ADD ESP, 4
main: SUB ESP, 4
PUSH EBP MOV [ESP], EAX
MOV EBP, ESP
PUSH EAX
POP EAX
MOV ESP, EBP
POP EBP MOV EAX, [ESP]
ADD ESP, 4
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Podemos acessar parâmetros da pilha a partir de EBP
• Offsets Constantes → [EBP + 8]
• Chamamos EBP de Ponteiro da Base ou Ponteiro de
Moldura
• EBP não muda durante o procedimento
• EBP e ESP devem ser restaurados ao final do procedimento
SECTION .text sumThis:
GLOBAL main PUSH EBP
main: MOV EBP, ESP
PUSH EBP MOV EAX, [ESP + 12]
MOV EBP, ESP ADD EAX, [ESP + 8]
PUSH EAX MOV ESP, EBP
PUSH EBX POP EBP
CALL sumThis RET
MOV ESP, EBP
POP EBP
XOR EAX, EAX
RET Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
Revendo a instrução RET:
• Função → Retorne de uma procedimento(sub-rotina)
• Desempilha no ponteiro de instrução, EIP
• Desempilhar endereço de retorno
• Controle de Fluxo transferido para endereço
• Sintaxe
• RET
• RET n
• Caso seja utilizado o operando opcional n
• Endereço de retorno desempilhado em EIP
• Adiciona n bytes para o ponteiro de pilha, ESP
• Dessa forma → Limpa a pilha dos parâmetros
• Quem remove os parâmetros da pilha?
• Que chama o procedimento. Ex: utilizando ADD ESP, n
• Procedimento chamado. Ex: utilizando RET n
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Não é possível empilhar valores de 8-bits
• Empilhar valores de 16-bits pode causar problemas
• Page fault
• Alinhamento do ESP
• Incompatibilidade com funções API do Windows
• Recomendado → Padronizar o empilhamento de 32-bits
• Estender argumentos menores em 32-bits
• Usar MOVZX ou MOVSX
• E depois empilhar
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Variáveis Locais → Visíveis somente no seu procedimento
• Armazenamento usado por variáveis locais liberado após o
fim do procedimento
• Essencial em programas recursivos e que requerem muitos
valores armazenados
• Podemos criar variáveis locais subtraindo do ESP
• SOMAR a ESP → parte alta da pilha, parâmetros do procedimento
• SUBTRAIR a ESP → parte baixa da pilha, stack frame do procedimento
• Exemplo: Criar duas variáveis locais de 4 bytes
• int x = 10;
• int y = 20;
meuProcedimento:
PUSH EBP
MOV EBP, ESP
SUB ESP, 8
MOV DWORD[EBP-4], 10
MOV DWORD[EBP-8], 10
... Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Suponha que você tem uma variável local em [EBP-8]
• Você precisa de seu endereço
• Usar MOV ESI, EBP – 8 resultará em erro
• MOV ESI, endereco – 8 ; CORRETO
• MOV ESI, reg_ptr - 8 ; ERRADO
• Instrução LEA → Retorna o endereço efetivo
• LEA retorna endereços de operandos diretos e indiretos
• Requerido para obter endereço de parâmetros na pilha e
variáveis locais
• Sintaxe → LEA r32, [expressao]
• Logo. LEA ESI, [EBP - 8], ESI = endereço da variável local
• Uso dos colchetes requerido na instrução
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Exemplo na utilização da instrução LEA
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
• Duas formas de criar e desfazer a Stack Frame:
• Instruções gerais
• Instruções específicas
• Instrução ENTER n, 0 → Cria a Stack Frame do
procedimento
• O operando n estipula quantos bytes serão reservados para variáveis
locais
• Instrução LEAVE → Desfaz a Stack Frame do procedimento
meuProcedimento: meuProcedimento:
PUSH EBP ENTER 8,0
MOV EBP, ESP ...
SUB ESP, 8 LEAVE
... RET
MOV ESP, EBP
POP EBP
RET
Pedro Botelho
Bacharelando em Engenharia de Computação
Stack Frames
Resumindo...
• Instrução CALL empilha o endereço de retorno
• Coloca o endereço do procedimento em EIP
• Instrução RET desempilha(o endereço) em EIP
• Stack Frame facilita a utilização da pilha
• Podemos manusear a pilha...
• ...usando instruções PUSH e POP
• ...pelo topo usando ESP
• ...pela base usando EBP
• Podemos passar argumentos...
• ...por referência
• ...por valor
• Parâmetros devem ser removidos da pilha...
• ...durante o procedimento chamado
• ...na função que o chama
• Podemos utilizar variáveis locais reservando espaço na
pilha
Pedro Botelho
Bacharelando em Engenharia de Computação
Montando o Programa
• Até agora usamos uma IDE para criar os programas
• No SASM alguns detalhes foram simplificados
• Iremos, agora, trabalhar direto na linguagem NASM
Revisando...
• Linguagem de montagem não é executada diretamente
pelo processador
• Conversão Assembly → Código de máquina do computador alvo
• Instruções Assembly ⇋ Instruções do Processador
• Podemos ter programas divididos em diversos arquivos e
usando bibliotecas externas
• Isso precisa ser incorporado ao código que será executado
Pedro Botelho
Bacharelando em Engenharia de Computação
Montando o Programa
• Do .asm ao executável temos...
• Montagem
• Conversão do [Link] em arquivo.o, em linguagem de máquina
• Ligação
• Verifica se no arquivo objeto há chamada de procedimentos em
uma biblioteca
• Copia todos os procedimentos da biblioteca e combina com o
arquivo objeto
• Gera o arquivo executável
• Execução
• O Sistema Operacional lê o arquivo executável e carrega na
memória
• Salva em EIP o caminho do endereço de início do programa
• O programa começa sua execução
Pedro Botelho
Bacharelando em Engenharia de Computação
Montando o Programa
• Ciclo de Conversão, desde o código Assembly até o
carregamento pelo Sistema Operacional
Pedro Botelho
Bacharelando em Engenharia de Computação
Montando o Programa
AO UTILIZAR O LINUX (recomendado):
• Ponto de início do programa recomendado → main
• Pode utilizar _start, basta ligar usar ld –m elf_i386 –s –o main
main.o
Processo de Montagem:
• Montagem feita pelo montador NASM
• nasm –f elf [Link]
Processo de Ligação:
• Ligação pelo GCC
• gcc –m32 main.o –o main
Pedro Botelho
Bacharelando em Engenharia de Computação
Montando o Programa
AO UTILIZAR O WINDOWS:
• Ponto de início do programa recomendado → _WinMain@16
• Ao final do programa deve-se usar RET 16
Processo de Montagem:
• Montagem feita pelo montador NASM
• nasm –f elf64 [Link]
Processo de Ligação:
• Ligação pelo LD
• ld main.o –o main
Pedro Botelho
Bacharelando em Engenharia de Computação
Programa em Múltiplos Módulos
• Podemos dividir um programa em diversas partes usando
procedimentos
• Ainda é possível dividir um programa em diversos arquivos
• Programa multi-módulo
• Código-fonte dividido em arquivos .asm separados
• Cada arquivo .asm é montado em um arquivo objeto
diferente
• Arquivo .asm → Módulo
• Todos os arquivos .obj que pertencem ao mesmo programa
devem ser ligados para gerar o arquivo executável
• Ligação Estática
Pedro Botelho
Bacharelando em Engenharia de Computação
Programa em Múltiplos Módulos
Vantagens:
• Programas mais fáceis de escrever, manter e depurar
• Quando uma alteração em um arquivo é feita, somente o
módulo modificado precisa ser montado novamente
• Ligar módulos já montados requer pouco tempo
• Um módulo pode ser um contêiner para código e dados
• Perspectiva de Orientação a Objetos
• Encapsulamento: procedimentos e variáveis são automaticamente
não visíveis em outros módulo
• A menos que sejam públicas
• Flexibilidade → Utilizar um procedimento externo
(módulo) em vários outros códigos
Pedro Botelho
Bacharelando em Engenharia de Computação
Programa em Múltiplos Módulos
Como criar um programa com módulos:
1. Criar o módulo main
2. Criar um módulo de código-fonte para cada procedimento
3. Para cada módulo é necessário ter o protótipo dos
procedimentos com visibilidade GLOBAL
• Disponível para os demais módulos
4. Use a diretiva EXTERN para indicar ao montador que o
procedimento será passado pelo ligador posteriormente
• Para liga-los:
• Monte cada módulo individualmente pelo NASM
• Ligue todos juntos com o GCC
Pedro Botelho
Bacharelando em Engenharia de Computação
Programa em Múltiplos Módulos
• Exemplo: programa multi-módulo que realiza EAX += EBX
Pedro Botelho
Bacharelando em Engenharia de Computação
Integração C e Assembly
• Podemos fazer a integração de três maneiras
• Módulo em Assembly dentro de um programa em C
• Módulo em C dentro de um programa Assembly
• Código Assembly dentro de uma função em C (inline Assembly)
• Vamos focar na utilização de Módulos Complementares em
Assembly em um código principal em C
• Inline Assembly utilizando o formato AT&T, diferente do
formato Intel que utilizamos, não recomendado
• Podemos usar funções em C no Assembly
• printf
• scanf
Pedro Botelho
Bacharelando em Engenharia de Computação
Integração C e Assembly
• Utilizando os conhecimentos que temos até agora
• Como chamar um módulo do C?
1. Referenciar com diretiva EXTERN o procedimento desejado
2. Empilhar os registradores usando PUSHAD (opcional)
3. Passar os parâmetros em ordem inversa pela Pilha
4. Chamar a função usando CALL
5. Reajustar ESP
6. Desempilhar os registradores usando POPAD (opcional)
• Exemplo: printf(“%d”, valor);
1. Lendo da direita pra esquerda, temos uma função, um
parâmetro de String e um parâmetro inteiro
2. Em Assembly → Reverso
PUSH valor PASSA VALOR CHAMA FUNCAO
PUSH string PASSA STRING PASSA STRING
CALL printf CHAMA FUNCAO PASSA VALOR
ADD ESP, 8 REALOCA ESP Pedro Botelho
Bacharelando em Engenharia de Computação
Integração C e Assembly
• Utilizamos funções da biblioteca Standart I/O
• Não necessita especificar arquivos na ligação
• Podemos também utilizar arquivos próprios em C
• Necessita compilar cada arquivo em C
• Necessita especificar na ligação
int add(int a, int b){ EXTERN add
return a + b; EXTERN printf
} ...
PUSH 16
PUSH 2
• Logo: CALL add
• gcc –c –m32 add.c ADD ESP, 8
...
• nasm –f elf [Link]
PUSH EAX
• gcc –m32 –o main main.o PUSH string
add.o CALL printf
ADD ESP, 8
Pedro Botelho
Bacharelando em Engenharia de Computação
Integração C e Assembly
• Podemos utilizar também funções Assembly no C
• Isso pode ser feito em módulos ou inline (não
recomendável)
• Exemplo de Integração por Módulos
Pedro Botelho
Bacharelando em Engenharia de Computação
Integração C e Assembly
Sugestões:
• Utilizar funções Assembly incorporadas ao C
• Utilizar passagem de parâmetro por pilha
• Usar a Stack Frame e manusear ESP e EBP com cuidado
• Sempre que possível utilizar a abordagem multi-módulo
• Exemplos de funções específicas em Assembly
• Operações com Vetores
• Operações com números de ponto flutuante
• Interrupções de Software
Pedro Botelho
Bacharelando em Engenharia de Computação
Integração C e Assembly
• Exemplo de Assembly Inline:
Pedro Botelho
Bacharelando em Engenharia de Computação