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

时间:2013-04-30 13:55:08

标签: gcc assembly compiler-construction clang

我正在学习如何将C文件编译为机器代码。我知道我可以使用gcc标记从-S生成汇编,但是它也产生了很多与main()printf()无关的代码。那一刻。

有没有办法让gccclang编译”一个独立的函数并输出程序集?

I.e。单独获取以下c的程序集:

int add( int a, int b ) {
    return a + b;
}

2 个答案:

答案 0 :(得分:7)

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

  1. -ffunction-sections的{​​{1}}选项指示它为正在编译的源文件中的每个函数创建单独的ELF部分
  2. 符号表包含部分名称,起始地址和给定函数的大小;可以通过gcc / objdump参数提供给--start-address
  3. 第一个例子:

    $ 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

    这是使用--stop-address编译的,我的目标文件中有四个函数-ffunction-sectionsfoo()bar()foo2()。我可以像这样单独拆卸它们:

    $ 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

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

    $ 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>

    在这种情况下,nm选项未使用,因此函数的起始偏移量不为零,并且它不在其单独的部分中(但在{{ 1}})。

    在反汇编目标文件时要小心......

    这不是完全你想要的东西,因为对于目标文件,-ffunction-sections目标(以及全局变量的地址)都没有解决 - 你不能请参阅此处.text调用call,因为二进制级别的解析仅在链接时发生。虽然汇编源中有foo。此printf实际上为call printf的信息位于目标文件中,但与代码分开(它位于所谓的重定位部分,列出了对象中的位置文件由链接器“修补”;反汇编程序无法解决这个问题。

答案 1 :(得分:0)

最好的方法是将您的函数复制到一个temp.c C文件中,并使用-c标记进行编译,如下所示:gcc -c -S temp.c -o temp.s

它应该产生一个更加紧凑的汇编代码,没有其他分心(页眉和页脚除外)。