Embora eu particularmente prefira a sintaxe AT&T à Intel. Estou tendo que aprender a usá-la (e bem). Para os estudos optei pelo NASM, GNU ld e o GDB. Um processo simples, descrito abaixo:
#nasm -g -f elf programa.asm
#ld programa.o
#gdb -q a.out
Vamos fazer um pequeno programa teste que carrega no registro ecx o valor da variável (var1) e em edx seu endereço:
section .data var1 dd 40 section .text global _start _start: nop nop mov ecx, [var1] lea edx, [var1] _exit: mov eax, 1 int 80h
Dentro do gdb:
(gdb) break 11 Breakpoint 1 at 0x80480a1: file teste.asm, line 11. (gdb) r Starting program: /home/maluta/coding/a.out Breakpoint 1, _start () at teste.asm:11 11 nop (gdb) print var1 $1 = 40 (gdb) info registers ecx edx ecx 0x0 0 edx 0x0 0
Adicionamos um breakpoint (eu precisei inserir duas instruções nop para o gdb realmente para no ponto) e verificamos os valores de var1, ecx e edx.
(gdb) si _start () at teste.asm:12 12 mov ecx, [var1] (gdb) si _start () at teste.asm:13 13 lea edx, [var1] (gdb) info registers ecx ecx 0x28 40 (gdb) si _exit () at teste.asm:16 16 mov eax, 1 (gdb) info registers edx edx 0x80490b8 134516920
E por fim, verificamos o conteúdo no endereço definido em edx.
(gdb) print *0x80490b8 $2 = 40
Algumas considerações:
- O Data Diplay Debugger (DDD) é um front-end muito bom para o GDB que pode ser utilizado ao invés da interface de linha de comando.
- O após label _exit há uma chamada a uma syscall (adivinha qual?) do kernel. Passa-se o valor (no registro eax) e chama uma interrupção (80h). A verdadeira “diversão” está em associar essas syscalls (write, fork, execve, …) mas isto é para outro post… Por enquanto vou lidar com os diferentes modos de endereçamento e operações lógicas e aritméticas.