1. 程式人生 > >ARMv8架構下程式執行時棧幀佈局

ARMv8架構下程式執行時棧幀佈局

結合ARM相關文件和在飛騰機器上使用gdb除錯實際程式來研究ARM的指令和執行時棧幀佈局。主要參考了三篇文件。

1. Procedure Call Standard for the ARM 64-bit Architecture。參考其中的過程呼叫標準和執行時棧幀佈局。

2. ARMv8 Instruction Set Overview。參考其中的指令概述。

3. ARM Compiler Migration and Compatibility Guide。參考其中ARM彙編與GNU彙編格式的比較。

在文章1中,對ARM架構下執行時棧幀佈局如圖1所示。

圖1 ARM執行時棧幀佈局

其中,FP(x29)暫存器儲存棧幀地址,LR(x30)儲存當前過程的返回地址。棧是從高地址向低地址生長。為驗證圖中的佈局形式,在飛騰機器上安裝gdb,通過除錯一個示例程式,來研究ARM的指令特點和棧幀結構。示例程式如圖2所示,函式TestParam定義了兩個區域性變數,分別為陣列和標量型別。


圖2 示例程式

使用gdb除錯圖2中程式碼所產生的程式,然後再反彙編函式TestParam,可以得到如下結果。

=> 0x0000000000400680 <+0>:stpx29, x30, [sp,#-64]!

   0x0000000000400684 <+4>:movx29, sp

   0x0000000000400688 <+8>:strw0, [x29,#28]

   0x000000000040068c <+12>:strw1, [x29,#24]

   0x0000000000400690 <+16>:strw2, [x29,#20]

   0x0000000000400694 <+20>:strw3, [x29,#16]

   0x0000000000400698 <+24>:adrpx0, 0x411000 <

[email protected]>

   0x000000000040069c <+28>:addx0, x0, #0x38

   0x00000000004006a0 <+32>:ldrx1, [x0]

   0x00000000004006a4 <+36>:strx1, [x29,#56]

   0x00000000004006a8 <+40>:movx1, #0x0                   // #0

   0x00000000004006ac <+44>:ldrw1, [x29,#28]

   0x00000000004006b0 <+48>:ldrw0, [x29,#24]

   0x00000000004006b4 <+52>:addw0, w1, w0

   0x00000000004006b8 <+56>:strw0, [x29,#48]

   0x00000000004006bc <+60>:ldrw1, [x29,#20]

   0x00000000004006c0 <+64>:ldrw0, [x29,#16]

   0x00000000004006c4 <+68>:subw0, w1, w0

   0x00000000004006c8 <+72>:strw0, [x29,#52]

   0x00000000004006cc <+76>:ldrw1, [x29,#20]

   0x00000000004006d0 <+80>:ldrw0, [x29,#16]

   0x00000000004006d4 <+84>:addw0, w1, w0

   0x00000000004006d8 <+88>:strw0, [x29,#44]

   0x00000000004006dc <+92>:ldrw1, [x29,#48]

   0x00000000004006e0 <+96>:ldrw2, [x29,#52]

   0x00000000004006e4 <+100>:adrpx0, 0x400000

   0x00000000004006e8 <+104>:addx0, x0, #0x808

   0x00000000004006ec <+108>:ldrw3, [x29,#44]

   0x00000000004006f0 <+112>:bl0x400530 <[email protected]>

   0x00000000004006f4 <+116>:adrpx0, 0x411000 <[email protected]>

   0x00000000004006f8 <+120>:addx0, x0, #0x38

   0x00000000004006fc <+124>:ldrx1, [x29,#56]

   0x0000000000400700 <+128>:ldrx0, [x0]

   0x0000000000400704 <+132>:eorx0, x1, x0

   0x0000000000400708 <+136>:cmpx0, xzr

   0x000000000040070c <+140>:b.eq0x400714 <TestParam+148>

   0x0000000000400710 <+144>:bl0x400500 <[email protected]>

   0x0000000000400714 <+148>:ldpx29, x30, [sp],#64

   0x0000000000400718 <+152>:ret

該程式在執行時的棧幀如圖3所示。


以下是反彙編指令的解釋以及其對棧中內容的影響。

=> 0x0000000000400680 <+0>:stpx29, x30, [sp,#-64]!

   0x0000000000400684 <+4>:movx29, sp

指令stp把一對值x29x30放到SP-64的地址(7ffffff370)中去。此時的SP是舊SP,其值為7ffffff3b0。值得注意的是,這條語句同時完成了SP的自減運算,也就是執行之後,SP的值也變成了7ffffff370。第二條指令把FP的值設定為與SP的值相同。

   0x0000000000400688 <+8>:strw0, [x29,#28]

   0x000000000040068c <+12>:strw1, [x29,#24]

   0x0000000000400690 <+16>:strw2, [x29,#20]

   0x0000000000400694 <+20>:strw3, [x29,#16]

4條指令把儲存在引數傳遞暫存器中的4個引數儲存到棧中。如圖2中的w0, w1, w2, w3所示。

   0x0000000000400698 <+24>:adrpx0, 0x411000 <[email protected]>

   0x000000000040069c <+28>:addx0, x0, #0x38

   0x00000000004006a0 <+32>:ldrx1, [x0]

   0x00000000004006a4 <+36>:strx1, [x29,#56]

   0x00000000004006a8 <+40>:movx1, #0x0                   // #0

5條指令是用於安全保障的。因為函式TestParam中聲明瞭一個數組,因此有受到緩衝區溢位攻擊的危險。在其他平臺下或者之前版本中,需要在編譯時顯式使用-fstack-protector選項,才會增加這樣的安全保障指令。而在飛騰ARM配置的編譯器中,預設就增加了。

其主要思路是在編譯時生成一個隨機化的值,如圖中的_stack_guard儲存在bss段中。在開始執行函式體時,把它從bss段中取出,放在棧的底部。然後執行函式。若有針對陣列e的緩衝區溢位攻擊,則_stack_guard就會被改寫。在函式執行結束時,再把棧底部的值和bss段中的原始值相比較,若兩者不同,就說明有攻擊行為發生。

5條指令的功能就是從bss段中把_stack_guard的值放到棧的底部。需要注意的是,在查詢時使用了相對定址指令adrp

   0x00000000004006ac <+44>:ldrw1, [x29,#28]

   0x00000000004006b0 <+48>:ldrw0, [x29,#24]

   0x00000000004006b4 <+52>:addw0, w1, w0

   0x00000000004006b8 <+56>:strw0, [x29,#48]

   0x00000000004006bc <+60>:ldrw1, [x29,#20]

   0x00000000004006c0 <+64>:ldrw0, [x29,#16]

   0x00000000004006c4 <+68>:subw0, w1, w0

   0x00000000004006c8 <+72>:strw0, [x29,#52]

8條指令是使用形式引數進行運算,並把結果儲存在陣列中。陣列中只有兩個元素,被放置在靠近棧底的位置。

   0x00000000004006cc <+76>:ldrw1, [x29,#20]

   0x00000000004006d0 <+80>:ldrw0, [x29,#16]

   0x00000000004006d4 <+84>:addw0, w1, w0

   0x00000000004006d8 <+88>:strw0, [x29,#44]

4條指令的作用是計算出f的值,並把它儲存到棧中。

   0x00000000004006dc <+92>:ldrw1, [x29,#48]

   0x00000000004006e0 <+96>:ldrw2, [x29,#52]

   0x00000000004006e4 <+100>:adrpx0, 0x400000

   0x00000000004006e8 <+104>:addx0, x0, #0x808

   0x00000000004006ec <+108>:ldrw3, [x29,#44]

   0x00000000004006f0 <+112>:bl0x400530 <[email protected]>

6條指令是負責準備引數暫存器x0w1、 w2w3的值,並呼叫printfx0中存放的是指向格式字串的指標。

   0x00000000004006f4 <+116>:adrpx0, 0x411000 <[email protected]>

   0x00000000004006f8 <+120>:addx0, x0, #0x38

   0x00000000004006fc <+124>:ldrx1, [x29,#56]

   0x0000000000400700 <+128>:ldrx0, [x0]

   0x0000000000400704 <+132>:eorx0, x1, x0

   0x0000000000400708 <+136>:cmpx0, xzr

   0x000000000040070c <+140>:b.eq0x400714 <TestParam+148>

   0x0000000000400710 <+144>:bl0x400500 <[email protected]>

8條指令是比較_stack_guard的值與存放在bss段中的值是否相等,若相等,在跳到400714,繼續執行TestParam函式,否則跳到_stack_chk_fail函式,處理緩衝區溢位發生的情況。

   0x0000000000400714 <+148>:ldpx29, x30, [sp],#64

   0x0000000000400718 <+152>:ret

2條指令從棧中恢復x29x30的值,並返回。需要注意的是ldp指令執行之後,sp的值自動增加了64


相關推薦

ARMv8架構程式執行佈局

結合ARM相關文件和在飛騰機器上使用gdb除錯實際程式來研究ARM的指令和執行時棧幀佈局。主要參考了三篇文件。 1. Procedure Call Standard for the ARM 64-bit Architecture。參考其中的過程呼叫標準和執行時棧幀佈局。 2

虛擬機器位元組碼執行引擎——執行結構

文章目錄 一、區域性變量表 二、運算元棧 三、動態連線 四、方法返回地址 五、附加資訊 虛擬機器與物理機異同 同:都具有程式碼執行能力 異:物理機的執行引擎是建立在處理器、硬體、指令集和作業系

linux 程式執行出現的 error while loading shared libraries

Linux中error while loadin   預設情況下,編譯器只會使用/lib和/usr/lib這兩個目錄下的庫檔案,通常通過原始碼包進行安裝時,如果不指定--prefix,會將庫安裝在/usr/local/lib目錄下;當執行程式需要連結動態庫時,提示找不到相關的.s

深入理解Java虛擬機器之類執行結構

棧幀(Stack Frame)是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧(Virtual Machine Stack)的棧元素。棧幀儲存了方法的區域性變量表、運算元棧、動態連線和方法返回地址等資訊。每一個方法從呼叫

JAVA記憶體結構之執行結構

http://www.360doc.com/content/14/0925/13/1073512_412236522.shtml 感謝原創者的付出 ---------------------------------------------------------------

Java編譯原理--執行結構

Java語言在剛剛誕生的時候提出過一句著名的口號“一次編寫,到處執行”,這句話充分的表達了開發人員對於衝破平臺界限的渴望,也解釋了Java語言跟平臺無關的設定。  一、 概述 Java虛擬機器規定了虛擬機器執行位元組碼的概念模型,這個模型是各類虛擬機器的外觀結構,不同的虛

執行結構

棧幀是用於支援虛擬機器進行方法呼叫和方法執行的資料結構 棧幀儲存了方法的區域性變量表,運算元棧,動態連線,方法返回地址等資訊,每一個方法從呼叫開始直至執行完成的過程都對應著一個棧幀從入棧到出棧的過程 區域性變數: 是一組變數值儲存空間,用於儲存方法引數和方法內部定義的區域性變數 最小

JVM(11)——執行結構

1. 概述 “虛擬機器”是一個相對於“物理機”的概念,這兩種機器都有程式碼執行能力,其區別是物理機的執行引擎是直接建立在處理器、硬體、指令集和作業系統層面上的,而虛擬機器的執行引擎則是由自己實現的,因此可以自行制定指令集與執行引擎的結構體系,並且能夠執行那些不

14 執行結構

《深入理解Java虛擬機器:JVM高階特性與最佳實踐(第2版)》8.2節 不同的虛擬機器實現在執行Java程式碼時可能會有解釋執行(通過直譯器執行)和編譯執行(通過即時編譯器產生原生代碼執行)兩種選擇 棧幀(Stack Frame) 用於支援虛擬機器進行方法呼叫和方法執

JVM理論:(三/3)運行結構、基於的字節碼解釋執行過程

指向 stat 中一 指令執行過程 字節碼指令 輸出 作用 引擎 jvm 一、棧幀結構   講棧幀結構有必要回顧一下前文Class文件中的Code屬性結構,如下圖。      棧幀是用於支持虛擬機進行方法調用和方法執行的數據結構,它是虛擬機棧的棧元素。每一個方法從調用開始到

linux實現在程式執行的函式替換(熱補丁)

原帖地址: 宣告:以下的程式碼成果,是參考了網上的injso技術,在本文的最後會給出地址,同時非常感謝injso技術原作者的分享。    但是injso文章中的程式碼存在一些問題,所以後面出現的程式碼是經過作者修改和檢測的。也正因為這些錯誤,加深了我的學習深度。 &nb

java程式碼的MapReduce打包成jar 報錯: JAVA程式執行出現:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsEx

以前的學習筆記,整理一下: java程式碼的MapReduce打包成jar 報錯: JAVA程式執行時出現:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at PrintWhat.main(Pri

windowstomcat執行出現java.io.IOException: 您的主機中的軟體中止了一個已建立的連線

問題原因及解決:       在tomcat中出現這個錯誤是由於客戶端在傳送請求後,還沒等伺服器響應就斷開了連線,有可能是因為網路原因,突然網斷了,但是如果錯誤頻繁出現的話,可能就是服務端的問題了。   &n

vs程式執行結果框閃退的三種解決方案

1.getchar() 在return 0 之前一行getchar();因為getchar()會一直等待使用者輸入 #include <iostream> using namespace std; int main() { cout << "hello world!

習題 11.1 將例11.1的程式片斷補充和改寫成一個完整、正確的程式,用公用繼承方式。在程式中應包括輸入資料的函式,在程式執行輸入num,name,sex,age,addr的值,程式應輸出以上。。

C++程式設計(第三版) 譚浩強 習題11.1 個人設計 習題 11.1 將例11.1的程式片斷補充和改寫成一個完整、正確的程式,用公用繼承方式。在程式中應包括輸入資料的函式,在程式執行時輸入num,n

VSCode的Python擴充套件程式執行的幾種方式與環境變數管理

在VSCode中編寫Python程式時,由於有些地方要使用環境變數,但是發現設定的環境變數有時不起作用,花了點時間研究了一下,過程不表,直接說結論。 首先,環境變數的設定,Python擴充套件中有三種方式: 直接設定系統環境變數,或在使用命令列啟動VSCode時臨時先設定環境變數。這種方式設定的環境變

QT程式執行增加-qws

在嵌入式QT版本中,程式需要伺服器或自己作為伺服器程式。伺服器程式構造的方法是構造一個QApplication::GuiServe型別的QApplication物件。或者使用-qws命令選項啟動程式。 如果在執行時,不加-qws,會報錯如下 No Qt for Embedded Linu

程式執行,建立一個額外的輸出臺,輸出程式內的Log以及除錯結果

需求描述:在做硬體除錯的時候,經常會需要用程式除錯具體問題處在哪裡,但是不斷重啟程式看日誌顯得繁瑣,想將日誌及除錯結果實時輸出。 解決方案:使用Kernel32.dll和user32.dll建立Console,使用控制檯實時輸出。在Main函式中新增實現程式碼

程式執行更改程式外觀

新建自己的VCL程式,在PROJECT>OPTIONS>Application>Appearance 下選擇好自己喜歡的幾個樣式 如下圖  然後按OK。 在視窗中放置PANNEL,頂部對齊;LISTBOX控制元件居中對齊;底部放置一個BUTTON按

qt程式執行的路徑問題

程式執行時的路徑是該程式在被呼叫時的目錄 假如系統剛啟動時,是在/目錄處, 這時系統啟動指令碼/etc/rc.local呼叫/home/root/qt_broadcast_client/qt_broadcast_client程式 則目錄就是/目錄,qt_broadcast_client在呼叫s