好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > 淺析ARM架構下的函數的調用過程

淺析ARM架構下的函數的調用過程

熱門標簽:10086外包用的什么外呼系統 福州企業電銷機器人排名 400電話辦理介紹信 上海申請高400開頭的電話 打400電話怎么辦理收費 宿城區電話機器人找哪家 麗江真人語音電話外呼系統 河南防封號電銷機器人是什么 怎么找到沒有地圖標注的店

1、背景知識

1、ARM64寄存器介紹

2、STP指令詳解(ARMV8手冊)

我們先看一下指令格式(64bit),以及指令對于寄存機執行結果的影響

類型1、STP <Xt1>, <Xt2>, [<Xn|SP>],#<imm>

將Xt1和Xt2存入Xn|SP對應的地址內存中,然后,將Xn|SP的地址變更為Xn|SP + imm偏移量的新地址

類型2、STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!

將Xt1和Xt2存入Xn|SP的地址自加imm對應的地址內存中,然后,將Xn|SP的地址變更為Xn|SP + imm的offset偏移量后的新地址

類型3、STP <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]

將Xt1和Xt2存入Xn|SP的地址自加imm對應的地址內存中

手冊中有三種操作碼,我們只討論程序中涉及的后兩種

Pseudocode如下:

Shared decode for all encodings
integer n = UInt(Rn);
integer t = UInt(Rt);
integer t2 = UInt(Rt2);
if L:opc<0> == '01' || opc == '11' then UNDEFINED;
integer scale = 2 + UInt(opc<1>);
integer datasize = 8 << scale;
bits(64) offset = LSL(SignExtend(imm7, 64), scale);
boolean tag_checked = wback || n != 31;
Operation for all encodings
bits(64) address;
bits(datasize) data1;
bits(datasize) data2;
constant integer dbytes = datasize DIV 8;
boolean rt_unknown = FALSE;
if HaveMTEExt() then
         SetNotTagCheckedInstruction(!tag_checked);
if wback && (t == n || t2 == n) && n != 31 then
    Constraint c = ConstrainUnpredictable();
    assert c IN {Constraint_NONE, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP};
    case c of
        when Constraint_NONE rt_unknown = FALSE; // value stored is pre-writeback
        when Constraint_UNKNOWN rt_unknown = TRUE; // value stored is UNKNOWN
        when Constraint_UNDEF UNDEFINED;
        when Constraint_NOP EndOfInstruction();
if n == 31 then
 CheckSPAlignment();
    address = SP[];
else
    address = X[n];
if !postindex then
    address = address + offset;
if rt_unknown && t == n then
    data1 = bits(datasize) UNKNOWN;
else
    data1 = X[t];
if rt_unknown && t2 == n then
    data2 = bits(datasize) UNKNOWN;
else
    data2 = X[t2];
Mem[address, dbytes, AccType_NORMAL] = data1;
Mem[address+dbytes, dbytes, AccType_NORMAL] = data2;
if wback then
  if postindex then
        address = address + offset;
    if n == 31 then
        SP[] = address;
    else
        X[n] = address;

紅色部分對應推棧的關鍵邏輯,其他匯編指令含義可自行參考armv8手冊或者度娘。

2、一個例子

熟悉了上面的部分,接下來我們看一個實例:

C代碼如下:

相關的幾個函數反匯編如下(和推棧相關的一般只有入口兩條指令):

main\f3\f4\strlen

我們通過gdb運行后,可以看到strlen地方會觸發SEGFAULT,引發進程掛掉

上述通過代碼編譯后,沒有strip,因此elf文件是帶著符號的

查看運行狀態(info register):關注$29、$30、SP、PC四個寄存器

一個核心的思想:CPU執行的是指令而不是C代碼,函數調用和返回實際是在線程棧上面的壓棧和彈棧的過程

接下來我們來看上面的調用關系在當前這個任務棧是如何玩的:

函數調用在棧中的關系(call function壓棧,地址遞減;return彈棧,地址遞增):

以下是推棧的過程(劃重點)

再回頭來看之前的匯編:

main\f3\f4\strlen

從當前的sp開始,frame 0是strlen,這塊沒有開棧,因此上一級的調用函數仍然是x30,因此推導:frame1調用為f3

函數f3的起始入口匯編:

(gdb) x/2i f3
   0x400600 <f3>: stp   x29, x30, [sp,#-48]!
   0x400604 <f3+4>:      mov x29, sp

可以看到,f3函數開辟的棧空間為48字節,因此,倒推frame2的棧頂為當前的sp + 48字節:0xfffffffff2c0

(gdb) x/gx 0xfffffffff2c0+8
0xfffffffff2c8:    0x000000000040065c
(gdb) x/i 0x000000000040065c
   0x40065c <f4+36>:    mov w0, #0x0                       // #0
frame2的函數為sp+8:0x000000000040065c -> <f4+36>

繼續從sp = 0xfffffffff2c0倒推frame1的函數

函數f4的起始入口匯編為:

(gdb) x/2i f4
   0x400638 <f4>: stp   x29, x30, [sp,#-48]!
   0x40063c <f4+4>:      mov x29, sp

可以看到,f4函數開辟的棧空間也是為48字節,因此,倒推frame3的棧頂為當前的0xfffffffff2c0 + 48字節:0xfffffffff2f0

frame2的函數為0xfffffffff2c0 + 8:0x000000000040065c -> <f4+36>
(gdb) x/gx 0xfffffffff2f0+8
0xfffffffff2f8:    0x0000000000400684
(gdb) x/i 0x0000000000400684
   0x400684 <main+28>:       mov w0, #0x0                       // #0

因此frame3的函數為main函數,main函數對應的棧頂為0xfffffffff320

至此推導結束(有興趣的同學可以繼續推導,可以看到libc如何拉起main的過程)

總結:

推棧的關鍵:

  • 當前的現場
  • 熟悉cpu體系架構的開棧的方式

3、實戰講解

現場有如下的core:可以看到,所有的符號找不到,加載了符號表依然不好使,解析不出來實際的調用棧

(gdb) bt
#0  0x0000ffffaeb067bc in ?? () from /lib64/libc.so.6
#1  0x0000aaaad15cf000 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

先看info register,關注x29、x30、sp、pc四個寄存器的值

推導任務棧:

先將sp內容導出:

下圖實際已先將結果標出,我們下面來詳細描述如何推導

pc代表當前執行的函數指令,如果當前指令未開棧,一般情況x30代表上一級的frame調用當前函數的下一條指令,查看匯編,可以反解為如下函數

(gdb) x/i 0xaaaacd3de4fc
   0xaaaacd3de4fc <PGXCNodeConnStr(char const*, int, char const*, char const*, char const*, char const*, int, char const*)+108>: mov x27, x0

找到棧頂函數后,查看該函數的棧操作:

(gdb) x/6i PGXCNodeConnStr
   0xaaaacd3de490 <PGXCNodeConnStr(char const*, int, char const*, char const*, char const*, char const*, int, char const*)>: sub  sp, sp, #0xd0
   0xaaaacd3de494 <PGXCNodeConnStr(char const*, int, char const*, char const*, char const*, char const*, int, char const*)+4>:      stp   x29, x30, [sp,#80]
   0xaaaacd3de498 <PGXCNodeConnStr(char const*, int, char const*, char const*, char const*, char const*, int, char const*)+8>:      add  x29, sp, #0x50

可以看到,上一級的frame存在了當前的sp + 0xd0 - 0x80也就是0xfffec4cebd40 + 0xd0 - 0x80 = 0xfffec4cebd90的地方,而棧底在0xfffec4cebd40+ 0xd0 = 0xfffec4cebe10的地方

因此就找到了下一級的frame對應的棧頂和上一級的LR返回指令,反解,可以得到函數build_node_conn_str

(gdb) x/i 0x0000aaaacd414e08
   0xaaaacd414e08 <build_node_conn_str(Oid, DatabasePool*)+224>:     mov x21, x0

繼續重復上述推導,可以看到這個函數build_node_conn_str開了176字節的棧,

(gdb) x/4i build_node_conn_str
   0xaaaacd414d28 <build_node_conn_str(Oid, DatabasePool*)>:     stp   x29, x30, [sp,#-176]!
   0xaaaacd414d2c <build_node_conn_str(Oid, DatabasePool*)+4>: mov x29, sp

因此繼續用0xfffec4cebe10 + 176 = 0xfffec4cebec0

查看調用者0xfffec4cebe10+8為reload_database_pools

繼續看reload_database_pools

(gdb) x/8i reload_database_pools
   0xaaaacd4225e8 <reload_database_pools(PoolAgent*)>:       sub   sp, sp, #0x1c0
   0xaaaacd4225ec <reload_database_pools(PoolAgent*)+4>:  adrp x5, 0xaaaad15cf000
   0xaaaacd4225f0 <reload_database_pools(PoolAgent*)+8>:   adrp x3, 0xaaaacf0ed000
   0xaaaacd4225f4 <reload_database_pools(PoolAgent*)+12>: adrp x4, 0xaaaaceeed000 <_ZN4llvm18ConvertUTF8toUTF16EPPKhS1_PPtS3_NS_15ConversionFlagsE>
   0xaaaacd4225f8 <reload_database_pools(PoolAgent*)+16>: add  x3, x3, #0x9e0
   0xaaaacd4225fc <reload_database_pools(PoolAgent*)+20>: adrp x1, 0xaaaacf0ee000 <_ZZ25PoolManagerGetConnectionsP4ListS0_E8__func__+24>
   0xaaaacd422600 <reload_database_pools(PoolAgent*)+24>:         stp   x29, x30, [sp,#-96]!

實際開棧0x220字節,因此這一層frame的棧底為0xfffec4cebec0 + 0x220 = 0xfffec4cec0e0

因此得到基本的調用關系的結構如下

以上基本可以夠用來分析問題了,因此不需要再繼續推導

TIPS:arm架構下一般調用都會使用這種指令,

stp x29, x30, [sp,#immediate]! 有嘆號或者無嘆號

因此在每一層的frame都保存了上一層frame的棧頂地址和LR指令,通過準確找到底層的frame 0棧頂后,就可以快速推導出所有的調用關系(紅色虛線圈出來的部分),函數的反解依賴符號表,只要原始的elf文件的symbol段沒有strip掉,是都可以找到對應的函數符號(通過readelf -S查看即可)

找到Frame后,每一層frame里面的內容,結合匯編基本就可以用來推導過程變量了。

以上就是淺析ARM架構下的函數的調用過程的詳細內容,更多關于ARM架構下的函數的調用過程的資料請關注腳本之家其它相關文章!

標簽:隴南 朝陽 荊門 連云港 運城 雞西 遵義 面試通知

巨人網絡通訊聲明:本文標題《淺析ARM架構下的函數的調用過程》,本文關鍵詞  淺析,ARM,架構,下,的,函數,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《淺析ARM架構下的函數的調用過程》相關的同類信息!
  • 本頁收集關于淺析ARM架構下的函數的調用過程的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 少妇一级婬片60分钟一| 胖老太BBwBBWBBW| 成人国产精品秘?免费观看| 我是性瘾者电影| 成人免费看久久久A片| 一个色亚洲| 野外艳谭三级国语香港下载| 免费录像免费录像| 欧美精品久久久久A片2023| 欧美人与禽性猛交狂配双枪| 日本免费人爱做在线观看视频 | 天堂a在线| 十八禁无遮挡无码免费软件 | 下载黄色毛片| 动漫吸乳羞漫画免费| 琪琪久久爱爱一区二区| 国产欧美综合一区二区三区| 禁忌乩伦| 自由 日本语 热 亚洲人| 让我成为你的家人电视剧在线看| 西门庆掀开奶罩揉吮奶头| 下击暴流by假恐龙免费阅读全文无弹窗| 千乐网男女呻吟动态图500期| 伊人免费视频二| 国产色情综合五色丁香小说| 国产精品久久久久久久免牛肉蒲团| 91av视频免费在线观看| 久久这里只有精品首页| 伊人久久大香线蕉综合爱婷婷 | 国产精品久久成人影院| 乱码卡一卡二卡新区在线| 欧美成人爽毛片在线视频| 一级毛片60分钟免费看| 在线视频欧美精品| 丰满大肥婆肥奶大屁股| 中国国产高清一级毛片| 上课 手指伸入h| 夜夜躁日日躁狠狠| 色欲av人妻精品一区二| 欧美精产国品一二三产品测评| 风流岁月之活色生香奇书网下载|