GCC生成的汇编代码

Posted siwnchs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GCC生成的汇编代码相关的知识,希望对你有一定的参考价值。

假设我们写了一个C代码文件 code.c包含下面代码:

int accum = 0;

int sum(int x, int y)
{
    int t = x + y;
    accum += t;
    return t;
}
这是用echo命令输入源码的效果,简单的就是最好的:)
 
技术图片

 
 
 
一、查看GCC生成的汇编代码
 
 
 
 
在命令行上用“-S”选项,就能看到C编译器产生的汇编代码:
 #gcc -S code.c 
 
注意:这里是大写的-S,如果用小写gcc会说找不到main函数
 
会在当前目录下生成code.s文件,直接打开即可
 
这段汇编代码没有经过优化:
 
.file "code.c"
.globl _accum
 .bss
 .align 4
_accum:
 .space 4
 .text
.globl _sum
 .def _sum; .scl 2; .type 32; .endef
_sum:
 pushl %ebp
 movl %esp, %ebp
 subl $4, %esp                  # 为局部变量t在栈帧上分配空间
 movl 12(%ebp), %eax    # %eax <- y
 addl 8(%ebp), %eax       # %eax <- x + y
 movl %eax, -4(%ebp)     # t <- x +y
 movl -4(%ebp), %eax     # %eax <- t
 addl %eax, _accum        # _accum <- t + _accum
 movl -4(%ebp), %eax     # %eax <- t
 leave                                 # 平衡堆栈: %esp <- %ebp , popl %ebp
 ret                                      
 
 
下面是使用“-O2”选项开启二级优化的效果:
 
#gcc -O2 -S code.c
 
 .file "code.c"
.globl _accum
 .bss
 .align 4
_accum:
 .space 4
 .text
 .p2align 4,,15                    # 使下一条指令的地址从16的倍数处开始,
.globl _sum                        # 最多浪费15个字节
 .def _sum; .scl 2; .type 32; .endef
_sum:
 pushl %ebp                       # 保存原%ebp  
 movl %esp, %ebp       
 movl 12(%ebp), %eax     # %eax <- y
 movl 8(%ebp), %edx       # %edx <- x
 popl %ebp                        # 恢复原%ebp
 addl %edx, %eax             # %eax <- x + y
 addl %eax, _accum         # _accum <- _accum + x + y
 ret
 
 
GCC产生的汇编代码有点难读,它包含一些我们不关心的信息。所有以 "." 开头的行都是指导汇编器和链接器的命令,称为“汇编器命令”。
 
 
 
 
 
 
代码中已经除去了所有关于局部变量名或数据类型的信息,但我们还是看到了一个对全局变量_accum的引用,这是因为编译器还不能确定这个变量会放在存储中的哪个位置。
 
 
 
 
 
 
 
 
二、用GDB查看目标文件的字节表示
 
 
 
 
  首先,我们用反汇编器来确定函数sum的代码长度是19字节。然后我们在文件code.o上运行GNU调试工具GDB,输入命令:
 
 
 
 
(gdb) x/19xb sum
 
 
 
 
这条命令告诉GDB检查(简写为"x")19个以十六进制格式表示的字节。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
技术图片三、反汇编目标文件
 
 
 
 
  在Linux系统中,带 "-d" 命令行选项调用OBJDUMP可以完成这个任务:
 
 
 
 
#objdump -d code.o
 
 
 
 
 
 
 
技术图片 
 
 
 
从这里可以看出函数sum的代码长度正好是19字节。
 
 
四、生成实际可执行的代码
 
  这需要对一组目标文件运行链接器,而这一组目标代码文件中必须包含有一个Main函数。在 main.c 中有这样的函数:
 
  int main()
  {
       return sum(1,2);
  }
 
然后,我们用如下方法生成可执行文件:
 
#gcc -O2 -o prog code.o main.c
 
再反汇编:
 
objdump -d prog
 
 
00401050 <_sum>:
  401050: 55                              push   %ebp
  401051: 89 e5                        mov    %esp,%ebp
  401053: 8b 45 0c                   mov    0xc(%ebp),%eax
  401056: 8b 55 08                   mov    0x8(%ebp),%edx
  401059: 5d                              pop    %ebp
  40105a: 01 d0                        add    %edx,%eax
  40105c: 01 05 10 20 40 00  add    %eax,0x402010
  401062: c3                              ret 
 
 
  这段代码与code.c反汇编产生的代码几乎完全一样。一个主要的区别是左边列出的地址不同。第二个不同之处在于链接器终于确定了存贮全局变量accum的地址。地址由原来的0x0变成了现在的0x402010

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

以上是关于GCC生成的汇编代码的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 gcc 生成可以用 nasm 编译的汇编代码 [重复]

GCC生成的汇编代码

gcc生成含有C信息的汇编

GCC 无法从具有内联汇编的函数生成 32 位代码

linux下用gcc如何生成预处理汇编等文件

GCC编译过程