gcc - GCC 和 STM32 的堆栈帧不正确
问题描述
我正在尝试在 GNU GCC(不是 ARM GCC)中创建简单的 SVC 处理程序。如果调用 SVC 服务,它会SVC_Handler()
正确输入,但是当我尝试查找用于调用 SVC Handler ( svc_number
) 的 SVC 编号时,我得到的值是 248 而不是 1。
我正在使用 CubeMX IDE 和 Nucleo-F401RE 板。
代码:
void SVC_Handler(void)
{
asm volatile (
"TST lr, #4\t\n"
"ITE EQ\t\n"
"MRSEQ r0, msp\t\n"
"MRSNE r0, psp\t\n"
"B %[SVC_Handler_Main]\t\n"
:
: [SVC_Handler_Main] "i" (SVC_Handler_Main)
: "r0"
);
}
void SVC_Handler_Main(unsigned int* svc_args) {
uint8_t svc_number;
svc_number = ((char* )svc_args[6])[-2];
switch(svc_number) { // <- that's where I get 248 instead of 1
case SVC_ADD:
SVC_Add_Handler(svc_args[0], svc_args[1]);
break;
default:
break;
}
}
int __attribute__ ((noinline)) SVC_Service_Add(int x, int y) {
svc(SVC_ADD);
}
#define SVC_ADD 1
#define svc(code) asm volatile ("SVC %[immediate]"::[immediate] "I" (code))
我使用了带有断点的监视表达式,svc_number
它的值是 248,而不是应该的 1。
服务调用 (SVC) 主要用于 RTOS 设计,以使软件进入特权模式。ARM GCC 对 SV 调用有一些很好的支持,而在 GNU GCC 中你必须自己做这一切。理论是这样的:当一个 SV 调用(在我的例子中是 SVC_Service_Add() )被调用时,它会调用 SVC_Handler()。SVC_Handler() 检查使用了哪个堆栈(主 msp 或进程 psp),该信息通过读取链接寄存器 (LR) 的位 2 找到。取决于此,msp 或 psp 保存在 r0 中。之后,编译器将 r0,r1,r2,r3,r12,r14、返回地址和 xPSR 放在 svc_args 中,这样这些参数就可以在 SVC_Handler_Main 中使用了。svc_args[0]=r0, svc_args[1]=r1,...svc_args[6]=SP(我们感兴趣的那个,保留SVC号的那个)。由于 Cortex M4 堆栈是完全下降的,我们需要做 [-2] 来获取我们感兴趣的 svc_args[6] 的字节。由于对 SVC_Handler 的调用是由 SVC_ADD 宏 (0x01) 完成的,因此 ((char *) svc_args[6])[-2] 应该等于 SVC_ADD,因此可以从 SVC_Handler_Main() 调用适当的函数。我没有得到 1,出于某种原因,我得到了 248。
问题:为什么svc_number
等于248而我期待1
解决方案
#define svc(code) asm volatile ("SVC %[immediate]"::[immediate] "I" (code))
这将创建表单的汇编程序svc #1
。请注意,“1”编码在指令操作码中。为了找到“1”,您必须查看lr
并在该地址加载操作码,然后解析(通过屏蔽)该值。
例如,
ldr r1,[lr] ; load svc opcode to r1 (might need an offset)
and r1, r1, #SVC_MASK ; may need shifts as well.
这效率不高,因为您将代码管道视为数据。执行此操作的正常方法是定义一个服务寄存器,例如r7
,然后在指令r7
之前设置为“#1” 。svc #0
所以,宏是这样的,
#define svc(code) asm volatile ("mov r7, %[immediate]\n" \
" SVC #0"::[immediate] "I" (code) \
: "r7" /*clobbers r7*)
您可以使用 just r0
,但如果您的调用层次结构变得更复杂,许多函数可能会将 args 放入 r0,r1,r2,r3 中,然后您需要对它们进行洗牌。这就是r7
通常使用的原因。
为什么
svc_number
等于 248 而我期待 1
看起来您认为它已放入堆栈,但事实并非如此。值 248 只是堆栈中的随机值。
推荐阅读
- swift - 如何在 Swift 中使用相同类型在另一个泛型中初始化一个泛型?
- html - 从高度 0 到 100 的过渡元素,从底部开始
- vb.net - 带变量的数据列表达式
- c - 禁用 clang-tidy 诊断
- webgl - WebGL 德罗斯特效果
- javascript - 未找到模块:导入模块以做出反应时无法解析“axios”
- iccube - icCube 中是否可以有没有层次结构的维度?
- html - 如何包装 SVG
里面的元素 ? - excel - 投资公式
- amazon-cloudformation - 在不使用 Jenkins cloudformation 插件启动创建/更新堆栈后,如何从 Jenkins Job 跟踪 Cloudformation 事件?