cpp学习-第六章-函数

核心简记

按p5的子章节记

函数基础

  1. 定义包括:返回类型、函数名字、形参、函数体
  2. 调用运算符()作用于表达式,表达式是函数或指向函数的指针。实参列表,用实参初始化函数的形参。调用表达式的类型为函数返回类型
  3. 函数的返回值用于初始化调用表达式的结果。
  4. 实参是形参的初始值,但并没有规定实参的求值顺序。编译器可以任意顺序对实参求值。
  5. 形参名是可选的。可以不写形参名,只靠函数原型:参数个数、类型、返回类型、函数名就可以确定符号表内函数的位置。模块连接时由这些信息生成导出符号表内符号名供使用。声明时经常不写
  6. 作用域:指符号名字的作用范围,编译时由符号表的表现形式确保。生命周期:指执行过程中对象的存在时间。
  7. 作用域内隐藏外,编译器实现为符号表的查找方式。生命周期依赖定义方式。
  8. 自动变量:普通局部变量,分配在栈中。由函数自动创建销毁。
  9. 局部静态对象:第一次经过对象定义语句时初始化,函数结束不会影响它。默认为值初始化0
  10. 头文件声明,源文件定义。定义的源文件应该把声明的头文件包含进来,这样可以利用编译器检查定义与声明的匹配。
  11. 一个.c对应一个.o为一个编译单元-一个模块,之后模块连接。

对函数的调用等价:

1
2
3
4
5
6
7
8
9
10
11
12
13
int f(int i)
{
return i;
}
使用: int j=f(1);
等价:
int i=1;
函数体
int j=i;
类型 形参=实参;
函数体;
调用表达式=返回值;

参数传递

  1. 形参的初始化原理与变量初始化一样,形参的类型决定了形参与实参的交互方式:引用类型的形参将绑定实参。否则为拷贝初始化
  2. 初始化过程中,会忽略顶层const。因为const的初始化传入可以为普通。因此定义int i与const int i的形参会函数重复定义
  3. 底层const不可忽略,常量引用可接受范围比引用广,因为普通引用不可接受常量。这是底层const
  4. 传递数组时实际传递的是首元素指针。形参的第一维将被忽略掉,见下。传递大小常用:标记、尾后指针、大小参数
  5. 多维数组时,数组的第二维及之后的大小都是数组类型一部分,也是指针类型一部分。不能省略
  6. 参数数量未知类型相同可用initializer_list类型的形参接受,但传入还需要{}。c的…形参也支持。接受单一的initializer_list类型参数,此函数可以传入一个花括号列表,而c的实现需要前面的参确定类型,依据类型大小可以从栈中取出其它参使用。
1
2
3
4
5
6
7
以下三个等价,形参都是int *
void p(int *p);
void p(int p[]);
void p(int p[10]);
以下俩个等价
void p(int (*p)[10]);
void p(int p[][10]);

返回类型与return

  1. 返回一个值的方式与初始化一个变量的方式一样,返回的值用于初始化调用点的一个临时量,该临时量就是调用结果。
  2. 不要返回局部变量的引用与指针。因为栈调用后释放
  3. 返回引用的函数结果是左值,其它为右值。
  4. c++11规定可以返回{}包围的值列表,用于对临时量初始化。
  5. c++11可以使用尾置返回类型:auto f()->int (*)[10]

函数重载

  1. 编译时编译器自动指定调用,参数类型、数量不同即可。
  2. 顶层const会被忽略,无法重载仅顶层const不同的。底层const可区分
  3. 结果:找到最佳匹配、无匹配、二义性匹配。
  4. 调用时,编译器先寻找函数名的声明,之后忽略外层同名,之后检查调用有效验证重载。编译原理中为:先找符号表,找到后不再找外层同名的了,之后该表内查找有效匹配。因此内层是会屏蔽外层重载的。同层作用域才可重载。

函数匹配:

  1. 可见->名字->参数量->参类型
  2. 可见与名字找到可见同一作用域下的重载函数,参数数量匹配,可以有默认参数,参数类型可以转化。
  3. 寻找最佳匹配,当多个形参匹配时:如果有且只有一个函数满足-每个实参的匹配不劣于其它可行函数的匹配、至少一个实参的匹配优与其它函数的匹配。如果没有函数符合则为二义性
  4. 类型匹配:精确匹配(类型相同、数组-函数转化对应指针、顶层const改动) > const转化实现匹配 > 通过类型提升实现匹配 > 通过算数类型转化 > 类类型转化

语言特性

默认实参

声明时可以写成:

1
int f(int q,int r=1,int j=3);

一个赋予其后也需要。调用时前必须完整不可省略,后可以省。
不可重复声明默认实参

内联函数、constexpr函数

定义时

1
2
3
4
inline int f()
{
}

编译时展开,有的函数不能展开,编译器可以忽略这个inline

定义时:

1
2
3
4
constexpr int f()
{
}

函数返回值及形参是字面值类型、只有一条return语句。返回不一定是常量表达式,一切都有编译器检查。只是一个可能的标志。

内联函数、constexpr函数都是定义时的概念,且应该处处一致,因此这俩个通常定义在头文件中。

调试帮助

  1. assert断言,预处理宏,求值为0则输出并终止程序,定义于cassert
  2. NDEBUG,定义该预处理变量则关闭调试帮助,assert无用

编译器提供的调试时变量:

1
2
3
4
5
__func__ :函数名字
__FILE__ :文件名
__LINE__ :行号
__TIME__ :编译时间
__DATE__ :日期

函数指针

函数指针指向函数,函数的类型由返回类型与形参类型决定。

1
2
int (*f)(int a);
f(3);

当把函数名作为值使用时,自动转化为指针。使用指针可以直接调用函数,无需解引用。
指针类型必须与重载精确匹配才可赋予。
函数指针或函数类型可以作为形参,此时会自动转化为指针。
函数指针与函数类型是不同的,decltype可以区分出来,当decltype作用于函数名时返回的是函数类型,想作为指针要加*。
返回函数类型不会自动转化为指针,必须显式将返回类型指定为指针。
可以理解为函数名为地址,函数指针为指针,函数类型为返回值、形参相关的类型

1
int (*f1(int))(int);//由内到外,由右到左,函数的结合性更高。因此为返回函数指针的函数。

反汇编

application

1
2
APP_STL := gnustl_static
APP_OPTIM := debug

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <string>
#include <vector>
using std::string;
using std::vector;
struct A{
char a[10];
int b[30];
};
//传struct
A fstruct(A a)
{
a.a[0]='a';
//返回大对象时
return a;
}
//传类对象
string fclass(string str)
{
int a=str.size();
string ret="12345678";//常量字串在?
return ret;
}
//参数多于寄存器
int fmore(int a,int b,int c,int d,int f,int g,int h,int i,int j)
{
//static局部变量的位置以及如何做到只一次调用初始化
static int t=a;
t++;
return i+j;
}
vector<int> freturnvector()
{
return {1,2};
}
//形参初始化时机?调用方与被调用方的工作。栈的处理
int main(int argc, char const *argv[])
{
A a={0};
A a2=fstruct(a);
string b="123456";
string b2=fclass(b);
int c=fmore(1,2,3,4,5,6,7,8,9);
vector<int> d=freturnvector();
return 0;
}

x86-64

指令简记

ida结构体操作:支持文件导入、直接c式写入、自己一个字节一个字节定义。不过最后都要定义在structures中才可以。
使用定义好的结构体:找到定义的地址(数据区或栈区)Edit->Struct Var(ALT+Q)命令显示一组已知的结构体,之后选择就好,自动扩散。

X64多了8个通用寄存器:R8、R9、R10、R11、R12、R13、R14、R15。都是64位的,可以使用R8、R8D、R8W、R8B访问全64位、低32位、低16位、低8位
时刻谨记:b一字节,w(word)-俩字节,dw-4字节,qw-8字节

分析

main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
.text:0000000000003220 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000003220 main proc near ; DATA XREF: start+2E↑o
.text:0000000000003220
.text:0000000000003220 var_22C = dword ptr -22Ch
.text:0000000000003220 var_228 = qword ptr -228h
.text:0000000000003220 var_220 = qword ptr -220h
.text:0000000000003220 var_218 = qword ptr -218h
.text:0000000000003220 var_210 = qword ptr -210h
.text:0000000000003220 var_208 = qword ptr -208h
.text:0000000000003220 var_200 = qword ptr -200h
.text:0000000000003220 var_1F8 = qword ptr -1F8h
.text:0000000000003220 var_1EC = dword ptr -1ECh
.text:0000000000003220 var_1E8 = qword ptr -1E8h
.text:0000000000003220 var_1E0 = dword ptr -1E0h
.text:0000000000003220 var_1DC = dword ptr -1DCh
.text:0000000000003220 var_1D8 = byte ptr -1D8h
.text:0000000000003220 var_1C0 = byte ptr -1C0h
.text:0000000000003220 var_1B8 = byte ptr -1B8h
.text:0000000000003220 var_1B0 = byte ptr -1B0h
.text:0000000000003220 var_1A8 = byte ptr -1A8h
.text:0000000000003220 dest = byte ptr -1A0h
.text:0000000000003220 var_120 = dword ptr -120h
.text:0000000000003220 var_118 = byte ptr -118h
.text:0000000000003220 src = xmmword ptr -90h
.text:0000000000003220 var_80 = xmmword ptr -80h
.text:0000000000003220 var_70 = xmmword ptr -70h
.text:0000000000003220 var_60 = xmmword ptr -60h
.text:0000000000003220 var_50 = xmmword ptr -50h
.text:0000000000003220 var_40 = xmmword ptr -40h
.text:0000000000003220 var_30 = xmmword ptr -30h
.text:0000000000003220 var_20 = xmmword ptr -20h
.text:0000000000003220 var_10 = dword ptr -10h
.text:0000000000003220 var_8 = qword ptr -8
.text:0000000000003220
.text:0000000000003220 ; __unwind {
//栈帧
.text:0000000000003220 push rbp
.text:0000000000003221 mov rbp, rsp
.text:0000000000003224 sub rsp, 2C0h
//栈检测
.text:000000000000322B mov rax, fs:28h
.text:0000000000003234 mov [rbp+var_8], rax
.text:0000000000003238 mov [rbp+var_1DC], 0
.text:0000000000003242 mov [rbp+var_1E0], edi
.text:0000000000003248 mov [rbp+var_1E8], rsi
//A a={0};A一共 10+2对齐+120=132字节 a在-90h
.text:000000000000324F xorps xmm0, xmm0
.text:0000000000003252 movaps [rbp+var_20], xmm0
.text:0000000000003256 movaps [rbp+var_30], xmm0
.text:000000000000325A movaps [rbp+var_40], xmm0
.text:000000000000325E movaps [rbp+var_50], xmm0
.text:0000000000003262 movaps [rbp+var_60], xmm0
.text:0000000000003266 movaps [rbp+var_70], xmm0
.text:000000000000326A movaps [rbp+var_80], xmm0
.text:000000000000326E movaps [rbp+src], xmm0
.text:0000000000003275 mov [rbp+var_10], 0
//A a2=fstruct(a);
//将a拷贝到dest -1A0h
.text:000000000000327C mov edi, 84h
.text:0000000000003281 mov edx, edi ; n
.text:0000000000003283 lea rax, [rbp+dest]
.text:000000000000328A lea rsi, [rbp+src] ; src
.text:0000000000003291 mov rdi, rax ; dest
.text:0000000000003294 mov [rbp+var_1F8], rax
.text:000000000000329B call _memcpy
//拷贝128个字节从 dest -1A0h到rsp 这是将dest放到栈顶
.text:00000000000032A0 mov rdx, rsp
.text:00000000000032A3 mov ecx, 10h
.text:00000000000032A8 mov rdi, rdx
.text:00000000000032AB mov rsi, [rbp+var_1F8]//传的都是值,怎么处理值寻址是汇编的事。
.text:00000000000032B2 rep movsq
//传最后4字节
.text:00000000000032B5 mov r8d, [rbp+var_120]
.text:00000000000032BC mov [rdx+80h], r8d
//调用fstruct rdi放的var_118为返回的地址:a2
.text:00000000000032C3 lea rdi, [rbp+var_118] ; src
.text:00000000000032CA mov [rbp+var_200], rax
.text:00000000000032D1 call sub_2F60
//没什么用
.text:00000000000032D6 lea rax, [rbp+var_1B0]
.text:00000000000032DD mov rdi, rax
.text:00000000000032E0 mov [rbp+var_208], rax
.text:00000000000032E7 call nullsub_2
// string b="123456"; var_1A8为this var_210为存this的指针
.text:00000000000032EC lea rsi, a123456 ; "123456"
.text:00000000000032F3 lea rax, [rbp+var_1A8]
.text:00000000000032FA mov rdi, rax
.text:00000000000032FD mov rdx, [rbp+var_208]
.text:0000000000003304 mov [rbp+var_210], rax
.text:000000000000330B call sub_4370
.text:0000000000003310 mov rdi, [rbp+var_208]
.text:0000000000003317 call nullsub_3
//拷贝构造 var_210存的b到var_1C0 var_218是存放var_1C0的指针
.text:000000000000331C lea rax, [rbp+var_1C0]
.text:0000000000003323 mov rdi, rax
.text:0000000000003326 mov rsi, [rbp+var_210]
.text:000000000000332D mov [rbp+var_218], rax
.text:0000000000003334 call sub_4600
//rdi:var_1B8为返回的b2,rsi:var_218为刚拷贝好的 var_220存b2的指针
.text:0000000000003339 lea rax, [rbp+var_1B8]
.text:0000000000003340 mov rdi, rax
.text:0000000000003343 mov rsi, [rbp+var_218]
.text:000000000000334A mov [rbp+var_220], rax
.text:0000000000003351 call sub_2F90 //为fclass
//析构var_218传入时的拷贝
.text:0000000000003356 mov rdi, [rbp+var_218]
.text:000000000000335D call sub_4490 //析构var_218传入时的拷贝
//int c=fmore(1,2,3,4,5,6,7,8,9);
//传参顺序左到右:di、si、dx、cx、8d、9d 之后sp低到高放
.text:0000000000003362 mov rax, rsp
.text:0000000000003365 mov dword ptr [rax+10h], 9
.text:000000000000336C mov dword ptr [rax+8], 8
.text:0000000000003373 mov dword ptr [rax], 7
.text:0000000000003379 mov edi, 1
.text:000000000000337E mov esi, 2
.text:0000000000003383 mov edx, 3
.text:0000000000003388 mov ecx, 4
.text:000000000000338D mov r8d, 5
.text:0000000000003393 mov r9d, 6
.text:0000000000003399 call sub_3030
.text:000000000000339E mov [rbp+var_1EC], eax
//vector<int> d=freturnvector(); var_1D8是传入的d的this,用于返回值 var_228为其指针
.text:00000000000033A4 lea r10, [rbp+var_1D8]
.text:00000000000033AB mov rdi, r10
.text:00000000000033AE mov [rbp+var_228], r10
.text:00000000000033B5 call sub_30C0
.text:00000000000033BA mov [rbp+var_1DC], 0
//释放d
.text:00000000000033C4 mov rdi, [rbp+var_228]
.text:00000000000033CB call sub_3420
//释放b2
.text:00000000000033D0 mov rdi, [rbp+var_220]
.text:00000000000033D7 call sub_4490
//释放b
.text:00000000000033DC mov rdi, [rbp+var_210]
.text:00000000000033E3 call sub_4490
//栈检测
.text:00000000000033E8 mov eax, [rbp+var_1DC]
.text:00000000000033EE mov rdi, fs:28h
.text:00000000000033F7 mov r10, [rbp+var_8]
.text:00000000000033FB cmp rdi, r10
.text:00000000000033FE mov [rbp+var_22C], eax
.text:0000000000003404 jnz loc_3419
.text:000000000000340A mov eax, [rbp+var_22C]
.text:0000000000003410 add rsp, 2C0h
.text:0000000000003417 pop rbp
.text:0000000000003418 retn
.text:0000000000003419 ; ---------------------------------------------------------------------------
.text:0000000000003419
.text:0000000000003419 loc_3419: ; CODE XREF: main+1E4↑j
.text:0000000000003419 call ___stack_chk_fail
.text:0000000000003419 ; } // starts at 3220
.text:0000000000003419 main endp

fstruct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.text:0000000000002F60 ; __int64 __fastcall sub_2F60(char src)
.text:0000000000002F60 sub_2F60 proc near ; CODE XREF: main+B1↓p
.text:0000000000002F60
.text:0000000000002F60 var_8 = qword ptr -8
.text:0000000000002F60 src = byte ptr 10h
.text:0000000000002F60
.text:0000000000002F60 ; __unwind {
.text:0000000000002F60 push rbp
.text:0000000000002F61 mov rbp, rsp
.text:0000000000002F64 sub rsp, 10h
.text:0000000000002F68 mov rax, rdi
//直接从上面的栈帧中获得a.a[0]
.text:0000000000002F6B lea rcx, [rbp+src] //rbp与返回地址,因此加16字节为原来的rsp
.text:0000000000002F6F mov edx, 84h ; n
.text:0000000000002F74 mov byte ptr [rcx], 61h ; 'a'
.text:0000000000002F77 mov rsi, rcx ; src
.text:0000000000002F7A mov [rbp+var_8], rax
//传入的rdi为返回时的接受者a2
.text:0000000000002F7E call _memcpy
.text:0000000000002F83 mov rax, [rbp+var_8]
.text:0000000000002F87 add rsp, 10h
.text:0000000000002F8B pop rbp
.text:0000000000002F8C retn
.text:0000000000002F8C ; } // starts at 2F60
.text:0000000000002F8C sub_2F60 endp

fclass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//rdi:var_1B8为返回的b2,rsi:var_218为刚拷贝好的 var_220存b2的指针
.text:0000000000002F90 fclass proc near ; CODE XREF: main+131↓p
.text:0000000000002F90
.text:0000000000002F90 var_28 = qword ptr -28h
.text:0000000000002F90 var_20 = qword ptr -20h
.text:0000000000002F90 var_15 = byte ptr -15h
.text:0000000000002F90 var_14 = dword ptr -14h
.text:0000000000002F90 var_10 = byte ptr -10h
.text:0000000000002F90 var_8 = qword ptr -8
.text:0000000000002F90
.text:0000000000002F90 ; __unwind {
.text:0000000000002F90 000 push rbp
.text:0000000000002F91 008 mov rbp, rsp
.text:0000000000002F94 008 sub rsp, 30h
.text:0000000000002F98 038 mov rax, rdi
.text:0000000000002F9B 038 mov rcx, fs:28h
.text:0000000000002FA4 038 mov [rbp+var_8], rcx
.text:0000000000002FA8 038 mov [rbp+var_20], rdi
// rsi为参数str int a=str.size();
.text:0000000000002FAC 038 mov rdi, rsi
.text:0000000000002FAF 038 mov [rbp+var_28], rax
.text:0000000000002FB3 038 call sub_44E0
.text:0000000000002FB8 038 lea rdi, [rbp+var_10]
.text:0000000000002FBC 038 mov edx, eax
.text:0000000000002FBE 038 mov [rbp+var_14], edx
// string ret="12345678";常量在rodata var_20为指针存的this 这里直接构建在返回值上了
.text:0000000000002FC1 038 mov [rbp+var_15], 0
.text:0000000000002FC5 038 call nullsub_2
.text:0000000000002FCA 038 lea rsi, a12345678 ; "12345678"
.text:0000000000002FD1 038 lea rdx, [rbp+var_10]
.text:0000000000002FD5 038 mov rdi, [rbp+var_20]
.text:0000000000002FD9 038 call sub_4370
.text:0000000000002FDE 038 lea rdi, [rbp+var_10]
.text:0000000000002FE2 038 call nullsub_3
.text:0000000000002FE7 038 mov [rbp+var_15], 1
.text:0000000000002FEB 038 test [rbp+var_15], 1 //这是逻辑与
.text:0000000000002FEF 038 jnz loc_2FFE
//析构var_20 这里不会执行
.text:0000000000002FF5 038 mov rdi, [rbp+var_20]
.text:0000000000002FF9 038 call sub_4490
.text:0000000000002FFE
.text:0000000000002FFE loc_2FFE: ; CODE XREF: fclass+5F↑j
.text:0000000000002FFE 038 mov rax, fs:28h
.text:0000000000003007 038 mov rcx, [rbp+var_8]
.text:000000000000300B 038 cmp rax, rcx
.text:000000000000300E 038 jnz loc_301E
.text:0000000000003014 038 mov rax, [rbp+var_28]
.text:0000000000003018 038 add rsp, 30h
.text:000000000000301C 008 pop rbp
.text:000000000000301D 000 retn
.text:000000000000301E ; ---------------------------------------------------------------------------
.text:000000000000301E
.text:000000000000301E loc_301E: ; CODE XREF: fclass+7E↑j
.text:000000000000301E 038 call ___stack_chk_fail
.text:000000000000301E ; } // starts at 2F90
.text:000000000000301E fclass endp

fmore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
.text:0000000000003030 sub_3030 proc near ; CODE XREF: main+179↓p
.text:0000000000003030
.text:0000000000003030 var_24 = dword ptr -24h
.text:0000000000003030 var_20 = dword ptr -20h
.text:0000000000003030 var_1C = dword ptr -1Ch
.text:0000000000003030 var_18 = dword ptr -18h
.text:0000000000003030 var_14 = dword ptr -14h
.text:0000000000003030 var_10 = dword ptr -10h
.text:0000000000003030 var_C = dword ptr -0Ch
.text:0000000000003030 var_8 = dword ptr -8
.text:0000000000003030 var_4 = dword ptr -4
.text:0000000000003030 arg_0 = dword ptr 10h
.text:0000000000003030 arg_8 = dword ptr 18h
.text:0000000000003030 arg_10 = dword ptr 20h
.text:0000000000003030
.text:0000000000003030 ; __unwind {
.text:0000000000003030 000 push rbp
.text:0000000000003031 008 mov rbp, rsp
.text:0000000000003034 008 sub rsp, 30h
//参数再拷贝一次
.text:0000000000003038 038 mov eax, [rbp+arg_10]
.text:000000000000303B 038 mov r10d, [rbp+arg_8]
.text:000000000000303F 038 mov r11d, [rbp+arg_0]
.text:0000000000003043 038 mov [rbp+var_4], edi
.text:0000000000003046 038 mov [rbp+var_8], esi
.text:0000000000003049 038 mov [rbp+var_C], edx
.text:000000000000304C 038 mov [rbp+var_10], ecx
.text:000000000000304F 038 mov [rbp+var_14], r8d
.text:0000000000003053 038 mov [rbp+var_18], r9d
.text:0000000000003057 038 cmp cs:byte_1E050, 0 //byte_1E050是静态变量的标志位
.text:000000000000305E 038 mov [rbp+var_1C], r11d
.text:0000000000003062 038 mov [rbp+var_20], r10d
.text:0000000000003066 038 mov [rbp+var_24], eax
.text:0000000000003069 038 jnz loc_3099 //不是0就跳,表示初始化过了,先保护一个锁
.text:000000000000306F 038 lea rdi, byte_1E050
.text:0000000000003076 038 call __cxa_guard_acquire //__cxa_guard_acquire的时候将锁变量的第二个字节置1,表示初始化中,若已经1了就等待0再返回0
.text:000000000000307B 038 cmp eax, 0
.text:000000000000307E 038 jz loc_3099
.text:0000000000003084 038 lea rdi, byte_1E050
//初始化 在.bss段
.text:000000000000308B 038 mov eax, [rbp+var_4]
.text:000000000000308E 038 mov cs:dword_1E048, eax
//__cxa_guard_release的时候清除第二个字节,再将第一个字节置1
.text:0000000000003094 038 call __cxa_guard_release
.text:0000000000003099
.text:0000000000003099 loc_3099: ; CODE XREF: sub_3030+39↑j
.text:0000000000003099 ; sub_3030+4E↑j
// t++;
.text:0000000000003099 038 mov eax, cs:dword_1E048
.text:000000000000309F 038 add eax, 1
.text:00000000000030A2 038 mov cs:dword_1E048, eax
//return i+j;
.text:00000000000030A8 038 mov eax, [rbp+arg_8]
.text:00000000000030AB 038 add eax, [rbp+arg_10]
.text:00000000000030AE 038 add rsp, 30h
.text:00000000000030B2 008 pop rbp
.text:00000000000030B3 000 retn
.text:00000000000030B3 ; } // starts at 3030
.text:00000000000030B3 sub_3030 endp

大意是一个全局的mutex和一个cond来保护一个锁变量,锁变量再来保护目标变量。锁变量的第一个字节表示目标变量是否被初始化过了,第二个字节表示目标变量是否在初始化中。

freturnvector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.text:00000000000030C0 sub_30C0 proc near ; CODE XREF: main+195↓p
.text:00000000000030C0
.text:00000000000030C0 var_38 = qword ptr -38h
.text:00000000000030C0 var_30 = qword ptr -30h
.text:00000000000030C0 var_28 = qword ptr -28h
.text:00000000000030C0 var_20 = qword ptr -20h
.text:00000000000030C0 var_18 = qword ptr -18h
.text:00000000000030C0 var_10 = byte ptr -10h
.text:00000000000030C0 var_8 = qword ptr -8
.text:00000000000030C0
.text:00000000000030C0 ; __unwind {
.text:00000000000030C0 000 push rbp
.text:00000000000030C1 008 mov rbp, rsp
.text:00000000000030C4 008 sub rsp, 40h
.text:00000000000030C8 048 mov rax, rdi
.text:00000000000030CB 048 mov rcx, fs:28h
.text:00000000000030D4 048 mov [rbp+var_8], rcx
.text:00000000000030D8 048 lea rcx, unk_16808//rodata段的1 2
.text:00000000000030DF 048 mov [rbp+var_20], rcx
.text:00000000000030E3 048 mov [rbp+var_18], 2
.text:00000000000030EB 048 lea rcx, [rbp+var_10]
.text:00000000000030EF 048 mov [rbp+var_28], rdi
.text:00000000000030F3 048 mov rdi, rcx
.text:00000000000030F6 048 mov [rbp+var_30], rax
.text:00000000000030FA 048 mov [rbp+var_38], rcx
.text:00000000000030FE 048 call sub_3150
//列表构造rdi为this rsi为列表参数 rdx为列表个数
.text:0000000000003103 048 mov rsi, [rbp+var_20]
.text:0000000000003107 048 mov rdx, [rbp+var_18]
.text:000000000000310B 048 mov rdi, [rbp+var_28]
.text:000000000000310F 048 mov rcx, [rbp+var_38]
.text:0000000000003113 048 call sub_3170
.text:0000000000003118 048 mov rdi, [rbp+var_38]
.text:000000000000311C 048 call sub_3200
//栈检查
.text:0000000000003121 048 mov rax, fs:28h
.text:000000000000312A 048 mov rcx, [rbp+var_8]
.text:000000000000312E 048 cmp rax, rcx
.text:0000000000003131 048 jnz loc_3141
//返回对象地址
.text:0000000000003137 048 mov rax, [rbp+var_30]
.text:000000000000313B 048 add rsp, 40h
.text:000000000000313F 008 pop rbp
.text:0000000000003140 000 retn
.text:0000000000003141 ; ---------------------------------------------------------------------------
.text:0000000000003141
.text:0000000000003141 loc_3141: ; CODE XREF: sub_30C0+71↑j
.text:0000000000003141 048 call ___stack_chk_fail
.text:0000000000003141 ; } // starts at 30C0
.text:0000000000003141 sub_30C0 endp

总结下:

  1. 结构体当做大块的空间整体处理
  2. 传参为结构体:先在调用者的栈顶创建好结构体的拷贝,被调用函数使用时用正偏移直接使用调用者栈中的结构体拷贝对象,相当于栈中传参,只是sp提前变好。
  3. 返回为结构体:调用时第一个传入返回对象的地址,函数内返回的内容直接向其拷贝
  4. 传参为类对象:先在调用者的栈中进行拷贝构造,之后将构造好的对象地址传入。被调用者使用的参数对象实际在调用者栈中,调用结束后调用者执行析构函数。
  5. 返回为类对象:调用时第一个传入返回对象的地址,函数内直接对其构造。
  6. 函数的传参顺序:左到右:di、si、dx、cx、8d、9d 之后sp低到高放
  7. 静态局部变量的初次初始化依靠锁机制。
  8. 以上的sp在debug模式下都是提前分好的,调用传参不用现分配。

总而言之,对象形参都是调用者准备好的,之后清理也是由调用者负责。被调用者栈中其实没有传来的大块内容,只传入所需地址。而返回值也是直接传入的调用者栈中的地址,直接对调用者栈拷贝返回。
因此参数的构造由调用者负责,都在sp之上。sp不用回收参数,因为一开始分配栈帧时算参数的大小进去了。析构也由调用者负责。返回值的构造由被调用者负责。

ARM-64

指令简记

FP(x29)寄存器保存栈帧地址,LR(x30)保存当前过程的返回地址。
UXTB:字节被无符号扩展(高位清0)

分析

main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
.text:00000000000038E8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000038E8 EXPORT main
.text:00000000000038E8 main ; DATA XREF: LOAD:0000000000000540↑o
.text:00000000000038E8 ; .got:main_ptr↓o
.text:00000000000038E8
.text:00000000000038E8 var_240 = -0x240
.text:00000000000038E8 var_22C = -0x22C
.text:00000000000038E8 var_228 = -0x228
.text:00000000000038E8 var_220 = -0x220
.text:00000000000038E8 var_218 = -0x218
.text:00000000000038E8 var_210 = -0x210
.text:00000000000038E8 var_208 = -0x208
.text:00000000000038E8 var_1FC = -0x1FC
.text:00000000000038E8 var_1F8 = -0x1F8
.text:00000000000038E8 var_1F0 = -0x1F0
.text:00000000000038E8 var_1EC = -0x1EC
.text:00000000000038E8 var_1E8 = -0x1E8
.text:00000000000038E8 var_1D0 = -0x1D0
.text:00000000000038E8 var_1C8 = -0x1C8
.text:00000000000038E8 var_1C0 = -0x1C0
.text:00000000000038E8 var_1B8 = -0x1B8
.text:00000000000038E8 var_1B0 = -0x1B0
.text:00000000000038E8 var_128 = -0x128
.text:00000000000038E8 var_A0 = -0xA0
.text:00000000000038E8 var_10 = -0x10
.text:00000000000038E8 var_s0 = 0
.text:00000000000038E8
.text:00000000000038E8 ; __unwind {
//栈帧
.text:00000000000038E8 STR X28, [SP,#-0x10+var_10]!
.text:00000000000038EC STP X29, X30, [SP,#0x10+var_s0]
.text:00000000000038F0 ADD X29, SP, #0x10
.text:00000000000038F4 SUB SP, SP, #0x230
.text:00000000000038F8 ADD X8, SP, #0x240+var_208
.text:00000000000038FC MOV X9, #0x84
.text:0000000000003900 SUB X10, X29, #-var_A0
.text:0000000000003904 ADD X11, SP, #0x240+var_1B0
.text:0000000000003908 MOV W12, WZR
.text:000000000000390C MRS X13, #3, c13, c0, #2
.text:0000000000003910 LDR X13, [X13,#0x28]
.text:0000000000003914 STR X13, [X8]
.text:0000000000003918 STR WZR, [SP,#0x240+var_1EC]
.text:000000000000391C STR W0, [SP,#0x240+var_1F0]
.text:0000000000003920 STR X1, [SP,#0x240+var_1F8]
.text:0000000000003924 MOV X1, X10
.text:0000000000003928 MOV X0, X1
.text:000000000000392C UXTB W1, W12
.text:0000000000003930 MOV X2, X9
.text:0000000000003934 STR X8, [SP,#0x240+var_210]
.text:0000000000003938 STR X10, [SP,#0x240+var_218]
.text:000000000000393C STR X11, [SP,#0x240+var_220]
.text:0000000000003940 STR X9, [SP,#0x240+var_228]
//这时的X0为var_A0 W1为0 X2为0x84-还是132字节初始为0 var_218为var_A0的指针 为a
.text:0000000000003944 BL .memset
// 拷贝 a到var_1B0(存于var_220) 132字节
.text:0000000000003948 LDR X8, [SP,#0x240+var_220]
.text:000000000000394C LDR X9, [SP,#0x240+var_218]
.text:0000000000003950 MOV X0, X8
.text:0000000000003954 MOV X1, X9
.text:0000000000003958 LDR X2, [SP,#0x240+var_228]
.text:000000000000395C BL .memcpy
// A a2=fstruct(a); 传入 X0为var_1B0 X8放返回的结果地址var_128为a2
.text:0000000000003960 ADD X8, SP, #0x240+var_128
.text:0000000000003964 ADD X0, SP, #0x240+var_1B0
.text:0000000000003968 BL sub_361C
//构造b var_1B8为this
.text:000000000000396C ADD X0, SP, #0x240+var_1C0
.text:0000000000003970 BL nullsub_1
.text:0000000000003974 ADD X0, SP, #0x240+var_1B8
.text:0000000000003978 ADRP X8, #a123456@PAGE ; "123456"
.text:000000000000397C ADD X1, X8, #a123456@PAGEOFF ; "123456"
.text:0000000000003980 ADD X2, SP, #0x240+var_1C0
.text:0000000000003984 BL sub_4A24
.text:0000000000003988 ADD X0, SP, #0x240+var_1C0
.text:000000000000398C BL nullsub_2
//拷贝var_1B8到var_1D0
.text:0000000000003990 ADD X0, SP, #0x240+var_1D0
.text:0000000000003994 ADD X1, SP, #0x240+var_1B8
.text:0000000000003998 BL sub_4D00
//string b2=fclass(b); var_1D0为拷贝的this参 var_1C8为返回的this
.text:000000000000399C ADD X8, SP, #0x240+var_1C8
.text:00000000000039A0 ADD X0, SP, #0x240+var_1D0
.text:00000000000039A4 BL sub_3650
//析构var_1D0
.text:00000000000039A8 ADD X0, SP, #0x240+var_1D0
.text:00000000000039AC BL sub_4B64
// int c=fmore(1,2,3,4,5,6,7,8,9);
// arm-v8的传参顺序:寄存器01234567 栈顶
.text:00000000000039B0 MOV W0, #1
.text:00000000000039B4 MOV W1, #2
.text:00000000000039B8 MOV W2, #3
.text:00000000000039BC MOV W3, #4
.text:00000000000039C0 MOV W4, #5
.text:00000000000039C4 MOV W5, #6
.text:00000000000039C8 MOV W6, #7
.text:00000000000039CC MOV W7, #8
.text:00000000000039D0 MOV W12, #9
.text:00000000000039D4 STR W12, [SP,#0x240+var_240]
.text:00000000000039D8 BL sub_36E8
.text:00000000000039DC STR W0, [SP,#0x240+var_1FC]
// vector<int> d=freturnvector(); x8直接传入返回
.text:00000000000039E0 ADD X8, SP, #0x240+var_1E8
.text:00000000000039E4 BL sub_3784
//释放 d
.text:00000000000039E8 ADD X0, SP, #0x240+var_1E8
.text:00000000000039EC STR WZR, [SP,#0x240+var_1EC]
.text:00000000000039F0 BL sub_3A3C
//释放b2
.text:00000000000039F4 ADD X0, SP, #0x240+var_1C8
.text:00000000000039F8 BL sub_4B64
// 释放b
.text:00000000000039FC ADD X0, SP, #0x240+var_1B8
.text:0000000000003A00 BL sub_4B64
//栈检查
.text:0000000000003A04 LDR W0, [SP,#0x240+var_1EC]
.text:0000000000003A08 MRS X8, #3, c13, c0, #2
.text:0000000000003A0C LDR X8, [X8,#0x28]
.text:0000000000003A10 LDR X9, [SP,#0x240+var_210]
.text:0000000000003A14 LDR X10, [X9]
.text:0000000000003A18 CMP X8, X10
.text:0000000000003A1C STR W0, [SP,#0x240+var_22C]
.text:0000000000003A20 B.NE loc_3A38
.text:0000000000003A24 LDR W0, [SP,#0x240+var_22C]
.text:0000000000003A28 ADD SP, SP, #0x230
.text:0000000000003A2C LDP X29, X30, [SP,#0x10+var_s0]
.text:0000000000003A30 LDR X28, [SP+0x10+var_10],#0x20
.text:0000000000003A34 RET
.text:0000000000003A38 ; ---------------------------------------------------------------------------
.text:0000000000003A38
.text:0000000000003A38 loc_3A38 ; CODE XREF: main+138↑j
.text:0000000000003A38 BL .__stack_chk_fail
.text:0000000000003A38 ; } // starts at 38E8

fstruct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.text:000000000000361C sub_361C ; CODE XREF: main+80↓p
.text:000000000000361C
.text:000000000000361C var_8 = -8
.text:000000000000361C var_s0 = 0
.text:000000000000361C
.text:000000000000361C ; __unwind {
//存返回地址和栈帧
.text:000000000000361C SUB SP, SP, #0x20
.text:0000000000003620 STP X29, X30, [SP,#0x10+var_s0]
//记录栈帧
.text:0000000000003624 ADD X29, SP, #0x10
.text:0000000000003628 MOV X2, #0x84
//a.a[0]='a'; X0传入的参是main中的拷贝
.text:000000000000362C MOV W9, #0x61
.text:0000000000003630 STRB W9, [X0]
.text:0000000000003634 STR X0, [SP,#0x10+var_8]
//拷贝传入的X0到传入的X8
.text:0000000000003638 MOV X0, X8
.text:000000000000363C LDR X1, [SP,#0x10+var_8]
.text:0000000000003640 BL .memcpy
//取参返回
.text:0000000000003644 LDP X29, X30, [SP,#0x10+var_s0]
.text:0000000000003648 ADD SP, SP, #0x20
.text:000000000000364C RET
.text:000000000000364C ; } // starts at 361C

fclass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
.text:0000000000003650 sub_3650 ; CODE XREF: main+BC↓p
.text:0000000000003650
.text:0000000000003650 var_20 = -0x20
.text:0000000000003650 var_15 = -0x15
.text:0000000000003650 var_14 = -0x14
.text:0000000000003650 var_10 = -0x10
.text:0000000000003650 var_8 = -8
.text:0000000000003650 var_s0 = 0
.text:0000000000003650
.text:0000000000003650 ; __unwind {
.text:0000000000003650 SUB SP, SP, #0x30
.text:0000000000003654 STP X29, X30, [SP,#0x20+var_s0]
.text:0000000000003658 ADD X29, SP, #0x20
.text:000000000000365C MRS X9, #3, c13, c0, #2
.text:0000000000003660 LDR X9, [X9,#0x28]
.text:0000000000003664 STUR X9, [X29,#var_8]
.text:0000000000003668 STR X8, [SP,#0x20+var_20]
//int a=str.size();
.text:000000000000366C BL sub_4BBC
.text:0000000000003670 ADD X8, SP, #0x20+var_10
.text:0000000000003674 MOV W10, W0
.text:0000000000003678 STR W10, [SP,#0x20+var_14]
.text:000000000000367C STRB WZR, [SP,#0x20+var_15]
//string ret="12345678"; X8直接当成this
.text:0000000000003680 MOV X0, X8
.text:0000000000003684 BL nullsub_1
.text:0000000000003688 ADRP X8, #a12345678@PAGE ; "12345678"
.text:000000000000368C ADD X1, X8, #a12345678@PAGEOFF ; "12345678"
.text:0000000000003690 ADD X2, SP, #0x20+var_10
.text:0000000000003694 LDR X0, [SP,#0x20+var_20]
.text:0000000000003698 BL sub_4A24
.text:000000000000369C ADD X0, SP, #0x20+var_10
.text:00000000000036A0 BL nullsub_2
.text:00000000000036A4 MOV W10, #1
.text:00000000000036A8 AND W10, W10, #1
.text:00000000000036AC STRB W10, [SP,#0x20+var_15]
.text:00000000000036B0 LDRB W10, [SP,#0x20+var_15]
.text:00000000000036B4 AND W10, W10, #1
.text:00000000000036B8 TBNZ W10, #0, loc_36C4
.text:00000000000036BC LDR X0, [SP,#0x20+var_20]
.text:00000000000036C0 BL sub_4B64
.text:00000000000036C4
.text:00000000000036C4 loc_36C4 ; CODE XREF: sub_3650+68↑j
.text:00000000000036C4 MRS X8, #3, c13, c0, #2
.text:00000000000036C8 LDR X8, [X8,#0x28]
.text:00000000000036CC LDUR X9, [X29,#var_8]
.text:00000000000036D0 CMP X8, X9
.text:00000000000036D4 B.NE loc_36E4
.text:00000000000036D8 LDP X29, X30, [SP,#0x20+var_s0]
.text:00000000000036DC ADD SP, SP, #0x30
.text:00000000000036E0 RET
.text:00000000000036E4 ; ---------------------------------------------------------------------------
.text:00000000000036E4
.text:00000000000036E4 loc_36E4 ; CODE XREF: sub_3650+84↑j
.text:00000000000036E4 BL .__stack_chk_fail
.text:00000000000036E4 ; } // starts at 3650

fmore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
.text:00000000000036E8 sub_36E8 ; CODE XREF: main+F0↓p
.text:00000000000036E8
.text:00000000000036E8 var_24 = -0x24
.text:00000000000036E8 var_20 = -0x20
.text:00000000000036E8 var_1C = -0x1C
.text:00000000000036E8 var_18 = -0x18
.text:00000000000036E8 var_14 = -0x14
.text:00000000000036E8 var_10 = -0x10
.text:00000000000036E8 var_C = -0xC
.text:00000000000036E8 var_8 = -8
.text:00000000000036E8 var_4 = -4
.text:00000000000036E8 var_s0 = 0
.text:00000000000036E8 arg_0 = 0x10
.text:00000000000036E8
.text:00000000000036E8 ; __unwind {
.text:00000000000036E8 SUB SP, SP, #0x40
.text:00000000000036EC STP X29, X30, [SP,#0x30+var_s0]
.text:00000000000036F0 ADD X29, SP, #0x30
//栈帧上方识别为参
.text:00000000000036F4 LDR W8, [X29,#arg_0]
.text:00000000000036F8 STUR W0, [X29,#var_4]
.text:00000000000036FC STUR W1, [X29,#var_8]
.text:0000000000003700 STUR W2, [X29,#var_C]
.text:0000000000003704 STUR W3, [X29,#var_10]
.text:0000000000003708 STUR W4, [X29,#var_14]
.text:000000000000370C STR W5, [SP,#0x30+var_18]
.text:0000000000003710 STR W6, [SP,#0x30+var_1C]
.text:0000000000003714 STR W7, [SP,#0x30+var_20]
//静态初始赋值检查
.text:0000000000003718 ADRP X9, #unk_2E048@PAGE
.text:000000000000371C ADD X9, X9, #unk_2E048@PAGEOFF
//取俩个字节 检测第一个不是0就跳
.text:0000000000003720 LDARB WZR, W0, [X9]
.text:0000000000003724 STR W8, [SP,#0x30+var_24]
.text:0000000000003728 TBNZ W0, #0, loc_3758
//检测锁,加初始化锁
.text:000000000000372C ADRP X8, #unk_2E048@PAGE
.text:0000000000003730 ADD X0, X8, #unk_2E048@PAGEOFF
.text:0000000000003734 BL __cxa_guard_acquire
.text:0000000000003738 CBZ W0, loc_3758
.text:000000000000373C ADRP X8, #unk_2E048@PAGE
.text:0000000000003740 ADD X0, X8, #unk_2E048@PAGEOFF
// static int t=a; 在bss段
.text:0000000000003744 ADRP X8, #dword_2E040@PAGE
.text:0000000000003748 ADD X8, X8, #dword_2E040@PAGEOFF
.text:000000000000374C LDUR W9, [X29,#var_4]
.text:0000000000003750 STR W9, [X8]
//释放初始化锁
.text:0000000000003754 BL __cxa_guard_release
.text:0000000000003758
.text:0000000000003758 loc_3758 ; CODE XREF: sub_36E8+40↑j
.text:0000000000003758 ; sub_36E8+50↑j
//t++;
.text:0000000000003758 ADRP X8, #dword_2E040@PAGE
.text:000000000000375C ADD X8, X8, #dword_2E040@PAGEOFF
.text:0000000000003760 LDR W9, [X8]
.text:0000000000003764 ADD W9, W9, #1
.text:0000000000003768 STR W9, [X8]
//return i+j; 返回值用W0
.text:000000000000376C LDR W9, [SP,#0x30+var_20]
.text:0000000000003770 LDR W10, [X29,#arg_0]
.text:0000000000003774 ADD W0, W9, W10
.text:0000000000003778 LDP X29, X30, [SP,#0x30+var_s0]
.text:000000000000377C ADD SP, SP, #0x40
.text:0000000000003780 RET
.text:0000000000003780 ; } // starts at 36E8
.text:0000000000003780 ; End of function sub_36E8

freturnvector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
.text:0000000000003784 sub_3784 ; CODE XREF: main+FC↓p
.text:0000000000003784
.text:0000000000003784 var_28 = -0x28
.text:0000000000003784 var_20 = -0x20
.text:0000000000003784 var_18 = -0x18
.text:0000000000003784 var_10 = -0x10
.text:0000000000003784 var_8 = -8
.text:0000000000003784 var_s0 = 0
.text:0000000000003784
.text:0000000000003784 ; __unwind {
.text:0000000000003784 SUB SP, SP, #0x40
.text:0000000000003788 STP X29, X30, [SP,#0x30+var_s0]
.text:000000000000378C ADD X29, SP, #0x30
.text:0000000000003790 MRS X9, #3, c13, c0, #2
.text:0000000000003794 LDR X9, [X9,#0x28]
.text:0000000000003798 STUR X9, [X29,#var_8]
//获取初始化列表 1 2
.text:000000000000379C ADRP X9, #unk_17AC0@PAGE
.text:00000000000037A0 ADD X9, X9, #unk_17AC0@PAGEOFF
.text:00000000000037A4 STR X9, [SP,#0x30+var_20]
.text:00000000000037A8 MOV W10, #2
.text:00000000000037AC MOV W9, W10
.text:00000000000037B0 STR X9, [SP,#0x30+var_18]
.text:00000000000037B4 SUB X0, X29, #-var_10
.text:00000000000037B8 STR X8, [SP,#0x30+var_28]
.text:00000000000037BC BL sub_3808
.text:00000000000037C0 LDR X8, [SP,#0x30+var_18]
.text:00000000000037C4 LDR X9, [SP,#0x30+var_20]
.text:00000000000037C8 SUB X3, X29, #-var_10
// x0为this X1初始化列表-直接就在rodata区的 x2为成员个数
.text:00000000000037CC LDR X0, [SP,#0x30+var_28]
.text:00000000000037D0 MOV X1, X9
.text:00000000000037D4 MOV X2, X8
.text:00000000000037D8 BL sub_382C
.text:00000000000037DC SUB X0, X29, #-var_10
.text:00000000000037E0 BL sub_38C4
.text:00000000000037E4 MRS X8, #3, c13, c0, #2
.text:00000000000037E8 LDR X8, [X8,#0x28]
.text:00000000000037EC LDUR X9, [X29,#var_8]
.text:00000000000037F0 CMP X8, X9
.text:00000000000037F4 B.NE loc_3804
.text:00000000000037F8 LDP X29, X30, [SP,#0x30+var_s0]
.text:00000000000037FC ADD SP, SP, #0x40
.text:0000000000003800 RET
.text:0000000000003804 ; ---------------------------------------------------------------------------
.text:0000000000003804
.text:0000000000003804 loc_3804 ; CODE XREF: sub_3784+70↑j
.text:0000000000003804 BL .__stack_chk_fail
.text:0000000000003804 ; } // starts at 3784

arm-v8的传参顺序:寄存器01234567 栈顶
如果返回值为对象或结构体,提前在调用方分配好栈空间,将地址以X8传入被调函数,被调函数针对该指针构造返回,这个空间就是返回的临时值。同样传入对象或结构体也存于调用者栈中,传入指针。

c++对结构体与类的处理还是不太一样。结构体更偏向于数据,类更偏向于操作this