有没有一种方法可以单独输出一个函数的汇编代码?

14

我正在学习如何将C文件编译为机器码。我知道可以使用gcc-S标志生成汇编代码,但它还会产生与main()printf()有关的大量代码,而我目前对此不感兴趣。

是否有一种方法可以让gccclang仅"编译"一个函数并输出汇编代码?

仅获取以下C函数的汇编代码:

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

一些集成开发环境(IDE)可以让您设置断点并查看由该函数生成的汇编代码。这被称为“反汇编窗口”。这应该可以满足您的需求 - 您正在使用IDE吗? - Name
我更喜欢编译(带优化)再反汇编,你必须理解编译器会留下一些针对外部地址等未完成的指令,但在我看来比使用-S更容易阅读。gcc -O2 -c hello.c -o hello.o,objdump -D hello.o。 - old_timer
4
请前往这里:http://gcc.godbolt.org/,将函数粘贴到输入框中,选择编译器,非常有用。 - harold
2个回答

16
有两种方法针对特定的目标文件进行操作:
  1. 使用gcc选项-ffunction-sections会为被编译源文件中的每个函数创建一个独立的ELF节。
  2. 符号表包含给定函数的节名称、起始地址和大小;可以通过objdump使用--start-address/--stop-address参数输入。
第一个例子:
$ 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文件格式为elf64-x86-64。
.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的信息在目标文件中,但与代码分开(它在所谓的重定位部分中,该部分列出了要由链接器“修补”的目标文件中的位置);反汇编程序无法解析此信息。


我明白了,顺便告诉大家,你可以使用“gcc -ffunction-sections -c test.c”将源文件编译为对象文件。谢谢~ - ashleysmithgpu

2

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

这样可以生成更紧凑的汇编代码,没有其他干扰(除了头部和尾部)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接