带调试信息的x86-64简单指令如何避免重定位截断错误?
这个问题的核心是stab格式调试信息在x86-64平台上的32位重定位限制,具体原因和可行解决办法如下:
为什么会触发重定位截断?
当你使用-g选项时,GNU汇编器(GAS)默认会生成stab格式的调试信息。这种调试格式比较老旧,在x86-64架构下,它会用R_X86_64_32类型的32位重定位来引用.text段的地址。
但x86-64平台的链接器默认会生成位置无关可执行文件(PIE),这类文件的代码段(.text)会被加载到高地址空间(通常是0x7f开头的64位地址),远远超出了32位整数的容纳范围(最大0xffffffff)。链接器无法把64位地址塞进32位的重定位项里,就会抛出relocation truncated to fit的错误。
而去掉-g选项时,没有生成调试信息,也就不存在这些指向.text的32位重定位项,自然不会触发错误。
解决办法:三种可行方案
1. 改用DWARF调试格式(推荐)
stab是过时的调试格式,x86-64平台的现代调试器(如GDB)都更好支持DWARF格式。你可以通过指定-gdwarf-2/-gdwarf-4等选项让GAS生成DWARF调试信息:
as -o t.o -gdwarf-4 -al=t.lst t.s ld -o t t.o
DWARF使用64位重定位来适配x86-64的地址空间,不会出现截断问题,同时调试信息的功能也更完整。
2. 禁用PIE生成非位置无关可执行文件
如果你坚持使用stab调试信息,可以让链接器生成非PIE的可执行文件,这类文件的.text段会被加载到低32位地址(比如0x400000附近),32位重定位就能容纳这个地址:
as -o t.o -g -al=t.lst t.s ld -no-pie -o t t.o
这种方法虽然能解决错误,但非PIE文件在现代系统中安全性稍差,且stab格式本身功能有限,还是更推荐第一种方案。
3. 强制使用64位重定位的stab格式(可选)
部分版本的GAS支持--gstabs+选项,生成支持64位地址的stab扩展格式:
as -o t.o --gstabs+ -al=t.lst t.s ld -o t t.o
不过这个选项的兼容性不如DWARF,优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者cardiff space man

