1. 函數(shù)參數(shù)超過8個
1.1 源代碼
//參數(shù)個數(shù)大于8的函數(shù)調(diào)用
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函數(shù)中調(diào)用這個測試函數(shù),在調(diào)用函數(shù)的地方打上斷點,連接真機,運行程序,查看匯編代碼。
- (void)viewDidLoad {
[super viewDidLoad];
test(1, 2, 3, 4, 5, 6, 7, 8, 9);
}
1.2 viewDidLoad函數(shù)匯編及圖示
- 匯編代碼分析
-[ViewController viewDidLoad]:
;拉伸64字節(jié)大小??臻g,棧頂?shù)刂繁4娴絪p中
0x100819df8 <+0>: sub sp, sp, #0x40 ; =0x40
;保存寄存器x29,x30的值到棧底的16個字節(jié)當中
0x100819dfc <+4>: stp x29, x30, [sp, #0x30]
;設(shè)置當前函數(shù)調(diào)用棧的棧底地址(sp寄存器中保存的地址加上#0x30值保存到寄存器x29中)
0x100819e00 <+8>: add x29, sp, #0x30 ; =0x30
;存儲x0寄存器的值到棧底的第1個8字節(jié)存儲空間中
0x100819e04 <+12>: stur x0, [x29, #-0x8]
;存儲x1寄存器的值到棧底的第2個8字節(jié)存儲空間中
0x100819e08 <+16>: stur x1, [x29, #-0x10]
;取出靠近棧底的第1個8字節(jié)存儲空間的內(nèi)容到x8寄存器中
0x100819e0c <+20>: ldur x8, [x29, #-0x8]
;x9寄存器保存第6個8字節(jié)存儲區(qū)域的地址
0x100819e10 <+24>: add x9, sp, #0x10 ; =0x10
;將x8寄存器中的值存儲到第6個8字節(jié)的存儲區(qū)域中
0x100819e14 <+28>: str x8, [sp, #0x10]
;執(zhí)行完后x8寄存器的值為0x100822000
0x100819e18 <+32>: adrp x8, 8
;執(zhí)行完后x8寄存器的值為0x1008222c0
0x100819e1c <+36>: add x8, x8, #0x2c0 ; =0x2c0
;加載0x1008222c0處的值(可能為全局變量、全局常量或字符串的值)到x8寄存器中
0x100819e20 <+40>: ldr x8, [x8]
;存儲 x8寄存器中的值到第5個8字節(jié)的存儲區(qū)域中
0x100819e24 <+44>: str x8, [x9, #0x8]
;執(zhí)行后x8寄存器中的值為 0x100822000
0x100819e28 <+48>: adrp x8, 8
;執(zhí)行后x8寄存器中的值為 0x100822298
0x100819e2c <+52>: add x8, x8, #0x298 ; =0x298
;加載寄存器的值到x1寄存器中
0x100819e30 <+56>: ldr x1, [x8]
;將x9寄存器中的值存儲到x0寄存器中
0x100819e34 <+60>: mov x0, x9
;函數(shù)跳轉(zhuǎn)指令
0x100819e38 <+64>: bl 0x10081a4a4 ; symbol stub for: objc_msgSendSuper2
;將參數(shù)1的值存儲到w0寄存器
0x100819e3c <+68>: mov w0, #0x1
;將參數(shù)2的值存儲到w1寄存器
0x100819e40 <+72>: mov w1, #0x2
;將參數(shù)3的值存儲到w2寄存器
0x100819e44 <+76>: mov w2, #0x3
;將參數(shù)4的值存儲到w3寄存器
0x100819e48 <+80>: mov w3, #0x4
;將參數(shù)5的值存儲到w4寄存器
0x100819e4c <+84>: mov w4, #0x5
;將參數(shù)6的值存儲到w5寄存器
0x100819e50 <+88>: mov w5, #0x6
;將參數(shù)7的值存儲到w6寄存器
0x100819e54 <+92>: mov w6, #0x7
;將參數(shù)8的值存儲到w7寄存器
0x100819e58 <+96>: mov w7, #0x8
;將sp中的棧頂?shù)刂反鎯Φ絰8寄存器
0x100819e5c <+100>: mov x8, sp
;將參數(shù)9的值存儲到x10寄存器
0x100819e60 <+104>: mov w10, #0x9
;將w10存儲的值(也就是參數(shù)9的值)存儲到第8個八字節(jié)的存儲區(qū)域
0x100819e64 <+108>: str w10, [x8]
;跳轉(zhuǎn)到test函數(shù)執(zhí)行test函數(shù)的指令,并將0x100819e6c存儲到lr寄存器中
0x100819e68 <+112>: bl 0x100819d80 ; test at ViewController.m:27
;現(xiàn)場恢復
0x100819e6c <+116>: ldp x29, x30, [sp, #0x30]
;回收64字節(jié)的棧空間
0x100819e70 <+120>: add sp, sp, #0x40 ; =0x40
;繼續(xù)執(zhí)行l(wèi)r寄存器中存儲的指令地址的指令
0x100819e74 <+124>: ret
-
跳轉(zhuǎn)text函數(shù)之前viewDidLoad函數(shù)以及各寄存器存儲值情況:
1.3 test函數(shù)匯編代碼及圖示
- 匯編代碼分析
_test:
;拉伸48字節(jié)大小??臻g,棧頂?shù)刂繁4娴絪p中
0x102e41d80 <+0>: sub sp, sp, #0x30 ; =0x30
;將viewDidLoad函數(shù)調(diào)用棧中的參數(shù)9的值加載到w8寄存器中
0x102e41d84 <+4>: ldr w8, [sp, #0x30]
;將w0中保存的參數(shù)1的值存儲到第1個四字節(jié)存儲空間
0x102e41d88 <+8>: str w0, [sp, #0x2c]
;將w1中保存的參數(shù)2的值存儲到第2個四字節(jié)存儲空間
0x102e41d8c <+12>: str w1, [sp, #0x28]
;將w2中保存的參數(shù)3的值存儲到第3個四字節(jié)的存儲空間
0x102e41d90 <+16>: str w2, [sp, #0x24]
;將w3中保存的參數(shù)4的值存儲到第4個四字節(jié)的存儲空間
0x102e41d94 <+20>: str w3, [sp, #0x20]
;將w4中保存的參數(shù)5的值存儲到第5個四字節(jié)的存儲空間
0x102e41d98 <+24>: str w4, [sp, #0x1c]
;將w5中保存的參數(shù)6的值存儲到第6個四字節(jié)的存儲空間
0x102e41d9c <+28>: str w5, [sp, #0x18]
;將w6中保存的參數(shù)7的值存儲到第7個四字節(jié)的存儲空間
0x102e41da0 <+32>: str w6, [sp, #0x14]
;將w7中保存的參數(shù)8的值存儲到第8個四字節(jié)的存儲空間
0x102e41da4 <+36>: str w7, [sp, #0x10]
;將寄存器w8也就是參數(shù)9的值存儲到第9個四字節(jié)的存儲空間中
0x102e41da8 <+40>: str w8, [sp, #0xc]
;將參數(shù)1的值加載到w8寄存器中
0x102e41dac <+44>: ldr w8, [sp, #0x2c]
;將參數(shù)2的值加載到w9寄存器中
0x102e41db0 <+48>: ldr w9, [sp, #0x28]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41db4 <+52>: add w8, w8, w9
;將參數(shù)3的值加載到w9寄存器中
0x102e41db8 <+56>: ldr w9, [sp, #0x24]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41dbc <+60>: add w8, w8, w9
;將參數(shù)4的值加載到w9寄存器中
0x102e41dc0 <+64>: ldr w9, [sp, #0x20]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41dc4 <+68>: add w8, w8, w9
;將參數(shù)5的值加載到w9寄存器中
0x102e41dc8 <+72>: ldr w9, [sp, #0x1c]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41dcc <+76>: add w8, w8, w9
;將參數(shù)6的值加載到w9寄存器中
0x102e41dd0 <+80>: ldr w9, [sp, #0x18]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41dd4 <+84>: add w8, w8, w9
;將參數(shù)7的值加載到w9寄存器中
0x102e41dd8 <+88>: ldr w9, [sp, #0x14]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41ddc <+92>: add w8, w8, w9
;將參數(shù)8的值加載到w9寄存器中
0x102e41de0 <+96>: ldr w9, [sp, #0x10]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w8寄存器中
0x102e41de4 <+100>: add w8, w8, w9
;將參數(shù)9的值加載到w9寄存器中
0x102e41de8 <+104>: ldr w9, [sp, #0xc]
;將w8寄存器中的值與w9寄存器中的值相加存儲到w0寄存器中
0x102e41dec <+108>: add w0, w8, w9
;回收48字節(jié)大小的函數(shù)調(diào)用??臻g
0x102e41df0 <+112>: add sp, sp, #0x30 ; =0x30
0x102e41df4 <+116>: ret
-
text函數(shù)return之前棧空間以及寄存器存儲值情況
2. 函數(shù)中的局部變量以及函數(shù)中調(diào)用其他函數(shù)
2.1 源代碼
//測試函數(shù)B
int testB(int a, int b) {
return a + b;
}
//測試函數(shù)A
int testA(int a, int b) {
int c = 10 + testB(a, b);
int d = 12;
return c + d;
}
- (void)viewDidLoad {
[super viewDidLoad];
//調(diào)用測試函數(shù)A
testA(1, 2);
}
2.2 viewDidLoad函數(shù)部分匯編
- 部分匯編代碼分析
;將testA函數(shù)參數(shù)1的值存儲到w0寄存器
0x104cb1e60 <+68>: mov w0, #0x1
;將testA函數(shù)參數(shù)2的值存儲到w1寄存器
0x104cb1e64 <+72>: mov w1, #0x2
;跳轉(zhuǎn)到testA函數(shù)繼續(xù)執(zhí)行testA函數(shù)的指令,并將0x104cb1e6c的值存儲到lr寄存器,以便做現(xiàn)場保護
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函數(shù)匯編代碼
- 匯編代碼解析
_testA:
;拉伸32字節(jié)大小的棧空間
0x104cb1dd4 <+0>: sub sp, sp, #0x20 ; =0x20
;將x29(fp)寄存器存儲的值以及x30(lr)寄存器的值存儲到前兩個8字節(jié)空間中
0x104cb1dd8 <+4>: stp x29, x30, [sp, #0x10]
;x29寄存器保存當前棧的棧底地址
0x104cb1ddc <+8>: add x29, sp, #0x10 ; =0x10
;將w0寄存器中的參數(shù)1的值存儲到棧底后第1個4字節(jié)的存儲空間中
0x104cb1de0 <+12>: stur w0, [x29, #-0x4]
;將w1寄存器中的參數(shù)2的值存儲到棧底后第2個4字節(jié)的存儲空間中
0x104cb1de4 <+16>: str w1, [sp, #0x8]
;取出參數(shù)1的值載入到w0寄存器中
0x104cb1de8 <+20>: ldur w0, [x29, #-0x4]
;取出參數(shù)2的值載入到w1寄存器中
0x104cb1dec <+24>: ldr w1, [sp, #0x8]
;跳轉(zhuǎn)到testB函數(shù)執(zhí)行testB函數(shù)中的指令并將0x104cb1df4保存到lr寄存器中(現(xiàn)場保護,調(diào)用完testB函數(shù)可以回來繼續(xù)執(zhí)行testA中的代碼)
0x104cb1df0 <+28>: bl 0x104cb1db4 ; testB at ViewController.m:27
;將testB函數(shù)執(zhí)行后的返回值加上10,結(jié)果存儲到w8寄存器
0x104cb1df4 <+32>: add w8, w0, #0xa ; =0xa
;將w8寄存器的值(也就是局部變量c的值)存儲到棧空間中倒數(shù)第2個4字節(jié)空間中,將局部變量c的值保護起來,以防后面使用w8寄存器的時候,將局部變量c的值覆蓋掉
0x104cb1df8 <+36>: str w8, [sp, #0x4]
;將局部變量d的值(12)存儲到w8寄存器中
0x104cb1dfc <+40>: mov w8, #0xc
;將w8寄存器的值(也就是局部變量d的值)存儲到倒數(shù)第1個4字節(jié)的存儲空間中
0x104cb1e00 <+44>: str w8, [sp]
;將局部變量c的值加載到w8寄存器中
0x104cb1e04 <+48>: ldr w8, [sp, #0x4]
;將局部變量d的值加載到w9寄存器中
0x104cb1e08 <+52>: ldr w9, [sp]
;將w8寄存器中的值(局部變量c的值)與w9寄存器中的值(局部變量d的值)相加,結(jié)果存儲到寄存器w0中
0x104cb1e0c <+56>: add w0, w8, w9
;現(xiàn)場還原,獲取上viewDidLoad函數(shù)的棧底地址存儲到x29寄存器,獲取viewDidLoad函數(shù)調(diào)用testA后的下一條指令地址存儲到x30寄存器
0x104cb1e10 <+60>: ldp x29, x30, [sp, #0x10]
;回收32字節(jié)大小的函數(shù)調(diào)用棧空間
0x104cb1e14 <+64>: add sp, sp, #0x20 ; =0x20
;函數(shù)執(zhí)行完畢,繼續(xù)執(zhí)行l(wèi)r所保存的指令地址的指令
0x104cb1e18 <+68>: ret
2.4 testB函數(shù)匯編代碼
_testB:
;拉伸16字節(jié)的??臻g,sp寄存器保存棧頂?shù)刂? 0x104cb1db4 <+0>: sub sp, sp, #0x10 ; =0x10
;將w0(_testB函數(shù)參數(shù)1)中的值存儲到第1個四字節(jié)空間中
0x104cb1db8 <+4>: str w0, [sp, #0xc]
;將w2(_testB函數(shù)參數(shù)2)中的值存儲到第2個四字節(jié)空間中
0x104cb1dbc <+8>: str w1, [sp, #0x8]
;將參數(shù)1中的值加載到w8寄存器中
0x104cb1dc0 <+12>: ldr w8, [sp, #0xc]
;將參數(shù)2中的值加載到w9寄存器中
0x104cb1dc4 <+16>: ldr w9, [sp, #0x8]
;將參數(shù)1和參數(shù)2的值相加,結(jié)果保存到w0寄存器中
0x104cb1dc8 <+20>: add w0, w8, w9
;回收開辟的16字節(jié)??臻g
0x104cb1dcc <+24>: add sp, sp, #0x10 ; =0x10
;函數(shù)調(diào)用結(jié)束,執(zhí)行l(wèi)r寄存器保存的指令地址的指令
0x104cb1dd0 <+28>: ret
3. 函數(shù)返回值等于16字節(jié)時
3.1 源代碼
//定義一個結(jié)構(gòu)體
typedef struct TestStruct {
int a;
int b;
int c;
int d;
} TestStruct;
//testB函數(shù)定義一個結(jié)構(gòu)體并返回
TestStruct testB(int a, int b) {
TestStruct testStr = { a, b, 7, 4 };
return testStr;
}
//testA函數(shù)調(diào)用testB函數(shù)
int testA(int a, int b) {
TestStruct testStruct = testB(a, b);
int c = 10;
int d = 12;
return c + d + testStruct.d;
}
//viewDidLoad函數(shù)調(diào)用testA函數(shù),上面的viewDidLoad匯編已經(jīng)分析過了,就不分析了。
- (void)viewDidLoad {
[super viewDidLoad];
testA(1, 2);
}
3.2 testA函數(shù)匯編代碼分析及圖示
testA:
;拉伸48字節(jié)的棧空間,sp寄存器保存棧頂?shù)刂? 0x102549dc4 <+0>: sub sp, sp, #0x30 ; =0x30
;存儲x29(fp)、x30(lr)寄存器的值在靠近棧底的2個8字節(jié)空間中
0x102549dc8 <+4>: stp x29, x30, [sp, #0x20]
;將當前棧底的地址保存到x29寄存器中
0x102549dcc <+8>: add x29, sp, #0x20 ; =0x20
;將testA函數(shù)參數(shù)1的值存儲到靠近棧底的第1個4字節(jié)空間中
0x102549dd0 <+12>: stur w0, [x29, #-0x4]
;將testA函數(shù)參數(shù)2的值存儲到靠近棧底的第2個4字節(jié)空間中
0x102549dd4 <+16>: stur w1, [x29, #-0x8]
;加載參數(shù)1的值到w0寄存器中
0x102549dd8 <+20>: ldur w0, [x29, #-0x4]
;加載參數(shù)2的值到w1寄存器中
0x102549ddc <+24>: ldur w1, [x29, #-0x8]
;跳轉(zhuǎn)到testB中執(zhí)行匯編指令
0x102549de0 <+28>: bl 0x102549d88 ; testB at ViewController.m:34
;將testB函數(shù)調(diào)用的返回值(16字節(jié))存儲到??臻g中
0x102549de4 <+32>: str x0, [sp, #0x8]
0x102549de8 <+36>: str x1, [sp, #0x10]
;將10字面量的值(也就是局部變量c)存儲到w8寄存器
0x102549dec <+40>: mov w8, #0xa
;將w8寄存器中的值存儲到第6個8字節(jié)空間的第1個4字節(jié)空間中
0x102549df0 <+44>: str w8, [sp, #0x4]
;將12字面量的值(也就是局部變量d)存儲到w8寄存器
0x102549df4 <+48>: mov w8, #0xc
;將w8寄存器中的值存儲到第6個8字節(jié)空間的第2個4字節(jié)空間中
0x102549df8 <+52>: str w8, [sp]
;獲取局部變量c的值加載到w8寄存器
0x102549dfc <+56>: ldr w8, [sp, #0x4]
;獲取局部變量d的值加載到w9寄存器
0x102549e00 <+60>: ldr w9, [sp]
;將局部變量c的值與局部變量d的值相加,結(jié)果存儲到w8寄存器
0x102549e04 <+64>: add w8, w8, w9
;將結(jié)構(gòu)體變量的成員變量d的值加載到w9寄存器
0x102549e08 <+68>: ldr w9, [sp, #0x14]
;將局部變量c的值與局部變量d的值相加獲取的值與結(jié)構(gòu)體變量的成員變量d的值相加,結(jié)果存儲到w0寄存器
0x102549e0c <+72>: add w0, w8, w9
;函數(shù)調(diào)用結(jié)束,恢復現(xiàn)場(獲取上個函數(shù)的棧底地址保存到x29寄存器,以及下個指令執(zhí)行的地址保存到lr寄存器)
0x102549e10 <+76>: ldp x29, x30, [sp, #0x20]
;回收48個字節(jié)的??臻g,sp寄存器保存viewDidLoad的函數(shù)調(diào)用棧的棧頂?shù)刂? 0x102549e14 <+80>: add sp, sp, #0x30 ; =0x30
;執(zhí)行l(wèi)r寄存器所保存的指令地址的指令
0x102549e18 <+84>: ret

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

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

返回值大于16字節(jié)
4.3 testB函數(shù)匯編分析
testB:
;拉伸16字節(jié)的??臻g,sp寄存器保存棧頂?shù)刂? 0x102ad5d8c <+0>: sub sp, sp, #0x10 ; =0x10
;將testB函數(shù)的參數(shù)1的值存儲到第1個8字節(jié)空間中第1個4字節(jié)空間中
0x102ad5d90 <+4>: str w0, [sp, #0xc]
;將testB函數(shù)的參數(shù)2的值存儲到第1個8字節(jié)空間中第2個4字節(jié)空間中
0x102ad5d94 <+8>: str w1, [sp, #0x8]
;將testB函數(shù)的參數(shù)1的值加載到w9寄存器中
0x102ad5d98 <+12>: ldr w9, [sp, #0xc]
;將w9中的值存儲到x8寄存器存儲地址第1個4字節(jié)空間中
0x102ad5d9c <+16>: str w9, [x8]
;將testB函數(shù)的參數(shù)2的值加載到w9寄存器中
0x102ad5da0 <+20>: ldr w9, [sp, #0x8]
;將w9中的值存儲到x8寄存器存儲地址第2個4字節(jié)空間中
0x102ad5da4 <+24>: str w9, [x8, #0x4]
;將7的值存儲到w9寄存器中
0x102ad5da8 <+28>: mov w9, #0x7
;將w9中的值存儲到x8寄存器存儲地址第3個4字節(jié)空間中
0x102ad5dac <+32>: str w9, [x8, #0x8]
;將4的值存儲到w9寄存器中
0x102ad5db0 <+36>: mov w9, #0x4
;將w9中的值存儲到x8寄存器存儲地址第4個4字節(jié)空間中
0x102ad5db4 <+40>: str w9, [x8, #0xc]
;將20的值存儲到w9寄存器中
0x102ad5db8 <+44>: mov w9, #0x14
;將w9中的值存儲到x8寄存器存儲地址第4個4字節(jié)空間中
0x102ad5dbc <+48>: str w9, [x8, #0x10]
;回收16字節(jié)空間棧
0x102ad5dc0 <+52>: add sp, sp, #0x10 ; =0x10
;執(zhí)行l(wèi)r寄存器所保存的指令地址的地址
0x102ad5dc4 <+56>: ret
5.總結(jié)
由以上的匯編以及圖示,我們可以得到以下結(jié)論:
- 在viewDidLoad函數(shù)調(diào)用test函數(shù)時,如果testA函數(shù)中的參數(shù)不超過8個,就會在viewDidLoad函數(shù)的匯編代碼中將test的參數(shù)按位置對應一一存儲到w0到w8寄存器中。
- 在viewDidLoad函數(shù)調(diào)用testB函數(shù)時,如果test函數(shù)中的參數(shù)超過了8個,就會在viewDidLoad函數(shù)的匯編代碼中將test的參數(shù)按位置對應一一存儲到w0到w8寄存器中,然后剩余的參數(shù)會保存到viewDidLoad的??臻g中,然后在test函數(shù)體中的代碼執(zhí)行之前會將w0到w8寄存器中的參數(shù)值從棧底的位置地址向下依次進行存儲,然后再通過寄存器獲取viewDidLoad中保存的參數(shù)9的值存儲到test函數(shù)的調(diào)用棧中
- 當在一個函數(shù)中調(diào)用了其他函數(shù)時,一定要在這個函數(shù)中保存寄存器x29、x30寄存器的值,做好現(xiàn)場保護,然后在ret指令結(jié)束前再恢復之前存儲的x29、x30寄存器的值,做好現(xiàn)場恢復。
- 函數(shù)中的返回值是存儲到其??臻g中的。
- 當testA函數(shù)在調(diào)用testB函數(shù)時,如果testB函數(shù)值大小為8個字節(jié)或以下,就會在testB函數(shù)ret指令執(zhí)行前將函數(shù)返回值保存到x0寄存器中,然后繼續(xù)執(zhí)行testA函數(shù)代碼時,將x0中的返回值存儲到testA函數(shù)的??臻g中。
- 當testA函數(shù)在調(diào)用testB函數(shù)時,如果testB函數(shù)值大小為8個字節(jié)以上16個字節(jié)及以下,就會在testB函數(shù)ret指令執(zhí)行前將函數(shù)返回值保存到x0, x1寄存器中,然后繼續(xù)執(zhí)行testA函數(shù)代碼時,將x0、x1中的返回值存儲到testA函數(shù)的??臻g中。
- 當testA函數(shù)在調(diào)用testB函數(shù)時,如果testB函數(shù)值大小為16個字節(jié)或以上,就會在testA函數(shù)調(diào)用棧中開辟一塊區(qū)域,使其大小能存儲testB函數(shù)的返回值,并使用一個寄存器存儲這塊區(qū)域的最低地址位,然后在testB函數(shù)ret指令調(diào)用之前,依次將返回值的數(shù)據(jù)存儲到這塊區(qū)域中(由低地址向高地址存儲)。

