6. Registradores
• EAX = Extended Acumullator (registrador acumulador extendido)
• EBX = Extended Base (registrador de base extendido)
• ECX = Extended Couter (registrador contador extendido)
• EDX = Extended Data (registrador de dados extendido)
• ESI = Extended Source Index (registrador de índice de origem
extendido)
• EDI = Extended Destination Index (registrador de índice de destino
extendido)
• Em adição aos registradores de uso geral, temos os registradores
especiais, que são:
– EBP = Extended Base Pointer (Ponteiro de Base)
– ESP = Extended Stack Pointer (Ponteiro de Stack/Pilha)
– EIP = Extended Instruction Pointer (Ponteiro de Instrução)
– EFLAGS
7. Registradores
• Uma coisa que precisamos ter sempre em mente, é que
tanto como o EIP quanto o EFLAGS, só poderão ser
acessados através de instruções especiais e bem
específicas, diferente dos demais registradores.
• O EBP sempre aponta para a base da pilha, e também é
utilizado para acessar essa mesma pilha, apesar de
também poder ser utilizado como um registrador comum
(de uso geral). Já o ESP, aponta para a posição atual da
stack (pilha) e é o 'offset' do SS (Stack Segment).
8. Organização de um registrador
para uso geral
EAX
31 0
AX
31 16 15 0
AH AL
15 8 7 0
•EAX armazenaria, por exemplo, um valor fictício de 0x00000000.
•AX, que é a parte alta de EAX, armazenaria 0x0000.
•AH, é a parte alta de AX, enquanto AL é a parte baixa de AX (ambos são
de arquitetura 8bits), e armazenam apenas 0x00 cada um.
10. AT&T x Intel
• Na sintaxe Intel, uma instrução comum ficaria assim:
– instrução destino, origem
• Em AT&T é:
– instrução origem, destino
• Uma questão importante de se lembrar, é que na sintaxe AT&T,
todos os registradores devem ser prefixados pelo símbolo %,
enquanto que o valores literais, pelo símbolo $. Portanto, 100 é
diferente de $100, onde o primeiro é um endereço de memória, e o
segundo é um valor numeral.
• Outro símbolo importante, é o '$0x' utilizado para referenciar
hexadecimais.
11. Primeiro programa
#OBJETIVO: Programa simples que executa um exit e retorna um código de status para o kernel Linux
#ENTRADA: nenhuma
#OUTPUT: retorna um status código de status, que pode ser visto executando no terminal o comando:
# echo $?
# após a execução do programa
#VARIÁVEIS:
# %eax armazena o número da syscall
# %ebx armazena o status retornado
.section .data
.section .text
.globl _start
_start:
movl $1, %eax # esta é a syscall do kernel Linux para sair de um programa
movl $0, %ebx # este é o status que retornaremos para o SO.
# altere esse valor, e verá coisas diferentes ao executar
# echo $?
int $0x80 # isso chama o kernel para executar a syscall 1
12. Execução
• Salve este código como 'exemplo1.s', compile e
linkedite-o:
# as exemplo1.s -o exemplo1.o
# ld exemplo1.o -o exemplo1
Após este processo, para executar nosso
primeiro programa, basta digitar no terminal:
# ./exemplo1
13. Explicação
• .section .data = cria a seção "data", onde listamos quaisquer containers de memória.
• .section .text = seção onde inserimos as instruções a serem executadas.
• .globl _start = '.globl' é uma instrução que diz que o símbolo '_start' não deve ser descartado
após a compilação e linkedição do código.
• _start: = é onde definimos o valor do label '_start', que terá vinculado à si, o conjunto de
instruções que seguem logo abaixo.
• movl $1, %eax = aqui temos a instrução 'movl', seguido de dois operadores. Nesse caso,
inserimos o valor 1 no registrador EAX. Esse número é o valor de uma syscall específica (exit -
para conhecer os valores das demais 'syscall', execute o comando "cat /usr/include/asm-
i386/unistd.h" no terminal Linux*).
• movl $0, %ebx = inserimos o valor "0" no registrador EBX. Isso é o que dirá para o kernel que
está tudo ok para o 'exit' ser executado.
• int $0x80 = 'int' é o mesmo que 'interrupt'. Uma interrupção corta o fluxo de funcionamento de um
programa e passa o comando para o Linux, o que em nosso caso, fará com que o kernel execute
a 'syscall 1 '(exit). E o valor '$0x80' é o número de interrupção utilizado para que essa passagem
de controle para o Linux aconteça.
* No Ubuntu, o arquivo está em: /usr/include/asm/unistd.h
14. Segundo programa
.data
HelloWorldString:
.ascii "Hello Worldn"
.text
.globl _start
_start:
movl $4, %eax # syscall write()*
movl $1, %ebx # parâmetro da syscall para definir STDOUT (fd)
movl $HelloWorldString, %ecx # local da mem. onde se encontra o container com a string (Buf)
movl $12, %edx # tamanho da string (count)
int $0x80
movl $1, %eax # syscall exit()
movl $0, %ebx
int $0x80
* Syscall write() = ssize_t write(int fd, const void *Buf, size_t count);
15. Passagem de syscalls e
argumentos
• De que maneira podemos passar os
valores de syscall e seus argumentos?
– EAX – número da system call
– EBX – primeiro argumento
– ECX – segundo argumento
– EDX – terceiro argumento
– ESI – quarto argumento
– EDI – quinto argumento
16. Execução
• Salve este código como 'exemplo2.s', compile e
linkedite-o:
# as exemplo2.s -o exemplo2.o
# ld exemplo2.o -o exemplo2
Após este processo, para executar nosso
primeiro programa, basta digitar no terminal:
# ./exemplo2
17. Tipos de dados
• Espaço reservado em tempo de compilação (em .data):
– .byte = 1 byte
– .ascii = string
– .asciz = string terminada em null
– .int = integer de 32 bits
– .short = integer de 16 bits
– .float = número single com ponto flutuante
– .double = número double com ponto flutuante
• Espaço criado em tempo de execução (em .bss):
– .comm = declara área comum da memória
– .lcomm = declara área local comum da memória
19. Execução
• Salve este código como 'exemplo3.s', compile e
linkedite-o:
# as –gstabs exemplo3.s -o exemplo3.o
# ld exemplo3.o -o exemplo3
Após este processo, para executar nosso
primeiro programa, basta digitar no terminal:
# ./exemplo3
• # gdb ./exemplo3
20. Execução
• (gdb) list
• (gdb) break *_start+1
• (gdb) run
• (gdb) info variables
• (gdb) help x
• (gdb) x/12cb [endereço de HelloWorld]
• (gdb) x/1db [endereço de ByteLocation]
• (gdb) x/1dw [endereço de Int32]
• (gdb) x/1dh [endereço de Int16]
• (gdb) x/1fw [endereço de Float]
• (gdb) x/5dw [endereço de IntegerArray]
• (gdb) x/10db [endereço de LargeBuffer]
• (gdb) x/100db [endereço de LargeBuffer]
21. MOVx
• É uma das instruções mais utilizadas em Assembly
• Sua utilização é basicamente a seguinte:
– movx origem, destino
– movl movimenta valores de 32bits
movl %eax,%ebx
– movw movimenta valores de 16bits
movl %ax,%bx
– movb movimenta valores de 8bits
movl %ah,%bh
22. Movendo dados
• Entre registradores:
movl %eax, %ebx
• Entre registradores e memória:
local:
.int 10
movl %eax, local
movl local, %ebx
23. Movendo dados
• Valor direto no registrador:
movl $10, %ebx
• Valor direto na memória:
local:
.byte 0
movl $10, local
24. Movendo dados
• Em um endereço indexado da memória:
IntegerArray:
.int 10, 20, 30, 40, 50
• Para selecionar o 3º valor da integer (30)
– BaseAddres(offset, index, size) =
– IntegerArray(0, 2, 4)
movl %eax, IntegerArray(0, 2, 4)
25. Quarto programa
.section .data
string: .string "Digite algo:n"
tam: .long . - string
.section .text
.globl _start
_start:
movl $4, %eax # insere o valor 4, para a chamada da syscall write no EAX
movl $1, %ebx # passa o parâmetro da syscall 4 para que algo seja exibido
leal string, %ecx # carrega o endereço de memória do ECX e exibe o conteúdo de string
movl tam, %edx # armazena o valor de tam no EDX
int $0x80
movl %esp, %ecx # Salva o Stack Pointer em %ecx
subl $10, %esp # Reserva 10 bytes para o usuario digitar no stack
movl $3, %eax # insere o valor da syscall read (3) no EAX
movl $9, %edx # Tamanho do que vai ser lido para EDX
int $0x80
movl %eax, %edx # Move o que foi digitado para EDX.
movl $4, %eax # syscall write
movl $1, %ebx
int $0x80
movl $0x1, %eax
movl $0x0, %ebx
int $0x80
26. Execução
• Salve como 'leia.s'.
• Compile, linkedite e execute:
# as leia.s -o leia.o
# lf leia.o -o leia
# ./leia
27. Quinto programa
.section .data
string1: .string "Criar um arquivo e inserir conteúdo n"
tam1: .long . - string1
string2: .string “Viva o Linuxn"
tam2: .long . - string2
arq: .string "/tmp/arquivo.txt"
.section .text
.globl _start
_start:
movl $4, %eax # syscall write
movl $1, %ebx
leal string1, %ecx
movl tam1, %edx
int $0x80
movl $5, %eax # syscall open (5)
movl $arq, %ebx # arquivo que será aberto
movl $03101, %ecx # modo do arquivo
movl $0, %edx # Permissão 0
int $0x80
28. Quinto programa
movl %eax, %esi # Move o retorno da funcao open para ESI
movl $4, %eax # syscall write, para efetuar a escrita no arquivo
movl %esi, %ebx # local de escrita, arquivo.txt
leal string2, %ecx # escrita do conteúdo de string2 para dentro do arquivo
movl tam2, %edx # O tamanho da variavel
int $0x80
movl $6, %eax # syscall close (6)
movl %esi, %ebx # Fecha o arquivo
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
29. Execução
• Salve como ‘escreva.s'.
• Compile, linkedite e execute:
# as escreva.s -o escreva.o
# lf escreva.o -o escreva
# ./escreva
30. Comparação – Sexto programa
.section .data
data_items: .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi # insere 0 no registrador índice
movl data_items(,%edi,4), %eax # carrega o primeiro byte de dados
movl %eax, %ebx # como este é o primeiro item, %eax é o maior
start_loop:
cmpl $0, %eax # verifica se alcançamos o final
je loop_exit
incl %edi # carrega o próximo valor
movl data_items(,%edi,4), %eax
cmpl %ebx, %eax # compara valores
jle start_loop # pula para o loop se o novo valor não for o maior
movl %eax, %ebx # grava o valor como o maior
jmp start_loop # pula para o início do loop
loop_exit:
# %ebx é o código de status para a syscall exit
# e já possui o valor mais alto
movl $1, %eax
int $0x80
31. Execução
• Salve como ‘maximo.s'.
• Compile, linkedite e execute:
# as maximo.s -o maximo.o
# lf maximo.o -o maximo
# ./maximo
# echo $?
32. Condicionais
• je
– Pula (Jump) se os valores são iguais
• jg
– Pula se o segundo valor for maior que o primeiro
• jge
– Pula se o segundo valor for maior ou igual ao primeiro
• jl
– Pula se o segundo valor for menor que o primeiro
• jle
– Pula se o segundo valor for menor ou igual ao primeiro
• jmp
– Pula não importa o resultado da comparação (se houver uma). Esse Jump não
precisa ser precedido por uma comparação
• OBS: uma condicional normalmente é precedida por um cmpl (comparando
dois valores):
cmpl $0, %eax
je loop_exit