传递基本类型
int func(int a, int b, int c, int d, int e) {
int v1 = 1;
int r = a + b + c + d + e + v1;
return r;
}
int main() {
int i = 1, j = 2;
int r = func(i, j, 3, 4, 5);
printf("%d \n", r);
}
对应main函数的汇编代码
; int __cdecl main(int argc, const char **argv, const char **envp)
PUSH {R11,LR} ;保存现场
ADD R11, SP, #4 ;新栈的基址 FP(BP)
SUB SP, SP, #0x18 ;开辟栈空间
MOV R3, #1 ;r3 = 1
STR R3, [R11,#var_8] ;[r11+var_8] = 1
MOV R3, #2 ;r3 = 2
STR R3, [R11,#var_C] ;[r11+var_C] = 2
MOV R3, #5 ;r3 = 5
STR R3, [SP,#0x1C+var_1C] ; int ;[sp+0x1c+var_1c] = 5
LDR R0, [R11,#var_8] ;r0 = [r11+var_8] = 1
LDR R1, [R11,#var_C] ;r1 = [r11+var_C] = 2
MOV R2, #3 ;r2 = 3
MOV R3, #4 ;r3 = 4
BL _Z4funciiiii ; func(int,int,int,int,int)
此时栈及寄存器如下:
对应func函数的汇编代码
; _DWORD __fastcall func(int, int, int, int, int)
PUSH {R11}
ADD R11, SP, #0
SUB SP, SP, #0x1C
STR R0, [R11,#var_10] ; r0 = 1
STR R1, [R11,#var_14] ; r1 = 2
STR R2, [R11,#var_18] ; r2 = 3
STR R3, [R11,#var_1C] ; r3 = 4
MOV R3, #1
STR R3, [R11,#var_8]
LDR R2, [R11,#var_10]
LDR R3, [R11,#var_14]
ADD R2, R2, R3 ; 1 + 2
LDR R3, [R11,#var_18]
ADD R2, R2, R3 ; 1+2+3
LDR R3, [R11,#var_1C]
ADD R2, R2, R3 ; 1+2+3+4
LDR R3, [R11,#arg_0] ; 注意这里 r11+4,就是在main中传入的第5个参数
ADD R2, R2, R3
结论: 传递基本数据类型,前4个放入寄存器r0-r3中,多于的放入栈上
传递数组
void func6(int a[], int len) {
for (int i = 0; i < len; i++) {
printf("index: %d , num: %d\n", i, a[i]);
}
}
int main() {
int a[] = {0, 1, 2};
int n = sizeof(a) / sizeof(int);
func6(a, n);
}
main函数对应的汇编
PUSH {R11,LR}
ADD R11, SP, #4
SUB SP, SP, #0x10
LDR R2, =(dword_20BC - 0x8C8)
ADD R2, PC, R2 ; dword_20BC ; r2存储数组首地址
SUB R3, R11, #-var_14
LDM R2, {R0-R2} ; 把数组[0,1,2]内容存到r0,r1,r2
STM R3, {R0-R2} ; 再存到r3所指向的栈上
MOV R3, #3
STR R3, [R11,#var_8]
SUB R3, R11, #-var_14 ; 获取数组在栈上首地址。数组首地址放到r0中,作为参数传递
MOV R0, R3 ; int *
LDR R1, [R11,#var_8] ; int
BL _Z5func6Pii ; func6(int *,int)
MOV R3, #0
MOV R0, R3
SUB SP, R11, #4
POP {R11,PC}
结论:传递数组 实际上传递的是数组首地址指针,取数组内容通过首地址偏移
传递结构体
struct st_a {
int a;
int b;
int c;
int d;
int e;
};
void func1(st_a stA) {
int a = stA.a;
int b = stA.b;
int c = stA.c;
int d = stA.d;
int e = stA.e;
printf("%d, %d \n", a, b, c, d, e);
}
int main() {
st_a stA;
stA.a = 123;
stA.b = 234;
stA.c = 345;
stA.d = 456;
stA.e = 567;
func1(stA);
}
main函数对应汇编
PUSH {R11,LR}
ADD R11, SP, #4
SUB SP, SP, #0x20
MOV R3, #123
STR R3, [R11,#var_18] ; 123 放到栈上[r11-0x18]
MOV R3, #234
STR R3, [R11,#var_14] ; 234 放到栈上[r11-0x14]
LDR R3, =345
STR R3, [R11,#var_10] ; 345 放到栈上[r11-0x10]
MOV R3, #456
STR R3, [R11,#var_C] ; 456 放到栈上[r11-0xc]
LDR R3, =567
STR R3, [R11,#var_8] ; 567 放到栈上[r11-0x8]
LDR R3, [R11,#var_8]
STR R3, [SP,#0x24+var_24] ; 567 放到栈上[sp]
SUB R3, R11, #-var_18
LDM R3, {R0-R3} ; 将 123 234 345 456放到寄存器r0,r1,r2,r3
BL _Z5func14st_a ; func1(st_a)
MOV R3, #0
MOV R0, R3
SUB SP, R11, #4
POP {R11,PC}
结论:结构体的传递和直接传递参数一样 --> func1(int a, int b, int c, int d, int e)
传递枚举
enum en_a {
p1 = 103,
p2 = 201
};
void func2(en_a enA) {
printf("%d \n", enA);
}
int main() {
func2(p1);
}
main对应汇编代码
PUSH {R11,LR}
ADD R11, SP, #4
MOV R0, #103
BL _Z5func24en_a ; func2(en_a)
MOV R3, #0
MOV R0, R3
POP {R11,PC}
结论:传递枚举,直接传递的值 类似于 func2(int a)
传递对象地址
class Person {
public:
Person() {
printf("调用\n");
}
int get() {
return this->a;
}
int getb() {
return this->b;
}
void set(int pa, int pb) {
this->a = pa;
this->b = pb;
}
private:
int a;
int b;
};
void func3(Person *person) {
printf("%d \n", person->get());
}
int main() {
Person person;
person.set(102, 222);
func3(&person);
}
main函数对应汇编
PUSH {R11,LR}
ADD R11, SP, #4
SUB SP, SP, #8
SUB R3, R11, #-var_C
MOV R0, R3 ; this 分配栈上地址,调用构造函数
BL _ZN6PersonC2Ev ; Person::Person(void)
SUB R3, R11, #-var_C
MOV R0, R3 ; this
MOV R1, #102 ; int
MOV R2, #222 ; int
BL _ZN6Person3setEii ; 调用函数的时候,会多传一个参数,为对象分配的地址 Person::set(int,int)
SUB R3, R11, #-var_C
MOV R0, R3 ; 传递的是栈上地址 Person *
BL _Z5func3P6Person ; func3(Person *)
MOV R3, #0
MOV R0, R3
SUB SP, R11, #4
POP {R11,PC}
结论:传递对象指针 传递过来的是地址
传递对象引用
void func4(Person &person) {
printf("%d \n", person.get());
}
int main() {
func4(person);
}
main函数汇编,和传递对象地址是一样的
PUSH {R11,LR}
ADD R11, SP, #4
SUB SP, SP, #8
SUB R3, R11, #-var_C
MOV R0, R3 ; this
BL _ZN6PersonC2Ev ; Person::Person(void)
SUB R3, R11, #-var_C
MOV R0, R3 ; this
MOV R1, #102 ; int
MOV R2, #222 ; int
BL _ZN6Person3setEii ; Person::set(int,int)
SUB R3, R11, #-var_C
MOV R0, R3 ; Person *
BL _Z5func4R6Person ; func4(Person &)
MOV R3, #0
MOV R0, R3
SUB SP, R11, #4
POP {R11,PC}
传递对象
void func5(Person person) {
printf("a: %d ,b: %d\n", person.get(), person.getb());
person.set(222, 333);
}
int main() {
func5(person);
}
main函数的汇编代码
PUSH {R11,LR}
ADD R11, SP, #4
SUB SP, SP, #8
SUB R3, R11, #-var_C
MOV R0, R3 ; this
BL _ZN6PersonC2Ev ; Person::Person(void)
SUB R3, R11, #-var_C
MOV R0, R3 ; this
MOV R1, #102 ; int
MOV R2, #222 ; int
BL _ZN6Person3setEii ; Person::set(int,int)
SUB R3, R11, #-var_C
LDM R3, {R0,R1} ; 将对象的属性赋值给r1和r2
BL _Z5func56Person ; func5(Person)
MOV R3, #0
MOV R0, R3
SUB SP, R11, #4
POP {R11,PC}
func5对应的部分汇编代码
PUSH {R4,R11,LR}
ADD R11, SP, #8
SUB SP, SP, #0xC
SUB R3, R11, #-var_14
STM R3, {R0,R1} ; 重新为对象分配空间并赋值
SUB R3, R11, #-var_14
MOV R0, R3 ; this
BL _ZN6Person3getEv ; Person::get(void)
结论:传递对象 传递过来的是成员变量值,在被调用方再分配空间。 c++对象内存模型中只有成员变量占对象内存空间