[英]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.