测试在32位Linux x86平台上进行。
假设我正在编写一个C ++程序,在GCC
编译器生成的汇编代码中,存在一些这样的指令:
call _ZNSt8ios_baseC2Ev
movl _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+4, %ebx
movb $0, 312(%esp)
movl _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+8, %ecx
....
请特别注意符号_ZTTSt14basic_ifstreamIcSt11char_traitsIcEE
。
编译之后,假设我得到一个unstripped
二进制文件,我检查了这个符号:
readelf -s a.out | grep "_ZTTSt14basic"
69: 080a7390 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)
72: 080a7220 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ofstreamIcS@GLIBCXX_3.4 (3)
705: 080a7220 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ofstreamIcS
1033: 080a7390 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ifstreamIcS
请参阅,这是我的第一个问题,为什么符号_ZTTSt14basic_ifstreamIcSt11char_traitsIcEE
的名称已修改为_ZTTSt14basic_ifstreamIcS
和_ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)
?
什么是_ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)
?
然后我剥离了二进制文件:
strip a.out
readelf -s a.out | grep "_ZTTSt14basic"
69: 080a7390 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)
72: 080a7220 16 OBJECT WEAK DEFAULT 27 _ZTTSt14basic_ofstreamIcS@GLIBCXX_3.4 (3)
然后在我反汇编二进制文件后,相应的反汇编汇编指令是:
8063ee7: e8 84 54 fe ff call 8049370 <_ZNSt8ios_baseC2Ev@plt>
8063eec: 8b 1d 94 73 0a 08 mov 0x80a7394,%ebx
8063ef2: c6 84 24 38 01 00 00 movb $0x0,0x138(%esp)
8063ef9: 00
8063efa: 8b 0d 98 73 0a 08 mov 0x80a7398,%ecx
此时我们可以发现0x80a7394等于_ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+4
。
为了重用这些说明,我修改了代码:
call _ZNSt8ios_baseC2Ev
mov _ZTTSt14basic_ifstreamIcS+4,%ebx
movb $0x0,0x138(%esp)
mov _ZTTSt14basic_ifstreamIcS+8,%ecx
并进行了类似的更新(请参阅此question以供参考):
echo ""_ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)" = 0x080a7390;" > symbolfile
g++ -Wl,--just-symbols=symbolfile final.s
readelf -s a.out | grep "_ZTTSt14basic"
3001: 080a7390 0 NOTYPE LOCAL DEFAULT 27 _ZTTSt14basic_ifstreamIcS
8412: 080a7390 0 NOTYPE GLOBAL DEFAULT ABS _ZTTSt14basic_ifstreamIcS
我调试了新生成的二进制文件,令我惊讶的是,在新生成的二进制文件中,符号_ZTTSt14basic_ifstreamIcS
在_ZNSt8ios_baseC2Ev
的函数调用后没有得到任何值,而在原始二进制文件中,函数调用_ZTTSt14basic_ifstreamIcS
确实得到一些引用库部分的内存地址。这意味着:
call _ZNSt8ios_baseC2Ev
mov _ZTTSt14basic_ifstreamIcS+4,%ebx <--- %ebx gets zero!
movb $0x0,0x138(%esp)
mov _ZTTSt14basic_ifstreamIcS+8,%ecx <--- %ecx gets zero!
我必须说明在原始二进制文件的这些行中,寄存器%ebx和%ecx都获得了一些引用libc部分的地址。
这是我的第二个问题,为什么符号_ZTTSt14basic_ifstreamIcS
在函数调用_ZNSt8ios_baseC2Ev
之后没有得到任何值?我也尝试过使用符号名_ZTTSt14basic_ifstreamIcSt11char_traitsIcEE
。但这也行不通。
我清楚了吗?谁能救我的屁股?谢谢!