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

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

ARMv7-A那些事-?;厮轀\析

嵌入式那些事 ? 來源:嵌入式那些事 ? 2023-11-21 15:51 ? 次閱讀

嵌入式開發過程中,經常需要對代碼進行調試來解決各種各樣的問題,常用的調試手段有:

(1)、開發環境搭配硬件仿真器進行在線調試。優點:調試過程中能夠清楚的知道各個寄存器的值以及各個變量的值,程序的執行流程也能夠一目了然。缺點:板卡需要引出硬件仿真器的連接口,并且需要購買硬件仿真器。

(2)、通過調試串口打印信息梳理程序的執行流程,結合代碼分析問題產生的原因。優點:足夠簡單,通過增加較多的打印信息來分析問題出現的位置,再結合代碼分析問題產生的原因。缺點:沒法準確的定位問題產生的位置和原因。

(3)、在應用或者操作系統死機的時候,根據操作系統輸出的異常棧信息進行分析,再結合鏡像或者應用的反匯編代碼進行定位。通常這種方法和方法(2)結合使用。

本文主要簡單的講講?;厮荩瑢τ谝院笕ダ斫獠僮飨到y的異常棧處理打個基礎吧。

ARM處理器的?;厮葜饕袃煞N方式:一種是基于棧幀寄存器(FP)的棧回溯,另一種是unwind形式的?;厮?。本文主要講講基于棧幀寄存器(FP)的棧回溯。

棧回溯相關寄存器

在?;厮葸^程中,主要涉及如下寄存器:

R15:又叫程序計數器(Program Counter)PC,PC主要用于存放CPU取指的地址。

R14:又叫鏈接寄存器(Link register)LR,LR主要用于存放函數的返回地址,即當函數返回時,知道自己該回到哪兒去繼續運行。

R13:又叫堆棧指針寄存器(Stack pointer)SP,SP通常用于保存堆棧地址,在使用入棧和出棧指令時,SP中的堆棧地址會自動的更新。

R12:又叫內部過程調用暫存寄存器(Intra-Procedure-call scratch register)IP,主要用于暫存SP。

R11:又叫幀指針寄存器(Frame pointer)FP,通常指向一個函數的棧幀底部,表示一個函數棧的開始位置。

ARM棧幀結構

依據AAPCS (ARM Archtecture Procedure Call Standard)規范,當調用子函數時,子函數一開始的代碼總是會執行壓棧操作來保留父函數的相關信息,壓棧步驟示例如下所示:

movip,sp
push{fp,ip,lr,pc}
subfp,ip,#4
subsp,sp,#16
...

每個函數都有自己的??臻g,這一部分稱為棧幀。棧幀在函數被調用的時候創建,在函數返回后銷毀。每個函數的棧幀是由SP寄存器和FP寄存器來界定的,ARM棧幀結構典型示意圖如下所示:

6422d2b4-8842-11ee-939d-92fbcf53809c.png

ARMv7-A架構-ARM棧幀結構

上圖描述的棧幀,main函數和func1函數的示意代碼如下:

intfunc1(intp1,intp2,intp3,intp4,intp5)
{
inti;
intj;

i=0xf3;
j=0xf6;

return0;
}

intmain(intargc,char*argv[])
{
inti;
intj;

i=0x33;
j=0x66;
func1(0xa1,0xa2,0xa3,0xa4,0xa5);

return0;
}

每個函數的棧幀中都會保存調用該函數之前的PC、LR、SP、FP寄存器的值;如果函數具有參數并且函數內部使用了局部變量,那么函數棧幀中也會保存函數的參數和局部變量;如果被調用的子函數參數過多,那么多余的參數會通過父函數的棧進行傳遞。比如func1函數的參數p5通過main函數的棧幀進行傳遞的。(注:編譯器的版本不同,函數棧幀中參數和局部變量的壓棧順序可能不同,PC,LR,SP和FP這4個寄存器的壓棧順序一般是固定的)

函數棧幀中的PC和LR均指向代碼段,PC表示執行入棧指令時CPU正在取指的地址,LR表示當前函數返回后繼續執行的地址。

棧回溯原理

在?;厮莸倪^程中,我們主要利用FP寄存器進行?;厮荨Mㄟ^FP就可以知道當前函數的棧底,從而可以找到存儲在棧幀中的LR寄存器的數據,這個數據就是函數的返回地址。同時也可以找到保存在函數棧幀中的上一級函數FP的數據,這個數據指向了上一級函數的棧底,按照同樣的方法可以找出上一級函數棧幀中存儲的LR和FP數據,就知道哪個函數調用了上一級函數以及這個函數的棧底地址。這就是棧回溯的流程,整個流程以FP為核心,依次找出每個函數棧幀中存儲的LR和FP數據,計算出函數返回地址和上一級函數棧底地址,從而找出每一級函數調用關系。

?;厮菥幾g選項

當gcc的編譯選項帶有-mapcs-frame時,編譯出來的代碼能夠將PC,LR,SP和FP寄存器的值壓入函數的棧幀中。默認情況下gcc的編譯選項為-mno-apcs-frame ,此時編譯出來的代碼不一定會將PC,LR,SP和FP這四個寄存器的值壓入函數的棧幀中,可能只會將LR和FP寄存器的值壓入函數的棧幀中。關于-mapcs-frame選項,gcc的手冊描述如下:

Generateastackframethatiscompliant
withtheARMProcedureCallStandardfor
allfunctions,evenifthisisnotstrictly
necessaryforcorrectexecutionofthecode.
Specifying‘-fomit-frame-pointer’withthis
optioncausesthestackframesnottobe
generatedforleaffunctions.Thedefault
is‘-mno-apcs-frame’.
Thisoptionisdeprecated.

我這里使用的gcc信息如下:

$arm-none-eabi-gcc-v
...
gccversion10.3.120210824(release)(GNUArmEmbeddedToolchain10.3-2021.10)

雖然gcc手冊上說-mapcs-frame選項被廢棄了,但是只有添加了該選項,編譯出來的代碼才會將PC,LR,SP和FP寄存器的值壓入函數的棧幀中。

我這里編譯代碼仍然使用-mapcs-frame選項,有知道該選項對應的新的棧幀配置選項的兄弟可以告知我一下。

棧回溯示例

根據前面的內容,這里簡單的寫了一個棧回溯的示例,函數調用流程為:main -> test_a -> test_b -> test_c。

函數的源代碼如下:

inttest_a(intarg0,intarg1,intarg2,intarg3,intarg4)
{
inta;

a=0xff11;

test_b(0xbb00);

returna;
}

inttest_b(intarg0)
{
intb;

b=0xff22;

test_c(0xcc00);

returnb;
}

inttest_c(intarg0)
{
intc;

c=0xff33;

returnc;
}

intmain(void)
{
intval;

val=0xff00;

test_a(0xaa00,0xaa11,0xaa22,0xaa33,0xaa44);

return0;
}

上述函數的反匯編內容如下:

80002164:

inttest_a(intarg0,intarg1,intarg2,intarg3,intarg4)
{
80002164:e1a0c00dmovip,sp
80002168:e92dd800push{fp,ip,lr,pc}
8000216c:e24cb004subfp,ip,#4
80002170:e24dd018subsp,sp,#24
80002174:e50b0018strr0,[fp,#-24];0xffffffe8
80002178:e50b101cstrr1,[fp,#-28];0xffffffe4
8000217c:e50b2020strr2,[fp,#-32];0xffffffe0
80002180:e50b3024strr3,[fp,#-36];0xffffffdc
inta;

a=0xff11;
80002184:e30f3f11movwr3,#65297;0xff11
80002188:e50b3010strr3,[fp,#-16]

test_b(0xbb00);
8000218c:e3a00cbbmovr0,#47872;0xbb00
80002190:eb000003bl800021a4

returna;
80002194:e51b3010ldrr3,[fp,#-16]
}
80002198:e1a00003movr0,r3
8000219c:e24bd00csubsp,fp,#12
800021a0:e89da800ldmsp,{fp,sp,pc}

800021a4:

inttest_b(intarg0)
{
800021a4:e1a0c00dmovip,sp
800021a8:e92dd800push{fp,ip,lr,pc}
800021ac:e24cb004subfp,ip,#4
800021b0:e24dd010subsp,sp,#16
800021b4:e50b0018strr0,[fp,#-24];0xffffffe8
intb;

b=0xff22;
800021b8:e30f3f22movwr3,#65314;0xff22
800021bc:e50b3010strr3,[fp,#-16]

test_c(0xcc00);
800021c0:e3a00b33movr0,#52224;0xcc00
800021c4:eb000003bl800021d8

returnb;
800021c8:e51b3010ldrr3,[fp,#-16]
}
800021cc:e1a00003movr0,r3
800021d0:e24bd00csubsp,fp,#12
800021d4:e89da800ldmsp,{fp,sp,pc}

800021d8:

inttest_c(intarg0)
{
800021d8:e1a0c00dmovip,sp
800021dc:e92dd800push{fp,ip,lr,pc}
800021e0:e24cb004subfp,ip,#4
800021e4:e24dd010subsp,sp,#16
800021e8:e50b0018strr0,[fp,#-24];0xffffffe8
intc;

c=0xff33;
800021ec:e30f3f33movwr3,#65331;0xff33
800021f0:e50b3010strr3,[fp,#-16]

returnc;
800021f4:e51b3010ldrr3,[fp,#-16]
}
800021f8:e1a00003movr0,r3
800021fc:e24bd00csubsp,fp,#12
80002200:e89da800ldmsp,{fp,sp,pc}

80002204
: intmain(void) { 80002204:e1a0c00dmovip,sp 80002208:e92dd800push{fp,ip,lr,pc} 8000220c:e24cb004subfp,ip,#4 80002210:e24dd010subsp,sp,#16 intval; val=0xff00; 80002214:e3a03cffmovr3,#65280;0xff00 80002218:e50b3010strr3,[fp,#-16] test_a(0xaa00,0xaa11,0xaa22,0xaa33,0xaa44); 8000221c:e30a3a44movwr3,#43588;0xaa44 80002220:e58d3000strr3,[sp] 80002224:e30a3a33movwr3,#43571;0xaa33 80002228:e30a2a22movwr2,#43554;0xaa22 8000222c:e30a1a11movwr1,#43537;0xaa11 80002230:e3a00caamovr0,#43520;0xaa00 80002234:ebffffcabl80002164 return0; 80002238:e3a03000movr3,#0 } 8000223c:e1a00003movr0,r3 80002240:e24bd00csubsp,fp,#12 80002244:e89da800ldmsp,{fp,sp,pc}

當程序運行到test_c()函數的return c;代碼處時,FP的值為0x9FDFFF94,此時內存數據如下:

6441f4be-8842-11ee-939d-92fbcf53809c.png

Snipaste_2023-08-30_15-56-26

test_c()函數的棧底為0x9FDFFF94,可以得到test_c()函數棧幀中LR為0x800021C8、FP為0x9FDFFFB4,LR是test_c()函數執行完成后的返回地址,與反匯編代碼中test_b()函數調用完test_c()之后的下一個執行地址一致:

800021c0:e3a00b33movr0,#52224;0xcc00
800021c4:eb000003bl800021d8

returnb;
800021c8:e51b3010ldrr3,[fp,#-16]//test_c()函數返回后繼續執行的地址

FP為0x9FDFFFB4表示test_b()函數的棧底為0x9FDFFFB4,有了test_b()函數的棧底就可以得到test_b()函數棧幀中LR為0x80002194、FP為0x9FDFFFDC,從而知道test_b()函數執行完成后的返回地址以及test_a()函數的棧底,依次逐級回溯,就可以知道程序的整個運行流程了。

在棧回溯的過程中我們可以利用addr2line工具輔助我們對程序執行流程的分析。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    31

    文章

    5321

    瀏覽量

    120017
  • 計數器
    +關注

    關注

    32

    文章

    2254

    瀏覽量

    94358
  • ARM處理器
    +關注

    關注

    6

    文章

    360

    瀏覽量

    41667

原文標題:ARMv7-A 那些事 - 7.棧回溯淺析

文章出處:【微信號:嵌入式那些事,微信公眾號:嵌入式那些事】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    armv7 generic timer使用筆記

    armv7-A架構中每個CPU核心都包含自己的私有定時器,所有cpu的定時器共享一個System counter, System counter負責產生計數,傳遞到每個核心的私有定時器
    的頭像 發表于 09-27 15:10 ?2454次閱讀
    <b class='flag-5'>armv7</b> generic timer使用筆記

    ARMv7-A架構的實現中SIMD和VFP的擴展實現是可選的嗎?如何了解某控制器是否支持這些實現?

    ,如果更換其他ARMv7-A實現的內核(如Cortex A8),如何確定該實現是否支持?第一次提問,如果表述不清楚請見諒!謝謝!
    發表于 07-01 16:33

    ARMv8-A AArch32主要特性

    Cortex-A32產品介紹ARMv8-A AArch32主要特性ARMv7-M與AArch32的不同之處軟件從ARMv7-M移植到ARMv7-A
    發表于 02-19 06:20

    淺析ARMv7-A體系架構下的MMU的基本原理

    。MMU 主要功能之一是虛擬地址到物理地址的轉換,這個需要軟件和硬件配合完成,軟件需要針對不同的硬件進行策略。這里主要分析 ARMv7-A 體系架構下的 MMU 的基本原理。VMSA 是針對
    發表于 05-24 16:54

    如何在Armv7-A系列芯片上根據錯誤調用來debug呢

    本周解決了兩個在 Armv7-A 系列芯片上出現的錯誤,包括一個由于軟浮點配置導致的未定義指令錯誤以及一個由于數據未對齊導致的 data abort 錯誤,通過解決這兩個問題,學會了如何在 A 系列
    發表于 06-13 17:42

    Armv8-A構架中Armv8.6-A引進的最新功能介紹

    :細化的trap從Armv7-A開始引入虛擬化以來,arm持續改進虛擬化的支持。一個虛擬化關鍵的支持是trap虛擬機執行的一些操作。目的是為了虛擬化這些操作或是讓hypervisor充當Guest
    發表于 07-29 15:29

    ARM體系結構參考手冊ARMv7-AARMv7-R版本

    提前(AOT)編譯的特定支持。 ·決定處理器如何運行的模式和狀態,包括當前的執行特權和安全性。 ·例外模式。 ·內存模型,定義內存排序和內存管理: -ARMv7-A架構配置文件定義虛擬內存系統架構
    發表于 08-12 07:46

    ARM Cortex-A系列ARMv8-A程序員指南

    。 GNU和Linux文檔(Redhat和Fedora發行版除外)有時將AArch64稱為ARM64。 因為ARMv8-A體系結構的許多概念都與ARMv7-A體系結構相同,所以這里不涉及所有這些概念的細節
    發表于 08-22 07:22

    在基于ARMv7的平臺1.0版上使用CSAT進行低級調試

    Armv7-A 平臺上執行某些調試操作。 側重于平臺推移硅、 FPGA 和硬件模擬環境的用戶如果想要測試其調試設計的某些方面, 可能會發現此調試操作是有用的 。 此教程覆蓋的調試操作包括: ? 使用調試
    發表于 08-28 06:50

    如何將軟件應用程序從ARMv5遷移到ARMv7-A/R

    5。 本應用筆記還假設您具有ARMv5的軟件開發經驗。 假設主目標平臺是圍繞ARMv7-A處理器構建的。 由于ARMv7-AARMv7-R有許多重疊的區域,本文檔的一部分也適用于
    發表于 08-29 06:51

    一文詳解Linux內核的回溯與妙用

    網上或多或少都能找到回溯的一些文章,但是講的都并不完整,沒有將內核回溯的功能用于實際的內核、應用程序調試,這是本篇文章的核心:盡可能引導讀者將
    的頭像 發表于 10-05 10:02 ?5300次閱讀
    一文詳解Linux內核的<b class='flag-5'>棧</b><b class='flag-5'>回溯</b>與妙用

    ARMv7ARMv7的體系結構參考手冊免費下載

    ARM? Architecture Reference Manual ARMv7-A and ARMv7-R edition
    發表于 09-28 08:00 ?27次下載
    <b class='flag-5'>ARMv7</b>和<b class='flag-5'>ARMv7</b>的體系結構參考手冊免費下載

    Cortex A7 MPCore的技術參考手冊

    Cortex-A7 MPCore處理器是實現ARMv7-a架構的高性能、低功耗處理器。Cortex-A7 MPCore處理器在一個多處理器設備中有一到四個處理器,一個一級緩存子系統,一個可選的集成GIC和一個可選的二級緩存控制器
    發表于 12-09 08:00 ?9次下載
    Cortex <b class='flag-5'>A7</b> MPCore的技術參考手冊

    ARMv7-A工作模式介紹

    級(非安全模式)的應用就不能訪問高等級(安全模式)的資源,以此來保證敏感資源的安全性。 ARMv7-A 工作模式 以前的 A
    的頭像 發表于 09-11 16:31 ?936次閱讀
    <b class='flag-5'>ARMv7-A</b>工作模式介紹

    RVBacktrace RISC-V極簡回溯組件

    RVBacktrace組件簡介一個極簡的RISC-V回溯組件。功能在需要的地方調用組件提供的唯一API,開始當前環境的回溯支持輸出addr2line需要的命令,使用addr2lin
    的頭像 發表于 09-15 08:12 ?300次閱讀
    RVBacktrace RISC-V極簡<b class='flag-5'>棧</b><b class='flag-5'>回溯</b>組件