GCC能否排除crt*.o的DWARF5调试信息同时保留自有代码调试信息?
问题原因
你添加的-gdwarf-4 -gstrict-dwarf参数仅会控制当前编译流程中,编译器、汇编器处理自有源码生成的目标文件的DWARF版本,不会影响链接阶段GCC自动引入的系统预编译C运行时启动文件(crt1.o、crti.o、crtn.o、Scrt1.o等crt*.o系列文件)。这些文件是发行版构建glibc时预编译生成的,目前多数新发行版默认使用DWARF 5格式生成调试信息,因此哪怕自有代码全部生成DWARF 4信息,最终链接出的二进制仍会携带DWARF 5编译单元,触发Ghidra抛出异常。
可行解决方案
可以通过ld链接器的段丢弃规则实现需求:仅剔除来自crt系列文件的调试信息,完整保留自有代码的DWARF 4调试信息,不需要修改系统文件。
- 新建一个极简链接脚本片段,比如命名为
strip-crt-dwarf.ld,内容如下:
这段规则的作用是告诉链接器:所有匹配通配符路径的启动目标文件中,所有以SECTIONS { /DISCARD/ : { */crt*.o(.debug*) */Scrt1.o(.debug*) */gcrt1.o(.debug*) } }.debug开头的段(即全部DWARF调试信息段)直接丢弃,不链接进最终二进制。 - 编译代码时,在原有编译参数基础上追加参数,把这个链接脚本传给ld即可:
编译完成后用gcc -gdwarf-4 -gstrict-dwarf foo.c -o foo -Wl,-T,strip-crt-dwarf.ldreadelf -w foo验证,就看不到来自crt文件的DWARF 5编译单元了,自有代码的DWARF 4调试信息会完整保留,Ghidra可以正常加载。
小提示:如果你的项目中存在以
crt开头命名的自有目标文件,担心被通配符误匹配,可以把链接脚本里的路径改成对应系统库的实际路径,比如Debian/Ubuntu x86_64环境下可以写成/usr/lib/x86_64-linux-gnu/crt*.o(.debug*),就只会剔除系统路径下的启动文件调试信息。
其他可选方案
如果你不想维护额外的链接脚本,也可以手动重排链接顺序控制strip规则的生效范围:先单独编译自有源码为目标文件,再手动调用ld,在引入crt文件时开启调试段剥离,引入自有目标文件和系统库时关闭剥离。不过这种方式需要手动指定所有链接依赖,操作复杂度更高,不如链接脚本方案易用。
内容的提问来源于stack exchange,提问作者Tavian Barnes
相关产品推荐
相关产品推荐

