为什么调整arm-none-eabi-ld链接目标文件顺序会改变可执行文件运行行为
问题根本原因
- 你通过
objcopy将ELF文件转换为了纯二进制bin文件,这类文件不包含任何入口地址、段属性等元信息,只是程序内存镜像的直接拼接。 - QEMU的
versatilepb平台使用-kernel参数加载bin文件时,会默认将bin内容加载到0x10000地址,直接从0x10000地址开始取指执行,完全不会读取原ELF文件中通过ENTRY(start)指定的入口地址。 - 你的链接脚本中
.text段的合并规则为*(.text),ld在合并多个目标文件的.text段时,严格按照命令行输入的目标文件顺序排列:- 当链接顺序为
ts.o t.o时,ts.o的.text段排在最前面,位于0x10000地址的是ts.s中定义的start初始化代码。QEMU启动后会先执行ldr sp, =stack_top设置正确的栈指针,再跳转到main执行,程序运行正常。 - 当链接顺序为
t.o ts.o时,t.o的.text段(即main函数的二进制代码)被排在最前面的0x10000地址。QEMU启动后直接执行main函数的代码,完全没有运行start段的栈初始化逻辑,此时SP还是QEMU上电的默认值(也就是你看到的0xf3575ec0这类不在你规划的内存范围内的地址),后续调用sum函数需要压栈操作时访问非法地址,自然出现异常。
- 当链接顺序为
解决方案
你可以选择任意一种方法规避这个问题:
- 直接使用ELF文件启动QEMU,不需要转换为bin:
qemu-system-arm -M versatilepb -kernel t.elf -nographic -serial /dev/null,QEMU会读取ELF头的入口地址执行start代码,不受链接顺序影响。 - 修改链接脚本的
.text段规则,强制将ts.o的代码放在最开头,无论链接顺序如何都能保证入口正确:
.text : { ts.o(.text) *(.text) }
内容的提问来源于stack exchange,提问作者reininger
相关产品推荐
相关产品推荐

