13

I am learning how a C file is compiled to machine code. I know I can generate assembly from gcc with the -S flag, however it also produces a lot of code to do with main() and printf() that I am not interested in at the moment.

Is there a way to get gcc or clang to "compile" a function in isolation and output the assembly?

I.e. get the assembly for the following c in isolation:

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

2 回答 2

15

对于特定的目标文件,有两种方法可以做到这一点:

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

第一个例子:

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

这已经编译,并且在我的目标文件中-ffunction-sections有四个函数 , foo(),和 。我可以像这样单独拆卸它们:bar()foo2()munch()

$ objdump -w -d --section=.text.foo 到

to:文件格式elf64-x86-64

.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 测试 %eax,%eax
  15:75 01 jne 18 <foo+0x18>
  17: 90 诺普
  18: 48 83 c4 08 添加 $0x8,%rsp
  1c:c3 retq

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

$ nm -f sysv 到 | grep 栏
酒吧 |0000000000000020| T | 功能|0000000000000026| |.text
$ objdump -w -d --start-address=0x20 --stop-address=0x46 to --section=.text

to:文件格式elf64-x86-64

部分.text的反汇编:

0000000000000020 <条>:
  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 测试 %eax,%eax
  35:75 01 jne 38 <bar+0x18>
  37:90 诺普
  38: bf 3f 00 00 00 移动 $0x3f,%edi
  3d: 48 83 c4 08 添加 $0x8,%rsp
  41: e9 00 00 00 00 jmpq 46 <bar+0x26>

在这种情况下,-ffunction-sections使用该选项,因此该函数的起始偏移量不为零,并且不在其单独的部分中(而是在 中)。.text

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

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

于 2013-04-30T17:39:01.940 回答
1

最好的方法是将你的函数复制到一个C 文件中,并使用如下标志temp.c编译它:-cgcc -c -S temp.c -o temp.s

它应该产生更紧凑的汇编代码,没有其他干扰(页眉和页脚除外)。

于 2013-04-30T15:02:28.290 回答