我正在学习如何将C文件编译为机器代码。我知道我可以使用gcc
标记从-S
生成汇编,但是它也产生了很多与main()
和printf()
无关的代码。那一刻。
有没有办法让gcc
或clang
“编译”一个独立的函数并输出程序集?
I.e。单独获取以下c的程序集:
int add( int a, int b ) {
return a + b;
}
答案 0 :(得分:7)
有两种方法可以为特定目标文件执行此操作:
-ffunction-sections
的{{1}}选项指示它为正在编译的源文件中的每个函数创建单独的ELF部分。gcc
/ objdump
参数提供给--start-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
这是使用--stop-address
编译的,我的目标文件中有四个函数-ffunction-sections
,foo()
,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
它应该产生一个更加紧凑的汇编代码,没有其他分心(页眉和页脚除外)。