加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專(zhuān)業(yè)用戶(hù)
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

淺析Cortex-M系統(tǒng)堆棧機(jī)制

2020/02/10
298
閱讀需 6 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

今天給大家分享的這篇依舊是 2016 年之前痞子衡寫(xiě)的技術(shù)文檔,花了點(diǎn)時(shí)間重新編排了一下格式。前面痞子衡講過(guò) 《嵌入式里的堆棧原理》,本篇算是堆棧原理的工程實(shí)踐,更具體點(diǎn)說(shuō)是在 ARM Cortex-M 上的應(yīng)用。ARM Cortex-M 家族發(fā)展至今已經(jīng)很多代,我們且以最簡(jiǎn)單的 Cortex-M0 為例來(lái)講述堆棧機(jī)制:

1. 基本規(guī)則

1.1 R13 / sp 寄存器

R0-R12 為通用寄存器,R13 為系統(tǒng)堆棧指針 sp,堆棧指針是用于訪問(wèn)堆棧,也即系統(tǒng)的 RAM 區(qū)。Cortex-M0 中采用了兩個(gè)堆棧指針:主堆棧指針(MSP)和進(jìn)程堆棧指針(PSP),R13 在任何時(shí)刻只能是其中一個(gè),默認(rèn)情況為 MSP,可以通過(guò)控制寄存器(CONTORL)來(lái)改變。

 

 

MSP 是系統(tǒng)復(fù)位后(即其處于 Handler Mode)的指定 sp(vector table 的前 4Byte 自動(dòng)載入),用于處理異常中斷。當(dāng)結(jié)束 Reset_Handler 后,cpu 進(jìn)入正常運(yùn)行狀態(tài)(即其處于 Thread Mode),僅在此狀態(tài)下 PSP 才能被使用,當(dāng)然 MSP 也可以使用。其后如有硬中斷來(lái)臨,則進(jìn)入 Handler Mode,如果硬件中斷結(jié)束,則返回 Thread Mode。

  

關(guān)于 MSP 和 PSP 的選用,其是通過(guò) CONTORL 寄存器來(lái)配置,僅在 Thread Mode 下才可設(shè)置 CONTORL 寄存器。一般情況下,沒(méi)有必要使用 PSP,除非是有 os 存在時(shí),MSP 用于 os 內(nèi)核的 sp,而 PSP 用于 thread 級(jí) app 的 sp,這兩個(gè) sp 需嚴(yán)格分開(kāi)。
  

編譯器中,可以通過(guò) r13(R13)或 sp(SP)來(lái)訪問(wèn)堆棧(具體是 MSP 和 PSP 由當(dāng)時(shí)環(huán)境決定);也可以通過(guò)指定的 MRS、MSR 指令來(lái)訪問(wèn) MSP 和 PSP。

1.2 棧結(jié)構(gòu)

無(wú) OS 的堆棧結(jié)構(gòu):

  

有 OS 的堆棧結(jié)構(gòu):

1.3 棧操作

Cortex-M0 中堆棧方向是向低地址方向增長(zhǎng),為滿(mǎn)堆棧機(jī)制。堆棧操作是通過(guò) PUSH 和 POP 來(lái)完成操作的。

  

棧一般放在 ARM 的 RAM 高位區(qū),如某 MCU 中 RAM 地址為 0x20000000-0x20007fff,共 32KByte。棧大小設(shè)為 4KByte 的話,其地址一般就放在 0x20007000-0x20007fff,其中 0x20007000 為絕對(duì)棧頂,0x20007ffc 為絕對(duì)棧底,sp 總是指向相對(duì)棧頂。第一個(gè) PUSH 數(shù)據(jù)被存在絕對(duì)棧底(此時(shí)絕對(duì)棧底也是相對(duì)棧頂)。實(shí)際上,除了 POP 指令可以從棧頂中取數(shù)據(jù)外;MOV 指令也可從任意位置取數(shù)據(jù),但不會(huì)影響棧結(jié)構(gòu)(即不影響其 sp)。
  

由于 ARM 寄存器均是 32bit,故 PUSH 和 POP 指令均是 32bit 訪問(wèn),故 sp 指針總是至少 4Byte 對(duì)齊(低 2bit 永遠(yuǎn)為 0)。有時(shí)編譯器也會(huì)分配 8Byte 對(duì)齊的棧,這是由于 double 浮點(diǎn)類(lèi)型需要占用 8Byte,為了處理方便,故將棧設(shè)為 8Byte 對(duì)齊。

2. 入棧順序

入棧順序因編譯器、處理器系統(tǒng)、OS 而異,C 語(yǔ)言中并沒(méi)有強(qiáng)制規(guī)定入棧順序,此處主要是講 ARM Cortex-M 系列處理器在指定編譯器情況下的入棧順序。

2.1 一般函數(shù)調(diào)用(通用)

上圖展示了在一般函數(shù)(無(wú)參無(wú)局部變量無(wú)返回值)嵌套調(diào)用時(shí),關(guān)于 sp 的操作。在執(zhí)行 BL FunctionA 指令時(shí),LR 記錄的是 BL FunctionA 的下一條順序指令,在進(jìn)入 FunctionA 后執(zhí)行的第一條操作便是 PUSH {LR}即將下一條順序指令壓入棧中,然后才開(kāi)始執(zhí)行 FunctionA 函數(shù)體。函數(shù)體執(zhí)行結(jié)束之后,使用 POP {PC}指令將棧頂數(shù)據(jù)彈到 PC 中,即可返回繼續(xù)執(zhí)行 BL FunctionA 的下一條順序指令。

2.2 極端函數(shù)調(diào)用(平臺(tái)而異)

考慮一種極端情況來(lái)詳細(xì)講述入棧順序,即函數(shù)含有 4 個(gè)參數(shù)以上,函數(shù)體內(nèi)定義了多個(gè)局部變量,并且還有返回值。這個(gè)情況比較特殊,痞子衡專(zhuān)門(mén)在 IAR 上做過(guò)一次實(shí)驗(yàn),詳見(jiàn)今天次條推文(是個(gè)長(zhǎng)圖,看懂需要有一定匯編基礎(chǔ)):

Arm

Arm

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

碩士畢業(yè)于蘇州大學(xué)電子信息學(xué)院,目前就職于恩智浦(NXP)半導(dǎo)體MCU系統(tǒng)部門(mén),擔(dān)任嵌入式系統(tǒng)應(yīng)用工程師。痞子衡會(huì)定期分享嵌入式相關(guān)文章