iOS逆向學習筆記4 (函數的本質下)

1. 函數參數超過8個

1.1 源代碼

//參數個數大于8的函數調用
int test(int a, int b, int c, int d,int e,int f,int g, int h, int i) {
    return a + b + c + d + e + f + g + h + i;
}
//在viewDidLoad函數中調用這個測試函數,在調用函數的地方打上斷點,連接真機,運行程序,查看匯編代碼。
- (void)viewDidLoad {
    [super viewDidLoad];
    test(1, 2, 3, 4, 5, 6, 7, 8, 9);
}

1.2 viewDidLoad函數匯編及圖示

  • 匯編代碼分析
-[ViewController viewDidLoad]:
    ;拉伸64字節大小棧空間,棧頂地址保存到sp中
    0x100819df8 <+0>:   sub    sp, sp, #0x40             ; =0x40 
    ;保存寄存器x29,x30的值到棧底的16個字節當中
    0x100819dfc <+4>:   stp    x29, x30, [sp, #0x30]
    ;設置當前函數調用棧的棧底地址(sp寄存器中保存的地址加上#0x30值保存到寄存器x29中)
    0x100819e00 <+8>:   add    x29, sp, #0x30            ; =0x30 
    ;存儲x0寄存器的值到棧底的第1個8字節存儲空間中
    0x100819e04 <+12>:  stur   x0, [x29, #-0x8]
    ;存儲x1寄存器的值到棧底的第2個8字節存儲空間中
    0x100819e08 <+16>:  stur   x1, [x29, #-0x10]
    ;取出靠近棧底的第1個8字節存儲空間的內容到x8寄存器中
    0x100819e0c <+20>:  ldur   x8, [x29, #-0x8]
    ;x9寄存器保存第6個8字節存儲區域的地址
    0x100819e10 <+24>:  add    x9, sp, #0x10             ; =0x10 
    ;將x8寄存器中的值存儲到第6個8字節的存儲區域中
    0x100819e14 <+28>:  str    x8, [sp, #0x10]
    ;執行完后x8寄存器的值為0x100822000
    0x100819e18 <+32>:  adrp   x8, 8
    ;執行完后x8寄存器的值為0x1008222c0
    0x100819e1c <+36>:  add    x8, x8, #0x2c0            ; =0x2c0
    ;加載0x1008222c0處的值(可能為全局變量、全局常量或字符串的值)到x8寄存器中
    0x100819e20 <+40>:  ldr    x8, [x8]
    ;存儲 x8寄存器中的值到第5個8字節的存儲區域中
    0x100819e24 <+44>:  str    x8, [x9, #0x8]
    ;執行后x8寄存器中的值為 0x100822000
    0x100819e28 <+48>:  adrp   x8, 8
    ;執行后x8寄存器中的值為 0x100822298
    0x100819e2c <+52>:  add    x8, x8, #0x298            ; =0x298 
    ;加載寄存器的值到x1寄存器中
    0x100819e30 <+56>:  ldr    x1, [x8]
    ;將x9寄存器中的值存儲到x0寄存器中
    0x100819e34 <+60>:  mov    x0, x9
    ;函數跳轉指令
    0x100819e38 <+64>:  bl     0x10081a4a4               ; symbol stub for: objc_msgSendSuper2
    ;將參數1的值存儲到w0寄存器
    0x100819e3c <+68>:  mov    w0, #0x1
    ;將參數2的值存儲到w1寄存器
    0x100819e40 <+72>:  mov    w1, #0x2
    ;將參數3的值存儲到w2寄存器
    0x100819e44 <+76>:  mov    w2, #0x3
    ;將參數4的值存儲到w3寄存器
    0x100819e48 <+80>:  mov    w3, #0x4
    ;將參數5的值存儲到w4寄存器
    0x100819e4c <+84>:  mov    w4, #0x5
    ;將參數6的值存儲到w5寄存器
    0x100819e50 <+88>:  mov    w5, #0x6
    ;將參數7的值存儲到w6寄存器
    0x100819e54 <+92>:  mov    w6, #0x7
    ;將參數8的值存儲到w7寄存器
    0x100819e58 <+96>:  mov    w7, #0x8
    ;將sp中的棧頂地址存儲到x8寄存器
    0x100819e5c <+100>: mov    x8, sp
    ;將參數9的值存儲到x10寄存器
    0x100819e60 <+104>: mov    w10, #0x9
    ;將w10存儲的值(也就是參數9的值)存儲到第8個八字節的存儲區域
    0x100819e64 <+108>: str    w10, [x8]
   ;跳轉到test函數執行test函數的指令,并將0x100819e6c存儲到lr寄存器中
    0x100819e68 <+112>: bl     0x100819d80               ; test at ViewController.m:27
    ;現場恢復
    0x100819e6c <+116>: ldp    x29, x30, [sp, #0x30]
    ;回收64字節的棧空間
    0x100819e70 <+120>: add    sp, sp, #0x40             ; =0x40
    ;繼續執行lr寄存器中存儲的指令地址的指令
    0x100819e74 <+124>: ret   
  • 跳轉text函數之前viewDidLoad函數以及各寄存器存儲值情況:


1.3 test函數匯編代碼及圖示

  • 匯編代碼分析
_test:
    ;拉伸48字節大小棧空間,棧頂地址保存到sp中
    0x102e41d80 <+0>:   sub    sp, sp, #0x30             ; =0x30 
    ;將viewDidLoad函數調用棧中的參數9的值加載到w8寄存器中
    0x102e41d84 <+4>:   ldr    w8, [sp, #0x30]
    ;將w0中保存的參數1的值存儲到第1個四字節存儲空間
    0x102e41d88 <+8>:   str    w0, [sp, #0x2c]
    ;將w1中保存的參數2的值存儲到第2個四字節存儲空間
    0x102e41d8c <+12>:  str    w1, [sp, #0x28]
    ;將w2中保存的參數3的值存儲到第3個四字節的存儲空間
    0x102e41d90 <+16>:  str    w2, [sp, #0x24]
    ;將w3中保存的參數4的值存儲到第4個四字節的存儲空間
    0x102e41d94 <+20>:  str    w3, [sp, #0x20]
    ;將w4中保存的參數5的值存儲到第5個四字節的存儲空間
    0x102e41d98 <+24>:  str    w4, [sp, #0x1c]
    ;將w5中保存的參數6的值存儲到第6個四字節的存儲空間
    0x102e41d9c <+28>:  str    w5, [sp, #0x18]
    ;將w6中保存的參數7的值存儲到第7個四字節的存儲空間
    0x102e41da0 <+32>:  str    w6, [sp, #0x14]
    ;將w7中保存的參數8的值存儲到第8個四字節的存儲空間
    0x102e41da4 <+36>:  str    w7, [sp, #0x10]
    ;將寄存器w8也就是參數9的值存儲到第9個四字節的存儲空間中
    0x102e41da8 <+40>:  str    w8, [sp, #0xc]
    ;將參數1的值加載到w8寄存器中
    0x102e41dac <+44>:  ldr    w8, [sp, #0x2c]
    ;將參數2的值加載到w9寄存器中
    0x102e41db0 <+48>:  ldr    w9, [sp, #0x28]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41db4 <+52>:  add    w8, w8, w9
    ;將參數3的值加載到w9寄存器中
    0x102e41db8 <+56>:  ldr    w9, [sp, #0x24]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41dbc <+60>:  add    w8, w8, w9
    ;將參數4的值加載到w9寄存器中
    0x102e41dc0 <+64>:  ldr    w9, [sp, #0x20]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41dc4 <+68>:  add    w8, w8, w9
    ;將參數5的值加載到w9寄存器中
    0x102e41dc8 <+72>:  ldr    w9, [sp, #0x1c]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41dcc <+76>:  add    w8, w8, w9
    ;將參數6的值加載到w9寄存器中
    0x102e41dd0 <+80>:  ldr    w9, [sp, #0x18]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41dd4 <+84>:  add    w8, w8, w9
    ;將參數7的值加載到w9寄存器中
    0x102e41dd8 <+88>:  ldr    w9, [sp, #0x14]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41ddc <+92>:  add    w8, w8, w9
    ;將參數8的值加載到w9寄存器中
    0x102e41de0 <+96>:  ldr    w9, [sp, #0x10]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
    0x102e41de4 <+100>: add    w8, w8, w9
    ;將參數9的值加載到w9寄存器中
    0x102e41de8 <+104>: ldr    w9, [sp, #0xc]
    ;將w8寄存器中的值與w9寄存器中的值相加存儲到w0寄存器中
    0x102e41dec <+108>: add    w0, w8, w9
    ;回收48字節大小的函數調用棧空間
    0x102e41df0 <+112>: add    sp, sp, #0x30             ; =0x30 
    0x102e41df4 <+116>: ret    
  • text函數return之前棧空間以及寄存器存儲值情況


2. 函數中的局部變量以及函數中調用其他函數

2.1 源代碼

//測試函數B
int testB(int a, int b) {
    return a + b;
}
//測試函數A
int testA(int a, int b) {
    
    int c = 10 + testB(a, b);
    int d = 12;
    
    return c + d;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //調用測試函數A
    testA(1, 2);
}

2.2 viewDidLoad函數部分匯編

  • 部分匯編代碼分析
    ;將testA函數參數1的值存儲到w0寄存器
    0x104cb1e60 <+68>: mov    w0, #0x1
    ;將testA函數參數2的值存儲到w1寄存器
    0x104cb1e64 <+72>: mov    w1, #0x2
    ;跳轉到testA函數繼續執行testA函數的指令,并將0x104cb1e6c的值存儲到lr寄存器,以便做現場保護
    0x104cb1e68 <+76>: bl     0x104cb1dd4               ; testA at ViewController.m:31
    0x104cb1e6c <+80>: ldp    x29, x30, [sp, #0x20]
    0x104cb1e70 <+84>: add    sp, sp, #0x30             ; =0x30 
    0x104cb1e74 <+88>: ret   

2.3 testA函數匯編代碼

  • 匯編代碼解析
_testA:
    ;拉伸32字節大小的棧空間
    0x104cb1dd4 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    ;將x29(fp)寄存器存儲的值以及x30(lr)寄存器的值存儲到前兩個8字節空間中
    0x104cb1dd8 <+4>:  stp    x29, x30, [sp, #0x10]
    ;x29寄存器保存當前棧的棧底地址
    0x104cb1ddc <+8>:  add    x29, sp, #0x10            ; =0x10 
    ;將w0寄存器中的參數1的值存儲到棧底后第1個4字節的存儲空間中
    0x104cb1de0 <+12>: stur   w0, [x29, #-0x4]
    ;將w1寄存器中的參數2的值存儲到棧底后第2個4字節的存儲空間中
    0x104cb1de4 <+16>: str    w1, [sp, #0x8]
    ;取出參數1的值載入到w0寄存器中
    0x104cb1de8 <+20>: ldur   w0, [x29, #-0x4]
    ;取出參數2的值載入到w1寄存器中
    0x104cb1dec <+24>: ldr    w1, [sp, #0x8]
    ;跳轉到testB函數執行testB函數中的指令并將0x104cb1df4保存到lr寄存器中(現場保護,調用完testB函數可以回來繼續執行testA中的代碼)
    0x104cb1df0 <+28>: bl     0x104cb1db4               ; testB at ViewController.m:27
    ;將testB函數執行后的返回值加上10,結果存儲到w8寄存器
    0x104cb1df4 <+32>: add    w8, w0, #0xa              ; =0xa 
    ;將w8寄存器的值(也就是局部變量c的值)存儲到棧空間中倒數第2個4字節空間中,將局部變量c的值保護起來,以防后面使用w8寄存器的時候,將局部變量c的值覆蓋掉
    0x104cb1df8 <+36>: str    w8, [sp, #0x4]
    ;將局部變量d的值(12)存儲到w8寄存器中
    0x104cb1dfc <+40>: mov    w8, #0xc
    ;將w8寄存器的值(也就是局部變量d的值)存儲到倒數第1個4字節的存儲空間中
    0x104cb1e00 <+44>: str    w8, [sp]
    ;將局部變量c的值加載到w8寄存器中
    0x104cb1e04 <+48>: ldr    w8, [sp, #0x4]
    ;將局部變量d的值加載到w9寄存器中
    0x104cb1e08 <+52>: ldr    w9, [sp]
    ;將w8寄存器中的值(局部變量c的值)與w9寄存器中的值(局部變量d的值)相加,結果存儲到寄存器w0中
    0x104cb1e0c <+56>: add    w0, w8, w9
    ;現場還原,獲取上viewDidLoad函數的棧底地址存儲到x29寄存器,獲取viewDidLoad函數調用testA后的下一條指令地址存儲到x30寄存器
    0x104cb1e10 <+60>: ldp    x29, x30, [sp, #0x10]
    ;回收32字節大小的函數調用棧空間
    0x104cb1e14 <+64>: add    sp, sp, #0x20             ; =0x20 
    ;函數執行完畢,繼續執行lr所保存的指令地址的指令
    0x104cb1e18 <+68>: ret 

2.4 testB函數匯編代碼

_testB:
    ;拉伸16字節的棧空間,sp寄存器保存棧頂地址
    0x104cb1db4 <+0>:  sub    sp, sp, #0x10             ; =0x10 
    ;將w0(_testB函數參數1)中的值存儲到第1個四字節空間中
    0x104cb1db8 <+4>:  str    w0, [sp, #0xc]
    ;將w2(_testB函數參數2)中的值存儲到第2個四字節空間中
    0x104cb1dbc <+8>:  str    w1, [sp, #0x8]
    ;將參數1中的值加載到w8寄存器中
    0x104cb1dc0 <+12>: ldr    w8, [sp, #0xc]
    ;將參數2中的值加載到w9寄存器中
    0x104cb1dc4 <+16>: ldr    w9, [sp, #0x8]
    ;將參數1和參數2的值相加,結果保存到w0寄存器中
    0x104cb1dc8 <+20>: add    w0, w8, w9
    ;回收開辟的16字節棧空間
    0x104cb1dcc <+24>: add    sp, sp, #0x10             ; =0x10
    ;函數調用結束,執行lr寄存器保存的指令地址的指令
    0x104cb1dd0 <+28>: ret    

3. 函數返回值等于16字節時

3.1 源代碼

//定義一個結構體
typedef struct TestStruct {
    int a;
    int b;
    int c;
    int d;
} TestStruct;

//testB函數定義一個結構體并返回
TestStruct testB(int a, int b) {
    TestStruct testStr = { a, b, 7, 4 };
    
    return testStr;
}

//testA函數調用testB函數
int testA(int a, int b) {
    TestStruct testStruct = testB(a, b);
    int c = 10;
    int d = 12;
    
    return c + d + testStruct.d;
}

//viewDidLoad函數調用testA函數,上面的viewDidLoad匯編已經分析過了,就不分析了。
- (void)viewDidLoad {
    [super viewDidLoad];
    testA(1, 2);
}

3.2 testA函數匯編代碼分析及圖示

 testA:
    ;拉伸48字節的棧空間,sp寄存器保存棧頂地址
    0x102549dc4 <+0>:  sub    sp, sp, #0x30             ; =0x30 
    ;存儲x29(fp)、x30(lr)寄存器的值在靠近棧底的2個8字節空間中
    0x102549dc8 <+4>:  stp    x29, x30, [sp, #0x20]
    ;將當前棧底的地址保存到x29寄存器中
    0x102549dcc <+8>:  add    x29, sp, #0x20            ; =0x20 
    ;將testA函數參數1的值存儲到靠近棧底的第1個4字節空間中
    0x102549dd0 <+12>: stur   w0, [x29, #-0x4]
    ;將testA函數參數2的值存儲到靠近棧底的第2個4字節空間中
    0x102549dd4 <+16>: stur   w1, [x29, #-0x8]
    ;加載參數1的值到w0寄存器中
    0x102549dd8 <+20>: ldur   w0, [x29, #-0x4]
    ;加載參數2的值到w1寄存器中
    0x102549ddc <+24>: ldur   w1, [x29, #-0x8]
    ;跳轉到testB中執行匯編指令
    0x102549de0 <+28>: bl     0x102549d88               ; testB at ViewController.m:34
    ;將testB函數調用的返回值(16字節)存儲到棧空間中
    0x102549de4 <+32>: str    x0, [sp, #0x8]
    0x102549de8 <+36>: str    x1, [sp, #0x10]
    ;將10字面量的值(也就是局部變量c)存儲到w8寄存器
    0x102549dec <+40>: mov    w8, #0xa
    ;將w8寄存器中的值存儲到第6個8字節空間的第1個4字節空間中
    0x102549df0 <+44>: str    w8, [sp, #0x4]
    ;將12字面量的值(也就是局部變量d)存儲到w8寄存器
    0x102549df4 <+48>: mov    w8, #0xc
    ;將w8寄存器中的值存儲到第6個8字節空間的第2個4字節空間中
    0x102549df8 <+52>: str    w8, [sp]
    ;獲取局部變量c的值加載到w8寄存器
    0x102549dfc <+56>: ldr    w8, [sp, #0x4]
     ;獲取局部變量d的值加載到w9寄存器
    0x102549e00 <+60>: ldr    w9, [sp]
    ;將局部變量c的值與局部變量d的值相加,結果存儲到w8寄存器
    0x102549e04 <+64>: add    w8, w8, w9
    ;將結構體變量的成員變量d的值加載到w9寄存器
    0x102549e08 <+68>: ldr    w9, [sp, #0x14]
    ;將局部變量c的值與局部變量d的值相加獲取的值與結構體變量的成員變量d的值相加,結果存儲到w0寄存器
    0x102549e0c <+72>: add    w0, w8, w9
    ;函數調用結束,恢復現場(獲取上個函數的棧底地址保存到x29寄存器,以及下個指令執行的地址保存到lr寄存器)
    0x102549e10 <+76>: ldp    x29, x30, [sp, #0x20]
    ;回收48個字節的棧空間,sp寄存器保存viewDidLoad的函數調用棧的棧頂地址
    0x102549e14 <+80>: add    sp, sp, #0x30             ; =0x30 
   ;執行lr寄存器所保存的指令地址的指令
    0x102549e18 <+84>: ret    
testA函數返回之前其棧空間圖示

3.3 testB函數匯編分析及圖示

testB:
    ;拉伸32字節的棧空間,sp寄存器保存棧頂地址
    0x102549d88 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    ;將testB函數的參數1的值存儲到第3個八字節的靠近棧底的4字節空間中
    0x102549d8c <+4>:  str    w0, [sp, #0xc]
    ;將testB函數的參數2的值存儲到第3個八字節的第2個4字節空間中
    0x102549d90 <+8>:  str    w1, [sp, #0x8]
    ;加載參數1的值到w8寄存器中
    0x102549d94 <+12>: ldr    w8, [sp, #0xc]
    ;存儲參數1的值到第2個八字節的第2個4字節空間中
    0x102549d98 <+16>: str    w8, [sp, #0x10]
    ;加載參數2的值到w8寄存器中
    0x102549d9c <+20>: ldr    w8, [sp, #0x8]
    ;存儲參數1的值到第2個八字節的第1個4字節空間中
    0x102549da0 <+24>: str    w8, [sp, #0x14]
    ;將7的值加載到w8寄存器中
    0x102549da4 <+28>: mov    w8, #0x7
    ;存儲w8寄存器中的值到第2個八字節的第2個4字節空間中
    0x102549da8 <+32>: str    w8, [sp, #0x18]
    ;將4的值加載到w8寄存器中
    0x102549dac <+36>: mov    w8, #0x4
    ;存儲w8寄存器中的值到第2個八字節的第1個4字節空間中
    0x102549db0 <+40>: str    w8, [sp, #0x1c]
    ;將結構體中的a,b的值存儲到x0寄存器中
    0x102549db4 <+44>: ldr    x0, [sp, #0x10]
    ;將結構體中的c,d的值存儲到x1寄存器中
    0x102549db8 <+48>: ldr    x1, [sp, #0x18]
    ;回收棧空間
    0x102549dbc <+52>: add    sp, sp, #0x20             ; =0x20 
    ;執行lr寄存器中存儲的指令地址的指令
    0x102549dc0 <+56>: ret    
testB函數返回之前其棧空間圖示

4. 函數返回值大于16字節時

4.1 源代碼

typedef struct TestStruct {
    int a;
    int b;
    int c;
    int d;
    int e;
} TestStruct;


TestStruct testB(int a, int b) {
    TestStruct testStr = { a, b, 7, 4, 20 };
    
    return testStr;
}

int testA(int a, int b) {
    TestStruct testStruct = testB(a, b);
    int c = 10;
    int d = 12;
    
    return c + d + testStruct.e;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    testA(1, 2);
}

4.2 testA函數匯編分析

testA:
    ;拉伸64字節的棧空間,sp寄存器保存棧頂地址
    0x102ad5dc8 <+0>:  sub    sp, sp, #0x40             ; =0x40 
    ;存儲x29(fp)、x30(lr)寄存器的值在靠近棧底的2個8字節空間中
    0x102ad5dcc <+4>:  stp    x29, x30, [sp, #0x30]
    ;將當前棧底的地址保存到x29寄存器中
    0x102ad5dd0 <+8>:  add    x29, sp, #0x30            ; =0x30 
    ;將testA函數的參數1的值存儲到第1個八字節的第1個4字節空間中
    0x102ad5dd4 <+12>: stur   w0, [x29, #-0x4]
    ;將testA函數的參數1的值存儲到第1個八字節的第2個4字節空間中
    0x102ad5dd8 <+16>: stur   w1, [x29, #-0x8]
    ;將testA函數的參數1的的值加載到w0寄存器中
    0x102ad5ddc <+20>: ldur   w0, [x29, #-0x4]
    ;將testA函數的參數2的的值加載到w1寄存器中
    0x102ad5de0 <+24>: ldur   w1, [x29, #-0x8]
    ;x8寄存器保存第6個8字節空間的第1個四字節空間地址
    0x102ad5de4 <+28>: add    x8, sp, #0x14             ; =0x14 
    ;跳轉到testB函數中執行匯編指令
    0x102ad5de8 <+32>: bl     0x102ad5d8c               ; testB at ViewController.m:35
    ;將局部變量c(值為10)存儲到w9寄存器
    0x102ad5dec <+36>: mov    w9, #0xa
    ;將局部變量c的值存儲到第6個8字節的第2個4字節空間中
    0x102ad5df0 <+40>: str    w9, [sp, #0x10]
    ;將局部變量d(值為12)存儲到w9寄存器
    0x102ad5df4 <+44>: mov    w9, #0xc
    ;將局部變量d的值存儲到第7個8字節的第1個4字節空間中
    0x102ad5df8 <+48>: str    w9, [sp, #0xc]
    ;加載局部變量c的值到w9寄存器中
    0x102ad5dfc <+52>: ldr    w9, [sp, #0x10]
    ;加載局部變量d的值到w10寄存器中
    0x102ad5e00 <+56>: ldr    w10, [sp, #0xc]
    ;局部變量c的值加上局部變量d的值,結果存儲到w9寄存器中
    0x102ad5e04 <+60>: add    w9, w9, w10
    ;加載結構體變量testStruct的結構體的成員變量e的值(20)到寄存器w10中
    0x102ad5e08 <+64>: ldr    w10, [sp, #0x24]
    ;局部變量c的值加上局部變量d的值再加上結構體變量testStruct的結構體的成員變量e的值,結果存儲到w0寄存器中,作為函數返回值
    0x102ad5e0c <+68>: add    w0, w9, w10
    ;現場還原
    0x102ad5e10 <+72>: ldp    x29, x30, [sp, #0x30]
    ;回收棧空間
    0x102ad5e14 <+76>: add    sp, sp, #0x40             ; =0x40 
    ;執行lr寄存器保存的指令地址的指令
    0x102ad5e18 <+80>: ret    
返回值大于16字節

4.3 testB函數匯編分析

testB:
    ;拉伸16字節的棧空間,sp寄存器保存棧頂地址
    0x102ad5d8c <+0>:  sub    sp, sp, #0x10             ; =0x10 
    ;將testB函數的參數1的值存儲到第1個8字節空間中第1個4字節空間中
    0x102ad5d90 <+4>:  str    w0, [sp, #0xc]
    ;將testB函數的參數2的值存儲到第1個8字節空間中第2個4字節空間中
    0x102ad5d94 <+8>:  str    w1, [sp, #0x8]
    ;將testB函數的參數1的值加載到w9寄存器中
    0x102ad5d98 <+12>: ldr    w9, [sp, #0xc]
     ;將w9中的值存儲到x8寄存器存儲地址第1個4字節空間中
    0x102ad5d9c <+16>: str    w9, [x8]
    ;將testB函數的參數2的值加載到w9寄存器中
    0x102ad5da0 <+20>: ldr    w9, [sp, #0x8]
    ;將w9中的值存儲到x8寄存器存儲地址第2個4字節空間中
    0x102ad5da4 <+24>: str    w9, [x8, #0x4]
    ;將7的值存儲到w9寄存器中
    0x102ad5da8 <+28>: mov    w9, #0x7
    ;將w9中的值存儲到x8寄存器存儲地址第3個4字節空間中
    0x102ad5dac <+32>: str    w9, [x8, #0x8]
    ;將4的值存儲到w9寄存器中
    0x102ad5db0 <+36>: mov    w9, #0x4
    ;將w9中的值存儲到x8寄存器存儲地址第4個4字節空間中
    0x102ad5db4 <+40>: str    w9, [x8, #0xc]
    ;將20的值存儲到w9寄存器中
    0x102ad5db8 <+44>: mov    w9, #0x14
    ;將w9中的值存儲到x8寄存器存儲地址第4個4字節空間中
    0x102ad5dbc <+48>: str    w9, [x8, #0x10]
    ;回收16字節空間棧
    0x102ad5dc0 <+52>: add    sp, sp, #0x10             ; =0x10 
    ;執行lr寄存器所保存的指令地址的地址
    0x102ad5dc4 <+56>: ret    

5.總結

由以上的匯編以及圖示,我們可以得到以下結論:

  • 在viewDidLoad函數調用test函數時,如果testA函數中的參數不超過8個,就會在viewDidLoad函數的匯編代碼中將test的參數按位置對應一一存儲到w0到w8寄存器中。
  • 在viewDidLoad函數調用testB函數時,如果test函數中的參數超過了8個,就會在viewDidLoad函數的匯編代碼中將test的參數按位置對應一一存儲到w0到w8寄存器中,然后剩余的參數會保存到viewDidLoad的棧空間中,然后在test函數體中的代碼執行之前會將w0到w8寄存器中的參數值從棧底的位置地址向下依次進行存儲,然后再通過寄存器獲取viewDidLoad中保存的參數9的值存儲到test函數的調用棧中
  • 當在一個函數中調用了其他函數時,一定要在這個函數中保存寄存器x29、x30寄存器的值,做好現場保護,然后在ret指令結束前再恢復之前存儲的x29、x30寄存器的值,做好現場恢復。
  • 函數中的返回值是存儲到其棧空間中的。
  • 當testA函數在調用testB函數時,如果testB函數值大小為8個字節或以下,就會在testB函數ret指令執行前將函數返回值保存到x0寄存器中,然后繼續執行testA函數代碼時,將x0中的返回值存儲到testA函數的棧空間中。
  • 當testA函數在調用testB函數時,如果testB函數值大小為8個字節以上16個字節及以下,就會在testB函數ret指令執行前將函數返回值保存到x0, x1寄存器中,然后繼續執行testA函數代碼時,將x0、x1中的返回值存儲到testA函數的棧空間中。
  • 當testA函數在調用testB函數時,如果testB函數值大小為16個字節或以上,就會在testA函數調用棧中開辟一塊區域,使其大小能存儲testB函數的返回值,并使用一個寄存器存儲這塊區域的最低地址位,然后在testB函數ret指令調用之前,依次將返回值的數據存儲到這塊區域中(由低地址向高地址存儲)。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容