【方輝專欄】ARM嵌入式編譯器(七) C/C++的堆棧使用
2022-08-22
摘要: 本文主要對C/C++的堆棧使用進(jìn)行介紹。關(guān)鍵字:堆棧、堆棧的預(yù)估1. C/C++中的堆棧在C和C++都會使用到堆棧。例如:函數(shù)的返回地址。Arm 架構(gòu)的過程調(diào)用標(biāo)準(zhǔn)(AAPCS) 或Arm 64 位架構(gòu)的過程調(diào)用標(biāo)準(zhǔn)(AAPCS64) 必要的寄存器。例如,當(dāng)進(jìn)入子程序時寄存器內(nèi)容需要被保存。局部變量,包括局部數(shù)組、結(jié)構(gòu)體和聯(lián)合體。C++ 中的類。一些堆棧的使用并不明顯,例如:如果局部整數(shù)或浮點變量被溢出(即未分配給寄存器),則為它們分配堆棧內(nèi)存。結(jié)構(gòu)體通常分配給堆棧。在堆棧上保留相當(dāng)于填充多個字節(jié)的空間,其中用于AArch64 狀態(tài)或AArch32 狀態(tài)。但是,編譯器可能會嘗試將結(jié)構(gòu)體分配給寄存器。 sizeof(struct)nn168如果在編譯時知道數(shù)組的大小,則編譯器會在堆棧上分配內(nèi)存。同樣,在堆棧上保留了相當(dāng)于填充 {n} 個字節(jié)的倍數(shù)的空間,其中用于AArch64 狀態(tài)或AArch32 狀態(tài)。 sizeof(array)n1682. 估計堆棧的使用堆棧的使用量很難估計,因為它取決于代碼的編寫,并且在運行時可能會有所不同,具體取決于程序執(zhí)行時所采用的代碼路徑。但是,可以使用以下方法手動估計堆棧利用率:編譯-g并鏈接--callgraph以生成靜態(tài)調(diào)用圖。此調(diào)用圖顯示所有函數(shù)的信息,包括堆棧使用情況。鏈接或列出所有全局符號的堆棧使用情況。--info=stack--info=summarystack使用調(diào)試器在堆棧中的最后一個可用位置設(shè)置觀察點,并查看觀察點是否被命中。使用選項編譯-g以生成必要的 DWARF 信息。注: Debugging With Attributed Record Formats(DWARF)使用帶屬性的記錄格式進(jìn)行調(diào)試。利用調(diào)試器:1)為比您預(yù)期需要的大得多的堆棧分配內(nèi)存空間。2)用已知值的副本填充堆??臻g,例如0xDEADDEAD.3)運行您的應(yīng)用程序,并在測試中使用盡可能多的堆棧空間。例如,嘗試執(zhí)行最深嵌套的函數(shù)調(diào)用和靜態(tài)分析發(fā)現(xiàn)的最壞情況路徑。嘗試在適當(dāng)?shù)牡胤缴芍袛啵员銓⑺鼈儼诙褩8欀小?)應(yīng)用程序完成執(zhí)行后,檢查內(nèi)存的堆棧空間以查看有多少已知值已被覆蓋。該空間在已使用的部分中有數(shù)據(jù),在剩余部分中是已知值。5)計算有數(shù)據(jù)值的數(shù)量(以字節(jié)為單位)。sizeof(value)使用與目標(biāo)處理器或架構(gòu)相對應(yīng)的固定虛擬平臺 (FVP)。使用映射文件,在堆棧正下方定義一個禁止訪問的內(nèi)存區(qū)域。如果堆棧溢出到禁止區(qū)域,則會發(fā)生數(shù)據(jù)中止,調(diào)試器可以捕獲該異常。3. 檢查堆棧的使用檢查程序中函數(shù)使用堆棧的大小是一個良好的編程習(xí)慣。這樣可以寫出使用較小堆棧的代碼。要檢查程序中的堆棧使用情況,需要使用--info=stack這個鏈接器選項。__attribute__((noinline)) int fact(int n){??int f = 1;??while (n>0)??{????f *= n--;??}??return f;}int foo (int n){??return fact(n);}int foo_mor (int a, int b, int c, int d){?return fact(a);}int main (void){??return foo(10) + foo_mor(10,11,12,13);}將代碼示例復(fù)制到file.c并使用以下命令對其進(jìn)行編譯:armclang --target=arm-arm-none-eabi -march=armv8-a -c -g file.c -o file.o使用該選項進(jìn)行編譯會-g生成armlink估計堆棧使用所需的 DWARF 幀信息。使用以下命令在目標(biāo)文件上運行armlink:--info=stackarmlink file.o --info=stack對于示例代碼,armlink顯示了各種函數(shù)使用的堆棧數(shù)量。Function foo_mor比 function foo 有更多的參數(shù),因此使用更多的堆棧。Stack Usage for fact 0xc bytes.Stack Usage for foo 0x8 bytes.Stack Usage for foo_mor 0x10 bytes.Stack Usage for main 0x8 bytes.您還可以使用鏈接器選項檢查堆棧使用情況--callgraph:armlink file.o --callgraph -o FileImage.axf這會輸出一個名為的文件FileImage.htm,其中包含應(yīng)用程序中各種函數(shù)的堆棧使用信息。fact (ARM, 84 bytes, Stack size 12 bytes, file.o(.text))[Stack]Max Depth = 12Call Chain = fact[Called By]>> ??foo_mor>> ??foofoo (ARM, 36 bytes, Stack size 8 bytes, file.o(.text))[Stack]Max Depth = 20Call Chain = foo >> fact[Calls]>> ??fact[Called By]>> ??mainfoo_mor (ARM, 76 bytes, Stack size 16 bytes, file.o(.text))[Stack]Max Depth = 28Call Chain = foo_mor >> fact[Calls]>> ??fact[Called By]>> ??mainmain (ARM, 76 bytes, Stack size 8 bytes, file.o(.text))[Stack]Max Depth = 36Call Chain = main >> foo_mor >> fact[Calls]>> ??foo_mor>> ??foo[Called By]>> ??__rt_entry_main (via BLX)4. 減少堆棧的使用的方法減少堆棧使用量通常有以下幾個方法:1)編寫只需要幾個變量的小函數(shù)。2)避免使用較大的局部結(jié)構(gòu)體或數(shù)組3)避免遞歸調(diào)用4)函數(shù)在執(zhí)行的任何特定時候都盡可能少的使用變量。5)使用C塊作用域語法并在需要的位置聲明變量,這樣可以在不同作用域使用相同內(nèi)存。來源:《Arm? Compiler for Embedded User Guide Version 6.18》參考鏈接:DWARF 格式簡介 https://gohalo.me/post/program-c-gdb-dwarf-format-introduce.html+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++關(guān)于億道電子億道電子技術(shù)有限公司(英文名稱:Emdoor Electronics Technology Co.,Ltd)是國內(nèi)資深的研發(fā)工具軟件提供商,公司成立于 2002 年,面向中國廣大的制造業(yè)客戶提供研發(fā)、設(shè)計、管理過程中使用的各種軟件開發(fā)工具,致力于幫助客戶提高研發(fā)管理效率、縮短產(chǎn)品設(shè)計周期,提升產(chǎn)品可靠性。20 年來,先后與 Altium、ARM、Ansys、QT、Adobe、Visu-IT、Minitab、Testplant、EPLAN、HighTec、GreenHills、PLS、Ashling、MSC Software 、Autodesk、Source Insight、TeamEDA、MicroFocus等多家全球知名公司建立戰(zhàn)略合作伙伴關(guān)系,并作為他們在中國區(qū)的主要分銷合作伙伴服務(wù)了數(shù)千家中國本土客戶,為客戶提供從芯片級開發(fā)工具、EDA 設(shè)計工具、軟件編譯以及測試工具、結(jié)構(gòu)設(shè)計工具、仿真工具、電氣設(shè)計工具、以及嵌入式 GUI 工具等等。億道電子憑借多年的經(jīng)驗積累,真正的幫助客戶實現(xiàn)了讓研發(fā)更簡單、更可靠、更高效的目標(biāo)。歡迎關(guān)注“億道電子”公眾號了解更多研發(fā)工具軟件知識
查看更多→