日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]一.為什么要保證堆棧8字節(jié)對齊AAPCS規(guī)則要求堆棧保持8字節(jié)對齊。如果不對齊,調(diào)用一般的函數(shù)也是沒問題的。但是當(dāng)調(diào)用需要嚴(yán)格遵守AAPCS規(guī)則的函數(shù)時可能會出錯。例如調(diào)用sprintf輸出一個浮點(diǎn)數(shù)時,棧必須是8字節(jié)對齊

一.為什么要保證堆棧8字節(jié)對齊
AAPCS規(guī)則要求堆棧保持8字節(jié)對齊。如果不對齊,調(diào)用一般的函數(shù)也是沒問題的。但是當(dāng)調(diào)用需要嚴(yán)格遵守AAPCS規(guī)則的函數(shù)時可能會出錯。
例如調(diào)用sprintf輸出一個浮點(diǎn)數(shù)時,棧必須是8字節(jié)對齊的,否則結(jié)果可能會出錯。

實(shí)驗(yàn)驗(yàn)證:
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];
int main(void)
{
sprintf(buf,"%.3fnr",fff);//A
while(1);
}

1.在A處設(shè)置斷點(diǎn),讓程序全速運(yùn)行至A
2.在MDK中修改MSP的值使MSP滿足8字節(jié)對齊
3.全速運(yùn)行程序,觀察buf中的字符為 1.234 結(jié)果正確
4.回到第2步,修改MSP使之只滿足4字節(jié)對齊而不滿足8字節(jié)對齊
5.全速運(yùn)行程序,觀察buf中的字符為 -2.000 結(jié)果錯誤

該實(shí)驗(yàn)證明了調(diào)用sprintf輸出一個浮點(diǎn)數(shù)必須要保證棧8字節(jié)對齊。


二.編譯器為我們做了什么
先看一個實(shí)驗(yàn)
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];

void fun(int a,int b,int c,int d)
{
int v;
v=v;
}
void test(void)
{}

int main(void)
{
fun(1,2,3,4);
test();//A
//sprintf(buf,"%.3fnr",fff);
while(1);
}

0.保證初始的時候堆棧是8字節(jié)對齊的
1.在A處設(shè)置斷點(diǎn)
2.全速運(yùn)行至A,觀察MSP=0x2000025c,沒有8字節(jié)對齊
3.略微修改一下main函數(shù)代碼如下,其他部分代碼不變

int main(void)
{
fun(1,2,3,4);
//test();
sprintf(buf,"%.3fnr",fff);//A
while(1);
}

4.同樣在A處設(shè)置斷點(diǎn)
5.全速運(yùn)行至A,觀察MSP=0x200002d8,這次8字節(jié)對齊了

這個實(shí)驗(yàn)說明了如果編譯器發(fā)現(xiàn)了某個函數(shù)需要調(diào)用浮點(diǎn)庫時會自動調(diào)整編譯生成的匯編
代碼,從而保證調(diào)用這些浮點(diǎn)庫函數(shù)時堆棧是8字節(jié)對齊的。換句話說如果我們保證了棧
初始的時候是8字節(jié)對齊的,那么編譯器可以保證以后調(diào)用浮點(diǎn)庫時堆棧仍是8字節(jié)對齊的。

三.os下應(yīng)該怎樣設(shè)置任務(wù)堆棧
由上面的討論可知給任務(wù)分配棧時需要保證棧是8字節(jié)對齊的,不然在該任務(wù)中凡是調(diào)用sprintf的函數(shù)
均會出錯,因?yàn)闂R婚_始就是不對齊的。

四.中斷中的棧對齊問題
是否保證了棧初始是8字節(jié)對齊了就萬事大吉了呢。no!大家請看一種特殊的情況:
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];
void fun(int a,int b,int c,int d)
{
int v;
v=v;
}
int main(void)
{
fun(1,2,3,4);
while(1);
}
void SVC_Handler(void)
{
sprintf(buf,"%.3fnr",fff);//B
}
mian函數(shù)的反匯編如下:
0x080001DC B500 PUSH {lr}
0x080001DE 2304 MOVS r3,#0x04 ;A
0x080001E0 2203 MOVS r2,#0x03
0x080001E2 2102 MOVS r1,#0x02
0x080001E4 2001 MOVS r0,#0x01
0x080001E6 F7FFFFF5 BL.W fun (0x080001D4)
0x080001EA BF00 NOP
0x080001EC E7FE B 0x080001EC

0.保證初始的時候堆棧是8字節(jié)對齊的
1.在A處設(shè)置斷點(diǎn)
2.全速運(yùn)行至A,觀察此時MSP=0x200002e4 未對齊
3.在MDK中將SVC的掛起位置1
4.在B處設(shè)置斷點(diǎn)
5.全速運(yùn)行至B,觀察此時MSP=0x200002b4 未對齊
6.繼續(xù)全速執(zhí)行,觀察buf中的字符為:-2.000 出錯了

這個實(shí)驗(yàn)說明了即使保證棧初始是8字節(jié)對齊的,編譯器也只能保證在調(diào)用sprintf那個時刻棧是8字節(jié)對齊的
但不能保證任意時刻棧都是8字節(jié)對齊的,如果恰巧在MSP沒有8字節(jié)對齊的時刻發(fā)生了中斷,而中斷中又調(diào)用
了sprintf,這種情況下仍會出錯

五.Cortex-M3內(nèi)核為我們做了什么
Cortex-M3內(nèi)核提供了一種硬件機(jī)制來解決上述這種中斷中棧不對齊問題。
CM3中可以把NVIC配置控制寄存器的STKALIGN置位,來保證中斷中的棧8字節(jié)對齊,
具體實(shí)現(xiàn)過程如下:
當(dāng)發(fā)生中斷時由硬件自動檢測MSP是否8字節(jié)對齊,如果對齊了,則不進(jìn)行任何操作,
如果沒有對齊,則自動將MSP減4這樣便對齊了,同時將xPSR的第9位置位來記錄這個
MSP的非正常的變化,在中斷返回若發(fā)現(xiàn)xPSR的第9位是置位的則自動將MSP加4調(diào)整
回原來的值。

實(shí)驗(yàn)驗(yàn)證:
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];
void fun(int a,int b,int c,int d)
{
int v;
v=v;
}
int main(void)
{
fun(1,2,3,4);
while(1);
}
void SVC_Handler(void)
{
sprintf(buf,"%.3fnr",fff);//B
}
mian函數(shù)的反匯編如下:
0x080001DC B500 PUSH {lr}
0x080001DE 2304 MOVS r3,#0x04 ;A
0x080001E0 2203 MOVS r2,#0x03
0x080001E2 2102 MOVS r1,#0x02
0x080001E4 2001 MOVS r0,#0x01
0x080001E6 F7FFFFF5 BL.W fun (0x080001D4)
0x080001EA BF00 NOP
0x080001EC E7FE B 0x080001EC

1.在A處設(shè)置斷點(diǎn)
2.全速運(yùn)行至A,觀察此時MSP=0x200002e4 未對齊
3.在MDK中將SVC的掛起位置1,同時將0xE000ED14處的值由0x00000000改為0x00000200
(即將NVIC配置控制寄存器的STKALIGN置位)
4.在B處設(shè)置斷點(diǎn)
5.全速運(yùn)行至B,觀察此時MSP=0x200002b0 對齊了
6.觀察中斷返回時的MSP=0x200002e4 調(diào)整回來了
7.繼續(xù)全速執(zhí)行,觀察buf中的字符為:1.234 正確

這個實(shí)驗(yàn)說明了將NVIC配置控制寄存器的STKALIGN置位可以保護(hù)中斷時棧仍是8字節(jié)對齊


六.總結(jié)
綜上所述,為了能夠安全的使用嚴(yán)格遵守AAPCS規(guī)則的函數(shù)(比如sprintf)需要做到以下幾點(diǎn):
1.保證MSP在初始的時候是8字節(jié)對齊的
2.如果用到OS的話需要保證給每個任務(wù)分配的棧是保持8字節(jié)對齊的
3.如果用的是基于CM3內(nèi)核的處理器需將NVIC配置控制寄存器的STKALIGN置位

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

數(shù)據(jù)結(jié)構(gòu)是抽象的概念,沒有語言之別,就像是設(shè)計(jì)模式一樣,是一種抽象的思想,用任何語言的代碼都能構(gòu)建出來。而我們的python中的字符串,列表,字典,元祖,集合都是基本數(shù)據(jù)類型,他們是依附于語言存在的,不同的語言有不同的基...

關(guān)鍵字: 數(shù)組 堆棧

堆棧和隊(duì)列在數(shù)據(jù)結(jié)構(gòu)中是最基礎(chǔ),但同時也是最重要的概念,很多小伙伴對兩者不是很了解,本文就言簡意賅的帶大家了解一下堆棧和隊(duì)列。

關(guān)鍵字: 堆棧 隊(duì)列

隨著嵌入式計(jì)算設(shè)備基礎(chǔ)硬件性能的提升,在通信、工業(yè)制造、交通運(yùn)輸?shù)阮I(lǐng)域,嵌入式系統(tǒng)逐漸承擔(dān)起更加綜合化和關(guān)鍵的任務(wù),這也導(dǎo)致嵌入式軟件在結(jié)構(gòu)愈加復(fù)雜的同時,其安全性問題也越來越受到重視。堆棧是嵌入式軟件中的重要存儲結(jié)構(gòu),...

關(guān)鍵字: 嵌入式軟件 堆棧

這些軟件可作為開源和雙重許可提供,并附有大量文檔

關(guān)鍵字: 軟件 堆棧 微控制器

隨著越來越多的嵌入式產(chǎn)品連接到外部網(wǎng)絡(luò),嵌入式產(chǎn)品的信息安全性(Security)越來越多地被人們關(guān)注。其中既包括直接連接到外部網(wǎng)絡(luò),比如通過Wi-Fi連接;也包括間接連接到外部網(wǎng)絡(luò),比如汽車中的ECU通過CAN總線與T...

關(guān)鍵字: IAR Systems 堆棧 嵌入式

運(yùn)算密度跟不上因特網(wǎng)流量增加速度,數(shù)據(jù)中心分析之?dāng)?shù)據(jù)量的成長速度前所未有;要解決這個問題,需要更大的內(nèi)存帶寬,而這是3D芯片堆棧技術(shù)展現(xiàn)其承諾的一個領(lǐng)域。

關(guān)鍵字: 堆棧 3D芯片 處理器

用C語言進(jìn)行MCS51系列單片機(jī)程序設(shè)計(jì)是單片機(jī)開發(fā)和應(yīng)用的必然趨勢。Keil公司的C51編譯器支持經(jīng)典8051和8051派生產(chǎn)品的版本,通稱為Cx51。應(yīng)該說,Cx51是C語言在MCS51單片機(jī)上的擴(kuò)展,既有C語言的共...

關(guān)鍵字: MCS51 單片機(jī) 堆棧

堆??臻g分配 這部分很重要,如果選擇的單片機(jī)RAM比較吃緊,那就要精打細(xì)算了。

關(guān)鍵字: 堆棧 單片機(jī) RAM

堆棧對于程序來說非常重要,程序能夠快速運(yùn)行,堆棧起到非常大的作用,但你了解堆棧嗎?

關(guān)鍵字: 堆棧 嵌入式
關(guān)閉