Опыты дизассемблирования
Рассмотрим ряд простых программ на C и посмотрим
на их
ассемблерный код , который получим с помощью программы
gcc
.
/* Программа a1.c*/
#include<stdio.h>
int main()
{
int i, n = 0;
for(i=1; i <= 10 ; i++)
{
n += i*i;
}
printf("%d\n", n);
}
С помощью команды
можно получть программу, которая выдёёт на стандартный поток вывода сумму квадратов первых 10
натуральных чисел.
Чтобы получить ассемблерный код этой программы, запустите программу
gcc
с опцией
-S
Результат выполнения этой оманду будет файл
a1.s
.
Откройте его в текстовом редакторе и изучите содержимое.
Есть возможность получить ассемблерный код,
с включенными в него строчками исходного кода на C.
Это называется
gcc -c -g -Wa,-a,-ah,-an,-ad a1.c > a1.lst
; программа a1.s
.file "a1.c"
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $0, -8(%ebp)
movl $1, -4(%ebp)
.L2:
cmpl $10, -4(%ebp)
jle .L5
jmp .L3
.L5:
movl -4(%ebp), %eax
movl %eax, %edx
imull -4(%ebp), %edx
leal -8(%ebp), %eax
addl %edx, (%eax)
leal -4(%ebp), %eax
incl (%eax)
jmp .L2
.L3:
subl $8, %esp
pushl -8(%ebp)
pushl $.LC0
call printf
addl $16, %esp
leave
ret
.size main, .-main
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.3.3"
Программа 2
Аналогично из программы
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
while(n){ printf("%d", n%2 ); n /= 2; }
putc('\n', stdout);
return 0;
}
можно получть следующий ассемблерный код:
.file "a2.c"
.section .rodata
.LC0:
.string "%d"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
subl $8, %esp
leal -4(%ebp), %eax
pushl %eax
pushl $.LC0
call scanf
addl $16, %esp
.L2:
cmpl $0, -4(%ebp)
jne .L4
jmp .L3
.L4:
subl $8, %esp
movl -4(%ebp), %edx
movl %edx, %eax
sarl $31, %eax
shrl $31, %eax
leal (%eax,%edx), %eax
sarl $1, %eax
addl %eax, %eax
subl %eax, %edx
movl %edx, %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl -4(%ebp), %edx
movl %edx, %eax
sarl $31, %eax
shrl $31, %eax
leal (%eax,%edx), %eax
sarl $1, %eax
movl %eax, -4(%ebp)
jmp .L2
.L3:
subl $8, %esp
pushl stdout
pushl $10
call _IO_putc
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.3.3"
Q: How can I create a file where I can see the C code and its assembly translation together?
A: Use the -S (note: capital S) switch to GCC, and it will emit the assembly code to a file with a .s extension. For example, the following command:
gcc -O2 -S -c foo.c
will leave the generated assembly code on the file foo.s.
If you want to see the C code together with the assembly it was converted to, use a command line like this:
gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst
which will output the combined C/assembly listing to the file foo.lst.
If you need to both get the assembly code and to compile/link the program, you can either give the -save-temps option to GCC (which will leave all the temporary files including the .s file in the current directory), or use the
-Wa,aln=foo.s
option which instructs the assembler to output the assembly translation of the C code (together with the hex machine code and some additional info) to the file named after the =.