【发布时间】:2021-12-07 18:39:38
【问题描述】:
使用时我的行为有所不同
arm-none-eabi-ld -T t.ld -o t.elf t.o ts.o
链接我的目标文件,vs
arm-none-eabi-ld -T t.ld -o t.elf ts.o t.o
目标文件 't.o' 和 'ts.o' 在命令中被转置。后一个版本会产生正确的行为,而前一个版本不会。不同之处似乎是我的程序中的堆栈指针与第一个版本设置不正确,我想知道为什么会这样。
这是我正在使用的源文件和链接器脚本,以及要编译的脚本。
t.ld
ENTRY(start) /* define start as the entry address */
SECTIONS
{
. = 0x10000; /* loading address, required by QEMU */
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
. =ALIGN(8);
. =. + 0x1000;
stack_top =.;
}
t.c
int g = 100; // un-initialized global
extern int sum(int a, int b, int c, int d, int e, int f);
int main() {
int a, b, c, d, e, f; // local variables
a = b = c = d = e = f = 1; // values do not matter
g = sum(a, b, c, d, e, f); // call sum()
}
ts.s
/*
Assembly file to define sum()
*/
.global start, sum
start:
ldr sp, =stack_top // set sp to stack top
bl main // call main()
stop: b stop // loop
sum:
// establish stack frame
stmfd sp!, {fp, lr} // push lr and fp
add fp, sp, #4 // fp -> saved lr on stack
// compute sum of all 6 parameters
add r0, r0, r1 // r0 = a + b
add r0, r0, r2 // r0 = a + b + c
add r0, r0, r3 // r0 = a + b + c + d
ldr r3, [fp, #4] // r1 = e
add r0, r0, r3 // r0 = a + b + c + d + e
ldr r3, [fp, #8] // r1 = f
add r0, r0, r3 // r0 = a + b + c + d + e + f
// return
sub sp, fp, #4 // point stack pointer to saved fp
ldmfd sp!, {fp, pc} // return to caller
mk.sh(带有产生预期结果的链接器命令)
arm-none-eabi-as -o ts.o ts.s # assemble ts.s
arm-none-eabi-gcc -c t.c # cross-compile t.c into t.o
arm-none-eabi-ld -T t.ld -o t.elf ts.o t.o # link object files into t.elf
arm-none-eabi-objcopy -O binary t.elf t.bin # convert t.elf to t.bin
运行二进制文件后
qemu-system-arm -M versatilepb -kernel t.bin -nographic -serial /dev/null
我得到以下信息。堆栈指针(R13)正确
(qemu) info registers
R00=00000000 R01=00000001 R02=000100c0 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=000110c8 R14=00010008 R15=00010008
PSR=400001d3 -Z-- A svc32
FPSCR: 00000000
VS 使用带有转置目标文件的链接器命令的结果
(qemu) info registers
R00=00000000 R01=00000183 R02=00000100 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=f3575ee4
R12=00000000 R13=f3575ec0 R14=00010060 R15=00010000
PSR=400001d3 -Z-- A svc32
FPSCR: 00000000
堆栈指针(R13)明显超出程序的内存范围。
【问题讨论】:
-
它真的找到了你的
start符号吗?如果它只是使用.text部分的顶部,那将取决于首先链接哪个目标文件。 (但ld会对此发出警告,例如warning: cannot find entry symbol _start; defaulting to 0000000008049000或类似的)。您的.global start和ENTRY(start)应该意味着这不是问题,但可能与调试器一起检查它在哪里输入您的代码。 -
我没有收到您提到的警告,但是鉴于 PC(R15) 仍位于版本不正确的加载地址,我认为您可能是正确的,程序不是事件启动。我没有使用带有 QEMU 裸机的调试器,但我会研究它。感谢您的帮助。
-
您正在运行 .bin 文件,因此您肯定需要在二进制文件中首先而不是最后一个引导代码 (ts.o),将其他任何内容放在命令行前面将构建一个二进制文件预计不会工作。
-
哦,对了,你设置了 ELF 入口点就好了,但是你用 objcopy 剥离了元数据,只留下二进制顶部的隐式入口点。我认为这就是 old_timer 的长答案旨在展示的内容,并且可能会在所有文本和代码中的某个地方说出来。
-
使用 ENTRY() 是 qemu 的一种可能的解决方法,如果您使用 elf 文件,但最好只知道如何使用这些工具。
标签: assembly linker arm qemu arm-none-eabi-gcc