簡體   English   中英

GCC 和 STM32 的堆棧幀不正確

[英]Stack Frame not correct with GCC and STM32

我正在嘗試在 GNU GCC(不是 ARM GCC)中創建簡單的 SVC 處理程序。 如果調用 SVC 服務,它會正確輸入SVC_Handler() ,但是當我嘗試查找用於調用 SVC 處理程序 ( 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之后使用了帶斷點的 watch 表達式,它的值是 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 ,然后在svc #0指令之前將r7設置為“#1”。 所以,宏是這樣的,

#define svc(code) asm volatile ("mov r7, %[immediate]\n" \
                                " SVC #0"::[immediate] "I" (code) \
                                 : "r7" /*clobbers r7*)

您可以只使用r0 ,但如果您的調用層次結構變得更復雜,許多函數可能會將 args 放在 r0,r1,r2,r3 中,然后您需要對它們進行洗牌。 這就是通常使用r7原因。


為什么svc_number等於 248 而我期待的是 1

看起來您認為它已被放入堆棧中,但事實並非如此。 值 248 只是堆棧中的隨機值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM