本帖最后由 aa328496536 于 2019-10-8 15:05 编辑
1:参数传递不同 , x86是以压栈实现传入参数(例如:push 1 push 2) , 而到了x64则是 rcx rdx r8 r9 [rsp+0x20] [rsp+0x28] 从左往右传递参数 , 前4个参数是固定的,如果超过4个参数则堆栈传递,如[rsp+0x20]
当参数小于4个
c函数:LONG64 add(LONG64 a, LONG64 b, LONG64 c, LONG64 d ) { return a + b + c + d ; } 汇编代码: mov r9d , 4 mov r8d , 3 mov edx , 2 mov ecx , 1 call add 调用代码: add(1 , 2 , 3 , 4 );
总结:可以看出当参数等于4个时候,参数的传递是以 rcx rdx r8 r9 来依次传递
当参数大于4个
c函数:LONG64 add(LONG64 a, LONG64 b, LONG64 c, LONG64 d , LONG64 e , LONG64 f , LONG64 g )
{
return a + b + c + d + e + f + g;
}
汇编代码: mov qword ptr [rsp+30h],7 mov qword ptr [rsp+28h],6 mov qword ptr [rsp+20h],5 mov r9d , 4 mov r8d , 3 mov edx , 2 mov ecx , 1 call add
调用代码:add(1 , 2 , 3 , 4 , 5 , 6 , 7);总结:可以看出当参数大于4个参数时候,多余的参数则以堆栈传递
当参数为结构体,且大小小于等于8字节
struct S
{
int x1;
int x2;
};
LONG64 add(S s1 )
{
return s1.x1 + s1.x2;
}
调用代码:
S s1 = {1 , 2};
add(s1);
汇编代码:
mov dword ptr [rsp+8] , 1
mov dword ptr [rsp+c] , 2
mov rcx , qword ptr[rsp+8]
call add
总结:如果参数为结构体且结构体小于等于8字节,在传递结构体参数时,应直接把结构体的内容放在寄存器中
当参数为结构体,且大小大于8字节 c函数: struct S
{
int x1;
int x2;
int x3;
int x4;
}; LONG64 add(S s1 )
{
return s1.x1 + s1.x2 + s1.x3 + s1.x4;
}
调用代码:
S s1 = {1 , 2 , 3 , 4};
add(s1);
汇编代码:
mov dword ptr [rsp+8] , 1
mov dword ptr [rsp+c] , 2
mov dword ptr [rsp+10] , 3
mov dword ptr [rsp+14] , 4
lea rax , [rsp + 100h]lea rcx , [rsp + 8]
mov rdi , rax
mov rsi , rcx
mov rcx , 10hrep
movs byte ptr[rdi] , byte ptr[rsi]
lea rcx , [rsp + 100h]
call add
总结:通过以上代码可以看出,如果参数是结构体且大于8个字节,在传递参数时,会先把结构体内容复制到栈空间中,再把结构地址当成函数的参数来传递
thiscall调用约定,他是c++类的成员函数调用约定:
c代码:
class CAdd
{
public:
int add(int nNum1, int nNum2)
{
return nNum1 + nNum2;
}
};
调用代码:
CAdd ob;
ob.add(1 , 2);
汇编代码:
mov r8d , 2
mov edx , 1
lea rcx , [rsp + 4]
call CAdd::add
总结:通过这个实例可以知道,类的成员函数调用,参数传递方式和普通函数没有很大区别,唯一区别是,成员函数调用会隐藏的传递一个this指针参数

|