?
1、介紹
- FP:棧頂指針,指向一個(gè)棧幀的頂部,當(dāng)函數(shù)發(fā)生跳轉(zhuǎn)時(shí),會(huì)記錄當(dāng)時(shí)的棧的起始位置。
- SP:棧指針(也稱為棧底指針),指向棧當(dāng)前的位置,
- LR:鏈接寄存器,保存函數(shù)返回的地址。
關(guān)于gcc就有一個(gè)關(guān)于stack frame的優(yōu)化選項(xiàng),加上該選項(xiàng)則忽略掉FP棧頂指針,(記得高版本默認(rèn)是不加FP的,gcc4.8以上吧(待確認(rèn)))
- -fomit-frame-pointer
Don’t keep the frame pointer in a register for functions that don’t need one. This avoids the instructions to save, set up and restore frame pointers; it also makes an extra register available in many functions. It also makes debugging impossible on some machines.
(大概意思 )不需要棧幀的時(shí)候不要加這個(gè)編譯選項(xiàng),這可以節(jié)省很多指令去保存,傳遞和恢復(fù),同時(shí)也省出一個(gè)寄存器可以在函數(shù)中做更多事情,也使得在某些機(jī)制下更容易去debug
arm cc5編譯也有關(guān)于FP生成的編譯選項(xiàng),默認(rèn)是不加的。
- –use_frame_pointer, --no_use_frame_pointer
Sets the frame pointer to the current stack frame.Using the --use_frame_pointer option reserves a register to store the 「frame pointer」.For newer processors that support Thumb-2 technology (ARMv6T2 and later), the reserved register isalways R11.(arm v7)如果是arm v8 -a 系列,則是X29來(lái)表示。For older processors that do not support Thumb-2 technology, the reserved register is R11 in ARM codeand R7 in Thumb code.Default「The default is --no_use_frame_pointer」. That is, register R11 (or register R7 for Thumb code on olderprocessors) is available for use as a general-purpose registe
2、作用
2.1 FP的作用
關(guān)于APCS(ARM Procedure Call Standard,ARM 程序調(diào)用標(biāo)準(zhǔn))的說(shuō)法 ,
- 除非子程序沒有修改鏈接寄存器,否則FP都需要記錄有效的棧幀位置
- 其寄存器(r11或者x29)不能被用做一個(gè)通用型的寄存器
FP的主要作用就是用來(lái)「棧回溯」,找到子程序的調(diào)用關(guān)系,也成為backtrace,當(dāng)然一級(jí)一級(jí)的子程序調(diào)用時(shí),F(xiàn)P的記錄也在變化,也會(huì)一級(jí)一級(jí)的保存到棧中,最后通過(guò)FP的值來(lái)反推出一級(jí)一級(jí)的調(diào)用關(guān)系。
以ARM CC5 編譯器為例,其棧回溯的主要邏輯如下圖所示:
通過(guò)上圖可以看出,main->fun1->fun2,每調(diào)用一級(jí)的時(shí)候,都會(huì)將FP、LR以及參數(shù)等壓棧,而每個(gè)FP指向了上一級(jí)的棧頂,通過(guò)保存關(guān)系,可以找到LR,從而找到上一級(jí)的調(diào)用函數(shù)。
具體的流程圖就如右圖所示,按照這樣的方法可以找到backtrace,再比如可以通過(guò)stack memory查找調(diào)用棧信息,
?
左圖為棧memory 右圖為寄存器信息。
上圖中:backtrace 第一級(jí)是寄存器中的LR,之后就是從棧中進(jìn)入回溯來(lái)找到的。(FP、LR)1、0x1F7BC 0x40BBAA42、0x1F7E4 0x18A3C3、0x1F7EC 0x188184、 0x1F7F4 0x40A41085、 0x1F7FC 0x15946、 0x184BC 0x40A0015
圖中 LR地址都-4 這是因?yàn)長(zhǎng)R總是保存PC的下一個(gè)運(yùn)行地址,所以找到PC進(jìn)函數(shù)的位置,則需要LR-4可以得到。
圖中 最后棧停止回溯,可以看到棧的邊界到了0x1f800,所以停止,不然會(huì)繼續(xù)一直進(jìn)行回溯。
backtrace的C代碼如下
void?get_backtrace(u32?lr,?u32?fP)
{
?u8?backtrace_deep?=?0
?u32?stack_limit=getStackLimit()
?u32?stack_base=getStackBase()
?
?printf("Bactrace?info:
")
?do{
??if((fp?<=?stack_base)?&&(fp?>=?stack_limit))
???break;
??lr?=?*(u32*)(fp)
??lr?(lr?==?OxFFFFFFFF?||?lr?==?0x0)
???break;
??fp=*(u32*)(fp-sizeof(u32))
??if(backtrace_deep++>MAX_BACKTRACE_DEPTH)
???break;
?}while(1);
?printf("
");
}
12345678910111213141516171819
2.2 SP的作用
sp 為棧指針,通過(guò)push pop 實(shí)現(xiàn)對(duì)棧存儲(chǔ)的訪問,棧主要是用來(lái)存儲(chǔ)局部變量 中間值 等數(shù)據(jù),同樣和全部變量等存儲(chǔ)的區(qū)域一樣,也是一塊memory,沒有任何區(qū)別,只是使用的方式不一樣。
接下來(lái)簡(jiǎn)單介紹一下各個(gè)處理器架構(gòu)的SP指針。
- CortexM3/4(ARMv7)
- CortexM3/4中,「SP分為MSP與PSP」,主棧與線程棧,任何時(shí)刻只有一個(gè)棧指針有效,通過(guò)「CONTROL 寄存器」來(lái)選擇棧指針。
- 程序剛運(yùn)行時(shí)就處在主棧(特權(quán)模式),之后可以切到線程棧(非特權(quán)模式),之所以設(shè)置這樣的原因是,一般OS會(huì)運(yùn)行在主棧,而應(yīng)用程序出在線程棧,應(yīng)用程序即使出錯(cuò),也不會(huì)影響OS的運(yùn)行,也不會(huì)影響主棧。通過(guò)簡(jiǎn)單的程序無(wú)需這樣運(yùn)行,直接在主棧特權(quán)模式下面運(yùn)行就可以。
- MSP的初值通過(guò)存儲(chǔ)器的第一個(gè)DWORD中獲取。
- MSP與PSP 都是32位,低兩位均是0.
- CortexR5(Cortexv7)
-
Cortex R5系列比較復(fù)雜,繼承了多種工作模式的特性,大多數(shù)模式下都有獨(dú)立的棧。
?
- 總共七種工作模式,SYS/FIQ/SYS/SVC/ABORT/IRQ/UND 以及USER,前面六種都是特權(quán)模式 后面是用戶模式也是非特權(quán)模式。可以看到基本都有獨(dú)立的棧寄存器,意味著每個(gè)模式下可以設(shè)置獨(dú)立的棧空間
-

- CortexA53 (ARMv8 -A系列)
- 其有變化了 分為EL1 EL2 EL3 EL4四種模式(AArch64狀態(tài))。每種模式下有自己的SP指針,SP_EL0,SP_EL1,SP_EL2,SP_EL3。通過(guò)SPSel來(lái)選擇是哪一種的SP指針。
-
- SP_EL1t 代表SP_EL0的指針,SP_ELxH代表相應(yīng)等級(jí)下的SP指針。
- 如果用作基址運(yùn)算時(shí),SP的低四位[3:0]必須為0,否則會(huì)產(chǎn)生SP非對(duì)齊異常,系統(tǒng)自動(dòng)會(huì)進(jìn)行check。
CheckSPAlignment()
?bits(64)?sp?=?SP[];
?if?PSTATE.EL?==?EL0?then
??stack_align_check?=?(SCTLR[].SA0?!=?'0');
?else
??stack_align_check?=?(SCTLR[].SA?!=?'0');
?if?stack_align_check?&&?sp?!=?Align(sp,?16)?then
??AArch64.SPAlignmentFault();
return;
123456789
由下圖可以看到EL3下的SP有值,且與系統(tǒng)的SP值相同(X15下面),則處于EL3模式。
2.3 LR的作用
-
LR為程序跳轉(zhuǎn)時(shí)需要用到的寄存器,用來(lái)保存「返回地址」(同時(shí)也包含異常返回地址)。
-
程序經(jīng)常會(huì)存在調(diào)用關(guān)系,當(dāng)程序執(zhí)行完子程序之后,肯定會(huì)返回到主程序,這是返回到主程序的地址就是在LR保存。
-
在一些CorteM系列的處理,LR的第0位會(huì)置1 表示,表示Thumb狀態(tài)。
-
當(dāng)然沒有LR這個(gè)寄存器也可以的,直接將返回地址保存到棧中,最后執(zhí)行完之后彈出到PC也行,但是寄存器的訪問速度可以遠(yuǎn)高于棧(存儲(chǔ)器SRAM),所以LR的作用還是很明顯的。
-
此外對(duì)應(yīng)ARMv8系列,還有ELR寄存器,對(duì)應(yīng)的是異常狀態(tài)下的返回地址。
a. 當(dāng)程序執(zhí)行到異常時(shí),異常的返回地址保存到ELR中,當(dāng)然ARMv8有四種模式,EL0沒有異常處理,所以只有三個(gè)ELR寄存器,處理三種異常時(shí)的返回地址。b. AArch32到AArch64狀態(tài)時(shí),保存的是32位的地址,高8位均為0。
-
2.3.1 LR的地址保存
當(dāng)假如程序A->B->C,
void?A()
{
?....??//1地址
?B();??//;BL?B
?....?//2地址
?return;
}
void?B()
{
?....?//3地址
?C();?//BL?C
?....?//4地址
?return;??//pop?lr->PC
}
void?C()
{
?....
?return;?//B?LR
}
12345678910111213141516171819
- 程序A調(diào)用B程序,此時(shí)LR更新為「2地址」,
- 跳轉(zhuǎn)到B程序時(shí),B發(fā)現(xiàn)還要跳轉(zhuǎn)到C程序,所以LR會(huì)被覆蓋,所以在B程序開始的時(shí)候,會(huì)講LR保存到棧中。
- 挑轉(zhuǎn)到C程序時(shí),此時(shí)LR更新到「4地址」,
- C程序執(zhí)行開始時(shí),發(fā)現(xiàn)沒有子程序跳轉(zhuǎn)了,所以此時(shí)的LR不會(huì)被覆蓋,所以也不需要將LR保存,退出時(shí)直接跳轉(zhuǎn)到「4地址」即可。
- B程序執(zhí)行完時(shí),發(fā)現(xiàn)LR還是錯(cuò)的,會(huì)將壓棧的LR彈出,這樣程序就可以回到「2地址」。
- 如此一來(lái),程序就完成調(diào)用過(guò)程,全部執(zhí)行完畢。
2.3.2 接著來(lái)說(shuō)跳轉(zhuǎn)的指令
-
B
- 用法:B Lable,直接跳轉(zhuǎn)Lable處的地址,不改變LR,有限范圍內(nèi)的跳轉(zhuǎn),是不返回的跳轉(zhuǎn)??梢钥吹缴蠄DB跳轉(zhuǎn)的地址 就是在附近,說(shuō)明可能是跳到后面的程序的指令,不帶返回的。
-
-
BL
- 用法:BL Lable,將LR=PC+4,(比如在32位程序上+4,Thumb是+2,64位程序上可能是+8)然后跳轉(zhuǎn)到Lable地址,帶鏈接的挑戰(zhàn),說(shuō)明還會(huì)回來(lái)的。圖中0x8000F300 地址不在該程序范圍內(nèi),說(shuō)明是跳到其他地址處 執(zhí)行完成之后,w0是返回值,然后再跳到此次,是帶鏈接的跳轉(zhuǎn)。
-
-
BX:
- 用法:BX Lable,跳轉(zhuǎn)到對(duì)應(yīng)Label地址,Lable中最后一位(bit)為指令集標(biāo)志,1表示Thumb,0表示ARM狀態(tài),可能會(huì)進(jìn)行模式切換,是不返回的跳轉(zhuǎn)。
- 用法:BX reg,跳轉(zhuǎn)到 reg里面保存的地址,同上,可能會(huì)切換模式。該程序直接跳到lr所指示的地址,即返回地址。
-
-
BLX:
- 用法:BLX Lable,跳轉(zhuǎn)到對(duì)應(yīng)Label地址,可能會(huì)切換模式,同時(shí)LR保存了返回的地址。
- 用法:BLX reg,跳轉(zhuǎn)到 reg里面保存的地址,可能會(huì)切換模式,同時(shí)LR保存了返回的地址。
-
BR:
- 用法:BR reg,跳轉(zhuǎn)到 reg里面保存的地址,是不返回的跳轉(zhuǎn)。
-
BLR:
- 用法:BLR reg,跳轉(zhuǎn)到 reg里面保存的地址,同時(shí)LR保存了返回的地址。
-
B.
- 用法:B.Cond label,根據(jù)狀態(tài)位進(jìn)行跳轉(zhuǎn),比如 ZCNV 等狀態(tài)位,
- 例如:BHI Lable 、BCS Lable
-
- b.cs 如果w8 >= 0x397 則跳到0x800c0988地址處。
-
評(píng)論