精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

在堆嵌入式單片機(jī)編程中為什么大多時(shí)候要保證堆棧8字節(jié)對(duì)齊呢?

STM32嵌入式開(kāi)發(fā) ? 來(lái)源:CSDN ? 2023-08-28 10:48 ? 次閱讀

本文主要介紹了嵌入式單片機(jī)編程中,為什么大多時(shí)候要保證堆棧8字節(jié)對(duì)齊的問(wèn)題。

字節(jié)對(duì)齊原則

1. 結(jié)構(gòu)(struct)(或聯(lián)合(union)) 中的第一個(gè)數(shù)據(jù)成員放在 offset 為 0 的地方,以后每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置,要從該成員大小或者成員的子成員大?。ㄖ灰摮蓡T有子成員,比如說(shuō)是數(shù)組,結(jié)構(gòu)體等)的整數(shù)倍開(kāi)始(比如 int 型變量在 32 位編譯環(huán)境下為 4 字節(jié),則要從 4 的整數(shù)倍地址開(kāi)始存儲(chǔ));

2. 如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開(kāi)始存儲(chǔ).

如:struct a 里存有 struct b, b 里有 char, int , double 等元素,那 b 應(yīng)該從 8 的整數(shù)倍開(kāi)始存儲(chǔ).;

3. 結(jié)構(gòu)體的總大小,也就是 sizeof 的結(jié)果,必須是其內(nèi)部最大成員的整數(shù)倍,不足的要補(bǔ)齊;

dd396a9e-433e-11ee-a2ef-92fbcf53809c.png

總大小為最大成員變量大小的整數(shù)倍,sizeof(AA) = 24;sizeof(BB) = 32。

#pragma pack():

在代碼前加一句 #pragma pack(1),會(huì)發(fā)現(xiàn) sizeof(AA) = 17;sizeof(BB) = 24;

AA 是 8+4+1+4=17;

BB 是 5+4+8+4+2+1=24;

這就是理想中的沒(méi)有內(nèi)存對(duì)齊的情況,所以 #pragma pack(1) 是告訴編譯器,所有的對(duì)齊都按照1的整數(shù)倍對(duì)齊,換句話說(shuō)就是沒(méi)有對(duì)齊規(guī)則。

即#pragma pack(n)就是所有的對(duì)齊都按照n的整數(shù)倍對(duì)齊。

Vc,Vs等編譯器默認(rèn)是 #pragma pack(8),所以測(cè)試我們的規(guī)則會(huì)正常;

gcc 默認(rèn)是 #pragma pack(4),并且 gcc 只支持 1, 2, 4 對(duì)齊。套用三原則里計(jì)算的對(duì)齊值是不能大于 #pragma pack 指定的n值。

為什么要保證堆棧8字節(jié)對(duì)齊

AAPCS 規(guī)則要求堆棧保持 8 字節(jié)對(duì)齊。如果不對(duì)齊,調(diào)用一般的函數(shù)也是沒(méi)問(wèn)題的。但是當(dāng)調(diào)用需要嚴(yán)格遵守 AAPCS 規(guī)則的函數(shù)時(shí)可能會(huì)出錯(cuò)。

例如調(diào)用 sprintf 輸出一個(gè)浮點(diǎn)數(shù)時(shí),棧必須是 8 字節(jié)對(duì)齊的,否則結(jié)果可能會(huì)出錯(cuò)。

實(shí)驗(yàn)驗(yàn)證:

dd545f52-433e-11ee-a2ef-92fbcf53809c.png


1.在 A 處設(shè)置斷點(diǎn),讓程序全速運(yùn)行至 A

2.在 MDK 中修改 MSP 的值使 MSP 滿足 8 字節(jié)對(duì)齊

3.全速運(yùn)行程序,觀察 buf 中的字符為 1.234 結(jié)果正確

4.回到第 2 步,修改 MSP 使之只滿足 4 字節(jié)對(duì)齊而不滿足 8 字節(jié)對(duì)齊

5.全速運(yùn)行程序,觀察 buf 中的字符為 -2.000 結(jié)果錯(cuò)誤

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

編譯器為我們做了什么

先看一個(gè)實(shí)驗(yàn):

dd672d62-433e-11ee-a2ef-92fbcf53809c.png


保證初始的時(shí)候堆棧是 8 字節(jié)對(duì)齊的;

1.在 A 處設(shè)置斷點(diǎn);

2.全速運(yùn)行至 A,觀察 MSP=0x2000025c,沒(méi)有 8 字節(jié)對(duì)齊;

3.略微修改一下 main 函數(shù)代碼如下,其他部分代碼不變;

dd810d90-433e-11ee-a2ef-92fbcf53809c.png


4.同樣在 A 處設(shè)置斷點(diǎn);

5.全速運(yùn)行至 A,觀察 MSP=0x200002d8,這次 8 字節(jié)對(duì)齊了; 這個(gè)實(shí)驗(yàn)說(shuō)明了如果編譯器發(fā)現(xiàn)了某個(gè)函數(shù)需要調(diào)用浮點(diǎn)庫(kù)時(shí)會(huì)自動(dòng)調(diào)整編譯生成的匯編代碼,從而保證調(diào)用這些浮點(diǎn)庫(kù)函數(shù)時(shí)堆棧是8字節(jié)對(duì)齊的。

換句話說(shuō)如果我們保證了棧初始的時(shí)候是8字節(jié)對(duì)齊的,那么編譯器可以保證以后調(diào)用浮點(diǎn)庫(kù)時(shí)堆棧仍是8字節(jié)對(duì)齊的。

os下應(yīng)該怎樣設(shè)置任務(wù)堆棧

由上面的討論可知給任務(wù)分配棧時(shí)需要保證棧是 8 字節(jié)對(duì)齊的,不然在該任務(wù)中凡是調(diào)用 sprintf 的函數(shù)均會(huì)出錯(cuò),因?yàn)闂R婚_(kāi)始就是不對(duì)齊的。

是否保證了棧初始是8字節(jié)對(duì)齊了就萬(wàn)事大吉了呢。no!大家請(qǐng)看一種特殊的情況:

dd92f834-433e-11ee-a2ef-92fbcf53809c.png

mian函數(shù)的反匯編如下:

ddad50d0-433e-11ee-a2ef-92fbcf53809c.png



保證初始的時(shí)候堆棧是 8 字節(jié)對(duì)齊的;

1.在 A 處設(shè)置斷點(diǎn);

2.全速運(yùn)行至 A,觀察此時(shí) MSP=0x200002e4 未對(duì)齊;

3.在 MDK 中將 SVC 的掛起位置 1;

4.在 B 處設(shè)置斷點(diǎn);

5.全速運(yùn)行至 B,觀察此時(shí) MSP=0x200002b4 未對(duì)齊;

6.繼續(xù)全速執(zhí)行,觀察 buf 中的字符為: -2.000 出錯(cuò)了;

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

Cortex-M3 內(nèi)核為我們做了什么

Cortex-M3 內(nèi)核提供了一種硬件機(jī)制來(lái)解決上述這種中斷中棧不對(duì)齊問(wèn)題。

CM3 中可以把 NVIC 配置控制寄存器的 STKALIGN 置位,來(lái)保證中斷中的棧 8 字節(jié)對(duì)齊。

具體實(shí)現(xiàn)過(guò)程如下:當(dāng)發(fā)生中斷時(shí)由硬件自動(dòng)檢測(cè) MSP 是否 8 字節(jié)對(duì)齊,如果對(duì)齊了,則不進(jìn)行任何操作,如果沒(méi)有對(duì)齊,則自動(dòng)將 MSP 減 4 這樣便對(duì)齊了,同時(shí)將 xPSR 的第 9 位置位來(lái)記錄這個(gè) MSP 的非正常的變化,在中斷返回若發(fā)現(xiàn) xPSR 的第 9 位是置位的則自動(dòng)將 MSP 加 4 調(diào)整回原來(lái)的值。

實(shí)驗(yàn)驗(yàn)證:

ddc6380c-433e-11ee-a2ef-92fbcf53809c.png



mian函數(shù)的反匯編如下:

ddda4aea-433e-11ee-a2ef-92fbcf53809c.png



1.在 A 處設(shè)置斷點(diǎn);

2.全速運(yùn)行至 A,觀察此時(shí) MSP=0x200002e4 未對(duì)齊;

3.在 MDK 中將 SVC 的掛起位置 1,同時(shí)將 0xE000ED14 處的值由 0x00000000 改為 0x00000200(即將 NVIC 配置控制寄存器的 STKALIGN 置位)

4.在 B 處設(shè)置斷點(diǎn);

5.全速運(yùn)行至 B,觀察此時(shí) MSP=0x200002b0 對(duì)齊了;

6.觀察中斷返回時(shí)的 MSP=0x200002e4 調(diào)整回來(lái)了;

7.繼續(xù)全速執(zhí)行,觀察 buf 中的字符為:1.234 正確;

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

總結(jié)

綜上所述,為了能夠安全的使用嚴(yán)格遵守AAPCS規(guī)則的函數(shù)(比如sprintf)需要做到以下幾點(diǎn):

保證MSP在初始的時(shí)候是8字節(jié)對(duì)齊的

如果用到OS的話,需要保證給每個(gè)任務(wù)分配的棧是保持8字節(jié)對(duì)齊的

如果用的是基于CM3內(nèi)核的處理器,需將NVIC配置控制寄存器的STKALIGN置位。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    19165

    瀏覽量

    229146
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5317

    瀏覽量

    120013
  • 存儲(chǔ)器
    +關(guān)注

    關(guān)注

    38

    文章

    7452

    瀏覽量

    163608
  • SVC控制器
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    5224
  • 嵌入式單片機(jī)
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    2260

原文標(biāo)題:對(duì)堆棧 8 字節(jié)對(duì)齊問(wèn)題的討論

文章出處:【微信號(hào):c-stm32,微信公眾號(hào):STM32嵌入式開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    AAPCS規(guī)則要求堆棧保持8字節(jié)對(duì)齊(轉(zhuǎn))

    我們保證了棧初始的時(shí)候8字節(jié)對(duì)齊的,那么編譯器可以保證以后調(diào)用浮點(diǎn)庫(kù)時(shí)
    發(fā)表于 01-19 11:43

    請(qǐng)問(wèn)F28335字節(jié)對(duì)齊能不能改為1字節(jié)?

    大家好,C2000成員TMS320F28335CCS3.3下是2字節(jié)對(duì)齊的,能不能改為1字節(jié)對(duì)齊?怎么改
    發(fā)表于 08-20 06:41

    align為什么8字節(jié)對(duì)齊?

    我知道數(shù)據(jù)儲(chǔ)存的起始地址%對(duì)齊字節(jié)(N)=0才行,但是我不明白有兩點(diǎn)問(wèn)題1:UCOSIII的系統(tǒng)的浮點(diǎn)數(shù)打印任務(wù)的堆棧大小
    發(fā)表于 04-23 00:21

    請(qǐng)問(wèn)嵌入式單片機(jī)之間的關(guān)系是什么?

    時(shí)間回到十五年前,大部分人搞嵌入式,其實(shí)是做單片機(jī),那時(shí)單片機(jī)資源少(我曾用過(guò)128字節(jié)RAM的MCU,仔細(xì)扣每一
    發(fā)表于 06-24 14:35

    詳解STM32單片機(jī)堆棧

    學(xué)習(xí)STM32單片機(jī)時(shí)候,總是能遇到“堆棧”這個(gè)概念。分享本文,希望對(duì)你理解堆棧有幫助。 對(duì)于了解一點(diǎn)匯編編程的人,就可以知道,
    發(fā)表于 01-12 11:30

    【原創(chuàng)】嵌入式系統(tǒng)中大小端和對(duì)齊問(wèn)題

    作者:黃忠老師(張飛實(shí)戰(zhàn)電子高級(jí)工程師)C語(yǔ)言是一種高級(jí)語(yǔ)言,大多數(shù)情況下C語(yǔ)言的代碼是和具體的處理器體系結(jié)構(gòu)無(wú)關(guān)的。然而,嵌入式系統(tǒng)的編程
    發(fā)表于 07-30 09:34

    8單片機(jī)全速USB集成128 k字節(jié)Flash ROM和8192字節(jié)的RAM

    LC87F17C8A是一個(gè)8單片機(jī)和USB全速主機(jī)/設(shè)備控制器。128 k字節(jié)閃速存儲(chǔ)器/ 8192字節(jié)的RAM / 48-pin。
    發(fā)表于 04-06 09:15 ?3次下載
    <b class='flag-5'>8</b>位<b class='flag-5'>單片機(jī)</b>全速USB集成128 k<b class='flag-5'>字節(jié)</b>Flash ROM和8192<b class='flag-5'>字節(jié)</b>的RAM

    什么是嵌入式單片機(jī)?嵌入式單片機(jī)詳情匯總

    嵌入式單片機(jī),即嵌入式微控制器,指以微控制器為核心控制單元的嵌入到對(duì)象體系的專用計(jì)算機(jī)系統(tǒng),是應(yīng)用十分廣泛的一種
    發(fā)表于 11-13 09:39 ?6065次閱讀

    什么是嵌入式編程

    什么是嵌入式編程?對(duì)于嵌入式系統(tǒng),許多人很容易將它與單片機(jī)編程混淆。其實(shí),嵌入式
    發(fā)表于 06-29 11:05 ?1.1w次閱讀
    什么是<b class='flag-5'>嵌入式</b><b class='flag-5'>編程</b>

    單片機(jī)or嵌入式linux

    最近很多童鞋投票并咨詢?nèi)绾螐?b class='flag-5'>單片機(jī)轉(zhuǎn)做嵌入式Linux開(kāi)發(fā)。看來(lái)讀者圈單片機(jī),RTOS的不少。盡管我目前從事Linux/Android方面的嵌入
    發(fā)表于 11-01 16:26 ?17次下載
    <b class='flag-5'>單片機(jī)</b>or<b class='flag-5'>嵌入式</b>linux

    單片機(jī)到底是不是嵌入式

    01 問(wèn)題很多同學(xué)一直糾結(jié):我是學(xué)單片機(jī)還是學(xué)嵌入式?還有人說(shuō)單片機(jī)也是
    發(fā)表于 11-04 11:21 ?14次下載
    <b class='flag-5'>單片機(jī)</b>到底是不是<b class='flag-5'>嵌入式</b>?

    是否要從單片機(jī)轉(zhuǎn)為嵌入式Linux

    最近很多童鞋投票并咨詢?nèi)绾螐?b class='flag-5'>單片機(jī)轉(zhuǎn)為嵌入式Linux開(kāi)發(fā)??磥?lái)讀者圈單片機(jī),RTOS的不少。盡管小編目前從事Linux/Android方面的
    發(fā)表于 11-13 20:51 ?11次下載
    是否要從<b class='flag-5'>單片機(jī)</b>轉(zhuǎn)為<b class='flag-5'>嵌入式</b>Linux

    基于51單片機(jī)設(shè)計(jì)N字節(jié)十六進(jìn)制除法——以6字節(jié)除以3字節(jié)為例

    基于51單片機(jī)設(shè)計(jì)N字節(jié)十六進(jìn)制除法——以6字節(jié)除以3字節(jié)為例1、思路借用十進(jìn)制除法豎計(jì)算的思路,作十六進(jìn)制的除法豎
    發(fā)表于 11-23 16:51 ?7次下載
    基于51<b class='flag-5'>單片機(jī)</b>設(shè)計(jì)N<b class='flag-5'>字節(jié)</b>十六進(jìn)制除法——以6<b class='flag-5'>字節(jié)</b>除以3<b class='flag-5'>字節(jié)</b>為例

    STM32 終極字節(jié)對(duì)齊解析

    一、全局變量對(duì)齊問(wèn)題:基本上用戶定義的變量是幾個(gè)字節(jié)就是幾字節(jié)對(duì)齊,這個(gè)比較好理解。uint8_t定義變量地址
    發(fā)表于 11-23 18:06 ?11次下載
    STM32 終極<b class='flag-5'>字節(jié)</b><b class='flag-5'>對(duì)齊</b>解析

    【M3內(nèi)核篇】關(guān)于“堆棧指針的最低兩位永遠(yuǎn)是0,這意味著堆棧總是4字節(jié)對(duì)齊的”的理解

    堆棧指針的最低兩位永遠(yuǎn)是0,這意味著堆棧總是4字節(jié)對(duì)齊的”理解在看到《Cortex-M3權(quán)威指南》堆棧指針的這句話剛開(kāi)始一直摸不著頭腦,通
    發(fā)表于 12-01 14:36 ?11次下載
    【M3內(nèi)核篇】關(guān)于“<b class='flag-5'>堆棧</b>指針的最低兩位永遠(yuǎn)是0,這意味著<b class='flag-5'>堆棧</b>總是4<b class='flag-5'>字節(jié)</b><b class='flag-5'>對(duì)齊</b>的”的理解