我正在学习如何将C文件编译为机器码。我知道可以使用gcc
和-S
标志生成汇编代码,但它还会产生与main()
和printf()
有关的大量代码,而我目前对此不感兴趣。
是否有一种方法可以让gcc
或clang
仅"编译"一个函数并输出汇编代码?
即仅获取以下C函数的汇编代码:
int add( int a, int b ) {
return a + b;
}
我正在学习如何将C文件编译为机器码。我知道可以使用gcc
和-S
标志生成汇编代码,但它还会产生与main()
和printf()
有关的大量代码,而我目前对此不感兴趣。
是否有一种方法可以让gcc
或clang
仅"编译"一个函数并输出汇编代码?
即仅获取以下C函数的汇编代码:
int add( int a, int b ) {
return a + b;
}
gcc
选项-ffunction-sections
会为被编译源文件中的每个函数创建一个独立的ELF节。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
的信息在目标文件中,但与代码分开(它在所谓的重定位部分中,该部分列出了要由链接器“修补”的目标文件中的位置);反汇编程序无法解析此信息。
最好的方法是将您的函数复制到单个temp.c
C文件中,并使用-c
标志编译它,例如:gcc -c -S temp.c -o temp.s
这样可以生成更紧凑的汇编代码,没有其他干扰(除了头部和尾部)。