有没有办法单独输出单个函数的程序集?

ash*_*gpu 7 compiler-construction assembly gcc clang

我正在学习如何将C文件编译为机器代码.我知道我可以gcc使用-S标志生成汇编,但是它也会生成很多代码,main()而且printf()我现在对此不感兴趣.

有没有办法单独获取gccclang" 编译 "一个函数并输出程序集?

即单独获取以下c的程序集:

int add( int a, int b ) {
    return a + b;
}
Run Code Online (Sandbox Code Playgroud)

Fra*_*kH. 7

有两种方法可以为特定的目标文件执行此操作:

  1. 指示它为正在编译的源文件中的每个函数创建单独的ELF部分-ffunction-sections选项.gcc
  2. 符号表包含段名,起始地址和给定函数的大小; 可以objdump通过--start-address/ --stop-addressarguments输入.

第一个例子:

$ readelf -S t.o | grep ' .text.'
  [ 1] .text             PROGBITS         0000000000000000  00000040
  [ 4] .text.foo         PROGBITS         0000000000000000  00000040
  [ 6] .text.bar         PROGBITS         0000000000000000  00000060
  [ 9] .text.foo2        PROGBITS         0000000000000000  000000c0
  [11] .text.munch       PROGBITS         0000000000000000  00000110
  [14] .text.startup.mai PROGBITS         0000000000000000  00000180

这已被编译-ffunction-sections并有四大功能,foo(),bar(),foo2()munch()我的目标文件.我可以像这样单独拆卸它们:

$ objdump -w -d --section=.text.foo t.o

t.o:     file format elf64-x86-64

Disassembly of section .text.foo:

0000000000000000 <foo>:
   0:   48 83 ec 08             sub    $0x8,%rsp
   4:   8b 3d 00 00 00 00       mov    0(%rip),%edi        # a <foo+0xa>
   a:   31 f6                   xor    %esi,%esi
   c:   31 c0                   xor    %eax,%eax
   e:   e8 00 00 00 00          callq  13 <foo+0x13>
  13:   85 c0                   test   %eax,%eax
  15:   75 01                   jne    18 <foo+0x18>
  17:   90                      nop
  18:   48 83 c4 08             add    $0x8,%rsp
  1c:   c3                      retq

另一个选项可以像这样使用(nm转储符号表条目):

$ nm -f sysv t.o | grep bar
bar       |0000000000000020|   T  |    FUNC|0000000000000026|     |.text
$ objdump -w -d --start-address=0x20 --stop-address=0x46 t.o --section=.text

t.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000020 <bar>:
  20:   48 83 ec 08             sub    $0x8,%rsp
  24:   8b 3d 00 00 00 00       mov    0(%rip),%edi        # 2a <bar+0xa>
  2a:   31 f6                   xor    %esi,%esi
  2c:   31 c0                   xor    %eax,%eax
  2e:   e8 00 00 00 00          callq  33 <bar+0x13>
  33:   85 c0                   test   %eax,%eax
  35:   75 01                   jne    38 <bar+0x18>
  37:   90                      nop
  38:   bf 3f 00 00 00          mov    $0x3f,%edi
  3d:   48 83 c4 08             add    $0x8,%rsp
  41:   e9 00 00 00 00          jmpq   46 <bar+0x26>

在这种情况下,-ffunction-sections选项没有被使用,因此开始时的功能的偏移不是零,并且它不是在其单独的部分(但在.text).

请注意,在拆卸目标文件时...

这不完全是你想要的,因为对于目标文件,call目标(以及全局变量的地址)没有被解析 - 你在这里看不到这些foo调用printf,因为二进制级别的分辨率只发生在链接时.虽然装配源也有call printf.这callq实际上printf是在目标文件中的信息,但是与代码分开(它在所谓的重定位部分中,列出目标文件中的位置,以便链接器"修补"); 反汇编程序无法解决这个问题.