首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GCC和STM32栈帧不正确

GCC和STM32栈帧不正确
EN

Stack Overflow用户
提问于 2020-02-03 19:21:50
回答 1查看 628关注 0票数 2

我试图创造简单的SVC处理在GNU GCC (不是武装GCC)。如果调用SVC服务,它将正确地进入SVC_Handler(),但是当我试图找到用于调用SVC (svc_number)的SVC编号时,我得到的值为248而不是1。

我使用的是CubeMX IDE和Nucleo-F401RE板。

代码:

代码语言:javascript
复制
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)主要用于实时操作系统的设计,使软件进入特权模式。ARM GCC对SV呼叫有一些很好的支持,而在GNU GCC中,你必须自己做。理论是这样的:当一个SV调用(在我的例子中是SVC_Service_Add() )被调用时,它会调用SVC_Handler()。SVC_Handler()检查使用哪个堆栈(main或process ),该信息是通过读取链接寄存器(LR)的第2位找到的。根据这一点,msp或psp都保存在r0中。然后,编译器将r0、r1、r2、r3、r12、r14、返回地址和xPSR放在svc_args中,这样就可以在SVC_Handler_Main中使用这些参数。svc_args=r0,svc_args1=r1,...svc_args6=SP(我们感兴趣的,保存SVC编号的那个)。因为Cortex M4堆栈是完全降序的,所以我们需要做-2来获得我们感兴趣的svc_args6的字节。由于对SVC_Handler的调用是由SVC_ADD宏(0x01)完成的,所以((char *) svc_args6)-2应该等于SVC_ADD,因此可以从SVC_Handler_Main()调用适当的函数。我没有得到1,因为某种原因我得到了248。

问题:为什么svc_number等于248,而我期望1

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-04 03:50:42

代码语言:javascript
复制
#define svc(code) asm volatile ("SVC %[immediate]"::[immediate] "I" (code))

这将创建表单svc #1的汇编程序。请注意,“1”是在指令操作代码中编码的。为了找到'1',您必须查看lr并在该地址加载op代码,然后解析(通过掩蔽)值。

例如,

代码语言:javascript
复制
ldr r1,[lr]            ; load svc opcode to r1 (might need an offset)
and r1, r1, #SVC_MASK  ; may need shifts as well.

当您将代码管道视为数据时,这是不有效的。通常的方法是定义一个服务寄存器,比如r7,然后在svc #0指令之前将r7设置为'#1‘。所以,宏就像,

代码语言:javascript
复制
#define svc(code) asm volatile ("mov r7, %[immediate]\n" \
                                " SVC #0"::[immediate] "I" (code) \
                                 : "r7" /*clobbers r7*)

您可以只使用r0,但是如果调用层次结构变得更加复杂,许多函数可能会将arg放入r0、r1、r2、r3中,然后需要对它们进行洗牌。这就是为什么通常使用r7

为什么svc_number等于248,而我期望的是1

看起来,您认为它是放在堆栈上的,这是,而不是。248值只是堆栈上的随机值。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60045830

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档