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

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

3天內不再提示

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

嵌入式那些事 ? 來(lái)源:嵌入式那些事 ? 2023-11-21 15:51 ? 次閱讀

嵌入式開(kāi)發(fā)過(guò)程中,經(jīng)常需要對代碼進(jìn)行調試來(lái)解決各種各樣的問(wèn)題,常用的調試手段有:

(1)、開(kāi)發(fā)環(huán)境搭配硬件仿真器進(jìn)行在線(xiàn)調試。優(yōu)點(diǎn):調試過(guò)程中能夠清楚的知道各個(gè)寄存器的值以及各個(gè)變量的值,程序的執行流程也能夠一目了然。缺點(diǎn):板卡需要引出硬件仿真器的連接口,并且需要購買(mǎi)硬件仿真器。

(2)、通過(guò)調試串口打印信息梳理程序的執行流程,結合代碼分析問(wèn)題產(chǎn)生的原因。優(yōu)點(diǎn):足夠簡(jiǎn)單,通過(guò)增加較多的打印信息來(lái)分析問(wèn)題出現的位置,再結合代碼分析問(wèn)題產(chǎn)生的原因。缺點(diǎn):沒(méi)法準確的定位問(wèn)題產(chǎn)生的位置和原因。

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

本文主要簡(jiǎn)單的講講?;厮?,對于以后去理解操作系統的異常棧處理打個(gè)基礎吧。

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

?;厮菹嚓P(guān)寄存器

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

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

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

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

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

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

ARM棧幀結構

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

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

每個(gè)函數都有自己的??臻g,這一部分稱(chēng)為棧幀。棧幀在函數被調用的時(shí)候創(chuàng )建,在函數返回后銷(xiāo)毀。每個(gè)函數的棧幀是由SP寄存器和FP寄存器來(lái)界定的,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;
}

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

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

?;厮菰?/p>

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

?;厮菥幾g選項

當gcc的編譯選項帶有-mapcs-frame時(shí),編譯出來(lái)的代碼能夠將PC,LR,SP和FP寄存器的值壓入函數的棧幀中。默認情況下gcc的編譯選項為-mno-apcs-frame ,此時(shí)編譯出來(lái)的代碼不一定會(huì )將PC,LR,SP和FP這四個(gè)寄存器的值壓入函數的棧幀中,可能只會(huì )將LR和FP寄存器的值壓入函數的棧幀中。關(guān)于-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手冊上說(shuō)-mapcs-frame選項被廢棄了,但是只有添加了該選項,編譯出來(lái)的代碼才會(huì )將PC,LR,SP和FP寄存器的值壓入函數的棧幀中。

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

?;厮菔纠?/p>

根據前面的內容,這里簡(jiǎn)單的寫(xiě)了一個(gè)?;厮莸氖纠?,函數調用流程為: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;代碼處時(shí),FP的值為0x9FDFFF94,此時(shí)內存數據如下:

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()之后的下一個(gè)執行地址一致:

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()函數的棧底,依次逐級回溯,就可以知道程序的整個(gè)運行流程了。

在?;厮莸倪^(guò)程中我們可以利用addr2line工具輔助我們對程序執行流程的分析。






審核編輯:劉清

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

    關(guān)注

    30

    文章

    5167

    瀏覽量

    118247
  • 計數器
    +關(guān)注

    關(guān)注

    32

    文章

    2211

    瀏覽量

    93448
  • ARM處理器
    +關(guān)注

    關(guān)注

    6

    文章

    351

    瀏覽量

    41395

原文標題:ARMv7-A 那些事 - 7.?;厮轀\析

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

收藏 人收藏

    評論

    相關(guān)推薦

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

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

    安徽Cortex-A7和大時(shí)代Cortex-A8內核的MCU改如何選擇?

    ARMv7-A架構的第一款Cortex-A系列的內核;Cortex-A7是后期才發(fā)布的,集合了前期發(fā)布內核的優(yōu)點(diǎn),彌補缺點(diǎn),在性能和功能上都有很大的增強?! ∑浯?,我們看下Cortex-A7
    發(fā)表于 09-29 10:19

    Cortex-A7和安徽Cortex-A8內核的大時(shí)代MCU改如何選擇

    Cortex-A8發(fā)布的時(shí)間很早,是屬于ARMv7-A架構的第一款Cortex-A系列的內核;Cortex-A7是后期才發(fā)布的,集合了前期發(fā)布內核的優(yōu)點(diǎn),彌補缺點(diǎn),在性能和功能上都有很
    發(fā)表于 10-17 10:27

    ARMv8-A AArch32主要特性

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

    ARMv8的函數調用是什么意思?調用的內存管理是怎樣的

    stack,函數調用過(guò)程中用來(lái)保存CPU狀態(tài)的存儲空間就叫調用。ARM體系結構對64位的支持從ARMV8開(kāi)始,V7及以前的版本并不支持。V8的寄存器及指令集都發(fā)生了較大的變化,導致V7
    發(fā)表于 05-13 10:36

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

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

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

    本周解決了兩個(gè)在 Armv7-A 系列芯片上出現的錯誤,包括一個(gè)由于軟浮點(diǎn)配置導致的未定義指令錯誤以及一個(gè)由于數據未對齊導致的 data abort 錯誤,通過(guò)解決這兩個(gè)問(wèn)題,學(xué)會(huì )了如何在 A 系列
    發(fā)表于 06-13 17:42

    Armv8-A構架中Armv8.6-A引進(jìn)的最新功能介紹

    :細化的trap從Armv7-A開(kāi)始引入虛擬化以來(lái),arm持續改進(jìn)虛擬化的支持。一個(gè)虛擬化關(guān)鍵的支持是trap虛擬機執行的一些操作。目的是為了虛擬化這些操作或是讓hypervisor充當Guest
    發(fā)表于 07-29 15:29

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

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

    Cortex-A7 MPCore技術(shù)參考手冊

    Cortex-A7 MPCore處理器是一款實(shí)現ARMv7-A架構的高性能、低功耗處理器。 Cortex-A7 MPCore處理器在帶有一級高速緩存子系統、可選集成GIC和可選二級高速緩存控制器的單個(gè)多處理器設備中具有一到四個(gè)處
    發(fā)表于 08-18 07:25

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

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

    在基于ARMv7的平臺1.0版上使用CSAT進(jìn)行低級調試

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

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

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

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

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

    ARMv7-A工作模式介紹

    級(非安全模式)的應用就不能訪(fǎng)問(wèn)高等級(安全模式)的資源,以此來(lái)保證敏感資源的安全性。 ARMv7-A 工作模式 以前的 A
    的頭像 發(fā)表于 09-11 16:31 ?581次閱讀
    <b class='flag-5'>ARMv7-A</b>工作模式介紹
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看