国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

淺析ARM架構下的函數的調用過(guò)程

發(fā)布時(shí)間:2021-08-15 18:37 來(lái)源: 閱讀:0 作者:華為云開(kāi)發(fā)者社區 欄目: 服務(wù)器 歡迎投稿:712375056

目錄

      1、背景知識

      1、ARM64寄存器介紹

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

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

      類(lèi)型1、STP <Xt1>, <Xt2>, [<Xn|SP>],#<imm>

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

      類(lèi)型2、STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!

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

      類(lèi)型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;

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

      2、一個(gè)例子

      熟悉了上面的部分,接下來(lái)我們看一個(gè)實(shí)例:

      C代碼如下:

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

      main\f3\f4\strlen

      我們通過(guò)gdb運行后,可以看到strlen地方會(huì )觸發(fā)SEGFAULT,引發(fā)進(jìn)程掛掉

      上述通過(guò)代碼編譯后,沒(méi)有strip,因此elf文件是帶著(zhù)符號的

      查看運行狀態(tài)(info register):關(guān)注$29、$30、SP、PC四個(gè)寄存器

      一個(gè)核心的思想:CPU執行的是指令而不是C代碼,函數調用和返回實(shí)際是在線(xiàn)程棧上面的壓棧和彈棧的過(guò)程

      接下來(lái)我們來(lái)看上面的調用關(guān)系在當前這個(gè)任務(wù)棧是如何玩的:

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

      以下是推棧的過(guò)程(劃重點(diǎn))

      再回頭來(lái)看之前的匯編:

      main\f3\f4\strlen

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

      函數f3的起始入口匯編:

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

      可以看到,f3函數開(kāi)辟的??臻g為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函數開(kāi)辟的??臻g也是為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

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

      總結:

      推棧的關(guān)鍵:

      • 當前的現場(chǎng)
      • 熟悉cpu體系架構的開(kāi)棧的方式

      3、實(shí)戰講解

      現場(chǎng)有如下的core:可以看到,所有的符號找不到,加載了符號表依然不好使,解析不出來(lái)實(shí)際的調用棧

      (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,關(guān)注x29、x30、sp、pc四個(gè)寄存器的值

      推導任務(wù)棧:

      先將sp內容導出:

      下圖實(shí)際已先將結果標出,我們下面來(lái)詳細描述如何推導

      pc代表當前執行的函數指令,如果當前指令未開(kāi)棧,一般情況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

      繼續重復上述推導,可以看到這個(gè)函數build_node_conn_str開(kāi)了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]!

      實(shí)際開(kāi)棧0x220字節,因此這一層frame的棧底為0xfffec4cebec0 + 0x220 = 0xfffec4cec0e0

      因此得到基本的調用關(guān)系的結構如下

      以上基本可以夠用來(lái)分析問(wèn)題了,因此不需要再繼續推導

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

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

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

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

      以上就是淺析ARM架構下的函數的調用過(guò)程的詳細內容,更多關(guān)于A(yíng)RM架構下的函數的調用過(guò)程的資料請關(guān)注腳本之家其它相關(guān)文章!

      免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

      真人作爱90分钟免费看视频| 在线播放国产精品三级| 最近中文字幕MV高清在线| 性少妇MDMS丰满HDFILM| 亚洲国产精品一区二区美利坚| 少妇被又大又粗又爽毛片久久黑人|