一个包含main函数的.c文件可以编译成.o文件(二进制目标代码)、.out文件(我经常使用后缀.exe,用来执行的文件)、.s文件(汇编文件)。
不包含的main函数的.c文件可以编译成.o文件、.s文件。
例:
main.c文件包含程序入口点main函数
gcc默认编译如 gcc -02 main.c -o main.exe 生成一个.exe二进制文件。它可以被命令./main.exe执行。但是如果文件中没有包含mian函数,按照上面的命令编译就会出错:/usr/lib/gcc/i486-linux-gnu/4.4.1/../../../../lib/crt1.o: In function `_start':/build/buildd/eglibc-2.10.1/csu/../sysdeps/i386/elf/start.S:115: undefined reference to `main'
code.c文件只包含一个sum函数:
int sum( int x, int y )
{
int t = x + y;
return t;
}
命令 gcc -02 -c code.c 可生成一个code.o二进制目标文件。
命令gcc -S code.c 可生成一个code.s汇编文件:
.file "code.c"
.text
.globl sum
.type sum, @function
sum:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.size sum, .-sum
.ident "GCC: (Ubuntu 4.4.1-4ubuntu8) 4.4.1"
.section .note.GNU-stack,"",@progbits
命令objdump -d code.o 反汇编code.o文件,显示在终端窗口:
Disassembly of section .text:
00000000 <sum>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
6: 8b 45 0c mov 0xc(%ebp),%eax
9: 8b 55 08 mov 0x8(%ebp),%edx
c: 8d 04 02 lea (%edx,%eax,1),%eax
f: 89 45 fc mov %eax,-0x4(%ebp)
12: 8b 45 fc mov -0x4(%ebp),%eax
15: c9 leave
16: c3 ret
一些区别是gcc -S 命令生成的汇编代码的常数用$xx形式的十进制数字来表示,而且指令指明了操作数的长度,而objdump -d 反汇编生成的汇编代码中用0x形式的十六进制表示,指令看不出操作数的长度;各自leal指令的形式有些不同。
刚看这段汇编代码的时候不解的是c,f ,12三行:
c: lea (%edx,%eax,1),%eax
f: 89 45 fc mov %eax,-0x4(%ebp)
12: 8b 45 fc mov -0x4(%ebp),%eax
把结果放到寄存器eax中,再把eax的值放到帧栈指针值偏移-4的内存中,反过来又读到eax中。
想了一下也许是为了避免存在寄存器与存在内存中的数据的精度表示差异。
命令 gdb code.o 启用gdb调试code.o代码。