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

原文地址:https://www.cnblogs.com/siwnchs/p/10463951.html

时间: 2024-08-29 10:08:01

GCC生成的汇编代码的相关文章

使用hsdis查看jit生成的汇编代码

http://blog.csdn.net/unei66/article/details/26477629 JVM 有 HotSpot引擎可以对热代码路径进行有效的 JIT优化,大幅度提升计算密集代码的性能.默认一个方法至少被调用10k次以上才可能被JIT优化. 查看JIT工作情况 Java代码 [java] view plain copy print? public class VolatileBarrierExample { long a; volatile long v1=1; volati

linux 下gcc生成intel汇编

留作备忘: gcc -S -masm=intel xxxx.c 生成elf可执行文件: gcc -o xxx xxxx.s linux 下gcc生成intel汇编,码迷,mamicode.com

看看GNU编译器都生成了什么样的汇编代码

平时工作中有接触到汇编,一时兴起,就想看看GNU的编译器生成的汇编代码是什么样的. 1. 生成汇编代码 我写了一个非常简单的C语言代码,如下 然后,执行"gcc -S simple_program.s simple_program.c"生成汇编代码(simple_program.s). 如下是注释了的汇编代码,编译器生成的汇编代码是没有注释的. 2. 汇编的知识,再说几点 在汇编代码中,我增加了不少注释.有些问题,我觉得光靠注释是说不清楚的,这里简明交待两点. 2.1 汇编程序中的se

通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

实验一:通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 学号:20135114 姓名:王朝宪 注: 原创作品转载请注明出处   <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1 1)实验部分(以下命令为实验楼64位Linux虚拟机环境下适用,32位Linux环境可能会稍有不同) 使用 gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与

解析c语言背后的汇编代码

源码 很简单的c语言代码,作用是交换两个数: 1 #include <stdio.h> 2 3 void swap(int * a, int * b) { 4 *a = *a + *b - (*b = *a); 5 return; 6 } 汇编代码解析 在gcc编译环境下执行, gcc -S  -o test.s test.c 命令生成相关汇编代码. 1 .file "test.c" 2 .text 3 .globl _swap 4 .def _swap; .scl 2;

Android漫游记(5)---ARM GCC 内联汇编烹饪书(附实例分析)

原文链接(点击打开链接) 关于本文档 GNU C编译器针对ARM RISC处理器,提供了内联汇编支持.利用这一非常酷炫的特性,我们可以用来优化软件代码中的关键部分,或者可以使用针对特定处理的汇编处理指令. 本文假定,你已经熟悉ARM汇编语言.本文不是一篇ARM汇编教程,也不是C语言教程. GCC汇编声明 让我们从一个简单的例子开始.下面的一条ARM汇编指令,你可以添加到C源码中. /* NOP example-空操作 */ asm("mov r0,r0"); 上面的指令,讲r0寄存器的

C编译器剖析_6.3.5 汇编代码生成_为类型转换产生汇编代码

6.3.5  为类型转换产生汇编代码 在这一小节中,我们来讨论一下整型和浮点型之间的类型转换.有些类型转换并不需要在汇编层次进行数据转换,例如int和unsigned  int之间的转换只是改变了表达式的类型,对数据本身并无影响,以下表达式"(unsigned int) a"对应的二进制数据为0xFFFFFFFF,而表达式"a"对应的二进制数据也为0xFFFFFFFF.但对相同内容的二进制数据来说,进行"有符号整数的右移"和"无符号整数

SDRAM和重定位(二)---开始在汇编代码中调用 C 语言

前面的点亮led的代码由于比较简单,所以全部用汇编代码完成,但是随着代码越来越多,逻辑关系越来越复杂,想要完全用汇编代码来写程序不太现实,必须要借助 c 语言程序,那么就会有从汇编语言到 c 语言的一个过渡阶段. ======================================================= 如何在汇编语言中调用 c 语言? 在汇编中调用 c语言程序的方法很简单,只需利用汇编代码:bl xxx(函数名)即可,但是重点不是如何调用 c 程序,而是汇编代码要为运行 c

C编译器剖析_6.3.4 汇编代码生成_为函数调用与返回产生汇编代码

6.3.4        为函数调用与返回产生汇编代码 在这一小节中,我们来讨论一下如何为函数调用和函数返回生成汇编代码.函数调用对应的中间指令如下所示: //中间指令的四元式: < opcode, DST, SRC1, SRC2> <CALL, 用于接收返回值的变量retVal, 函数名func,  参数列表[arg1,arg2, -,argn]> 让我们先熟悉一下C函数的调用约定CallingConvention,我们需要把参数从右向左入栈(即从argn到arg1依次入栈),不