我正在做一个小项目,在裸机(无操作系统)上为 ARM 使用 Linux 标准 C 库。我使用 qemu-system-arm 作为执行平台,使用 GDB 进行调试。我编写了一个小系统调用处理程序来处理 C 库进行的 SVC 调用,但我感到困惑的是,即使 SVC 处理程序可以,我未处理的系统调用函数也无法将堆栈遍历回调用者。处理程序代码是:
SVC_Handler:
srsfd sp!, #Mode_SYS // Save LR_svc and SPSR_svc on the sys stack.
cpsid i, #Mode_SYS // Switch to sys mode.
push {r4-r12, lr} // Save registers.
// In a system call.
// r7 is the call number.
__in_syscall: // The stack frame is valid here.
cmp r7, #512
blhs Unhandled_SVC // Jump if too big for a syscall.
adr r8, SVC_Table // Get the system call table.
str r7, SysCall // Save call number for error reporting.
ldr r7, [r8, r7, lsl #2]// Get the stystem call entry.
blx r7 // Dispatch. Return value is in r0/r1
goback:
pop {r4-r12, lr} // Restore registers.
rfeia sp! // And return.
SysCall:
.word 0
// Unhandled system calls.
Unhandled_SVC:
stmfd sp!, {r12, lr}
push {r2-r5} // Push extra arguments.
mov r3, r1
mov r2, r0
ldr r1, SysCall // And the system call number.
ldr r0, stringPtr // Get the format string.
bl printf
add sp, #16 // clean up the stack.
mov r0, #-ENOSYS
ldmfd sp!, {r12, pc}
如果我在 __in_syscall 处设置断点,我可以很好地看到堆栈帧。如果我通过分支或间接通过 SVC_Table 中的指针进入 Unhandled_SVC,即使程序正确执行,GDB 也会混淆显示堆栈帧。
我错过了什么?
这是我的ELLCC 嵌入式编译器项目的一部分,完整的源代码在这里。