为何GNU ld处理NASM与GAS等效汇编生成的.o文件输出不同?
解答
这种差异的核心原因是NASM和GAS生成的目标文件中,.text段的默认对齐属性不同,ld在链接时会严格遵循段的对齐要求来安排代码位置,最终导致入口地址和文件大小出现差异。
具体分析
段对齐属性差异
虽然用strip --strip-section-headers剥离段头后两个.o文件内容一致,但原始目标文件的段头信息中,.text段的对齐要求不同:- GAS生成的
.text段默认对齐值为16字节 - NASM生成的
.text段默认对齐值为8字节(不同版本可能略有差异)
- GAS生成的
ld的链接行为
非PIE模式下,ELF可执行文件的LOAD段起始地址固定为0x400000,LOAD段开头包含64字节的ELF头+56字节的程序头表(共120字节,即0x78):- 对于NASM的.o文件,
.text段要求8字节对齐,0x78是8的倍数,因此ld直接将代码放在该位置,LOAD段总大小为120+12=132字节(代码共12字节),入口地址为0x400078。 - 对于GAS的.o文件,
.text段要求16字节对齐,0x78不是16的倍数,ld会在程序头表后填充8字节空数据,将代码起始位置调整到0x80(128字节,16的倍数),LOAD段总大小变为128+12=140字节,入口地址为0x400080。
- 对于NASM的.o文件,
验证方法
执行readelf -S tiny-nasm.o和readelf -S tiny-gas.o,对比.text段的Align字段,即可看到两者的对齐值差异。统一输出的方法
手动指定.text段的对齐值,消除汇编器默认设置差异:- NASM代码中添加
ALIGN 16,或编译时使用nasm -f elf64 -align 16 tiny-nasm.asm - GAS代码中添加
.align 8
- NASM代码中添加
这样ld链接时会使用相同的对齐要求,生成的二进制文件大小和入口地址将完全一致。
内容的提问来源于stack exchange,提问作者MestreLion
相关产品推荐
相关产品推荐

