X64下分析调用约定的汇编代码

C代码
和X86的一样


int _fastcall fast_call(int a1, int a2, int a3, int a4, int a5)
{
    
    
	int t_a1 = a1;
	int t_a2 = a2;
	int t_a3 = a3;
	int t_a4 = a4;
	int t_a5 = a5;
	return t_a1 + t_a2 + t_a3 + t_a4 + t_a5;
}

int main()
{
    
    
	cd_call(1, 2, 3, 4, 5);
	std_call(1, 2, 3, 4, 5);
	fast_call(1, 2, 3, 4, 5);
	vector_call(1, 2, 3, 4, 5);
}

汇编代码
main函数

push rbp
sub rsp,70
lea rbp,qword ptr ss:[rsp+30]
mov dword ptr ss:[rsp+20],5
mov r9d,4
mov r8d,3
mov edx,2
mov ecx,1
call <0623_x86_x64_asm.cdcall>
mov dword ptr ss:[rsp+20],5
mov r9d,4
mov r8d,3
mov edx,2
mov ecx,1
call <0623_x86_x64_asm.stdcall>
mov dword ptr ss:[rsp+20],5
mov r9d,4
mov r8d,3
mov edx,2
mov ecx,1
call <0623_x86_x64_asm.fastcall>
mov dword ptr ss:[rsp+20],5
mov r9d,4
mov r8d,3
mov edx,2
mov ecx,1
call <0623_x86_x64_asm.vectorcall>
xor eax,eax
lea rsp,qword ptr ss:[rbp+40]
pop rbp
ret 

MS清理了windows x64平台上的函数调⽤约定,由原来的数种包阔stdcall,thiscall,fastcall,cdecl,pascal等,统⼀为⼀种新的fastcall调⽤⽅式。
要写其他的也不会出错,这主要是为了兼容以前定义的32的头文件。
_fastcall
调用函数代码

mov dword ptr ss:[rsp+20],5
mov r9d,4
mov r8d,3
mov edx,2
mov ecx,1
call <0623_x86_x64_asm.fastcall>

被调函数代码

mov dword ptr ss:[rsp+20],r9d
mov dword ptr ss:[rsp+18],r8d
mov dword ptr ss:[rsp+10],edx
mov dword ptr ss:[rsp+8],ecx
push rbp
sub rsp,60
mov rbp,rsp//lea rbp,qword ptr ss:[rsp+0]
mov eax,dword ptr ss:[rbp+70]//第一个参数a1
mov dword ptr ss:[rbp],eax
mov eax,dword ptr ss:[rbp+78]
mov dword ptr ss:[rbp+4],eax
mov eax,dword ptr ss:[rbp+80]
mov dword ptr ss:[rbp+8],eax
mov eax,dword ptr ss:[rbp+88]
mov dword ptr ss:[rbp+C],eax
mov eax,dword ptr ss:[rbp+90]
mov dword ptr ss:[rbp+10],eax
mov eax,dword ptr ss:[rbp+4]
mov ecx,dword ptr ss:[rbp]
add ecx,eax
mov eax,ecx
add eax,dword ptr ss:[rbp+8]
add eax,dword ptr ss:[rbp+C]
add eax,dword ptr ss:[rbp+10]
lea rsp,qword ptr ss:[rbp+60]
pop rbp
ret 

分析
1.ecx传递第一个参数,edx传递第二个参数,r8d传递第三个参数,r9d传递第四个参数,超过四个的参数使用堆栈传递。传参顺序也是从右至左传递
2.main函数中的sub rsp,70;lea rbp,qword ptr ss:[rsp+30]。被调函数中的sub rsp,60;mov rbp,rsp这四条语句怎么解释?
我的理解是和X86中的栈帧类似,把一个栈帧看成两个段,上面的段用于存储函数内部的局部变量,下面的段放置的是上一个函数传来的参数,在X86中,由于使用的是push,传参和开辟参数的存储空间是同时进行的,而X64不同,由父函数先开辟参数的存储空间,而赋值的任务交于子函数完成。而sub rsp,70;lea rbp,qword ptr ss:[rsp+30]这两条语句,完成了两个任务,一是开辟了存储函数自身局部变量的空间,二是开辟了存储要调用函数参数的空间,第一个空间占0x40字节,第二个空间占0x30字节。mov rbp,rsp,等价于lea rbp,qword ptr ss:[rsp+0],所以在sub rsp,60;mov rbp,rsp中,第一个空间占0x60字节,第二个空间占0字节
3.属于外平栈,调用者负责平栈
堆栈图
_fastcall堆栈图
esp=rbp> t_a1
-----------> t_a2
-----------> t_a3
-----------> t_a4
-----------> t_a5
----------->
----------->
----------->
----------->
----------->
----------->
----------->
-----------> a1
-----------> a2
-----------> a3
-----------> a4
-----------> a5

main函数堆栈图
------esp>
-----------> a1
-----------> a2
-----------> a3
-----------> a4
-----------> a5
------ebp>
------------>
------------>
------------>
------------>
------------>
------------>
------------>
16字节对齐问题
保证每次CALL之前,抬栈的大小是0X10的整数倍(包括call抬的栈)

//X64调用的约定的堆栈图真丑

猜你喜欢

转载自blog.csdn.net/sanqiuai/article/details/124386045
今日推荐