zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    生产者消费者问题 一个生产者 两个消费者 4个缓冲区 生产10个产品
    三个线程交替数数 数到100
    c++ 字符串去重
    Java中一个方法只被一个线程调用一次
    GEF开发eclipse插件,多页编辑器实现delete功能
    python-arp 被动信息收集
    ssrf
    TCP
    xxe
    越权
  • 原文地址:https://www.cnblogs.com/feika/p/3558466.html
Copyright © 2011-2022 走看看