Assembly code for analyzing calling conventions under X64

C code
same as 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);
}

Assembly code
main function

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 has cleaned up the function calling conventions on the windows x64 platform, and unified the original several types of calling methods, including stdcall, thiscall, fastcall, cdecl, pascal, etc., into a new fastcall calling method.
It will not go wrong if you want to write other, this is mainly for compatibility with the previously defined 32 header files.
_fastcall
call function code

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>

called function code

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 

Analysis
1.ecx passes the first parameter, edx passes the second parameter, r8d passes the third parameter, r9d passes the fourth parameter, and more than four parameters are passed using the stack. The order of passing parameters is also passed from right to left
2. sub rsp, 70 in the main function; lea rbp, qword ptr ss: [rsp+30]. How to explain the four statements sub rsp, 60; mov rbp, rsp in the called function?
My understanding is that it is similar to the stack frame in X86. A stack frame is regarded as two segments. The upper segment is used to store the local variables inside the function, and the lower segment is used to store the parameters passed by the previous function. In X86, because push is used, the parameter transfer and the storage space for the parameters are carried out at the same time. However, X64 is different. The parent function first opens up the storage space for the parameters, and the task of assignment is completed by the child function. The two statements sub rsp, 70; lea rbp, qword ptr ss:[rsp+30] have completed two tasks. One is to open up the space for storing the local variables of the function itself, and the other is to open up the space for storing the parameters of the function to be called. The first space occupies 0x40 bytes, and the second space occupies 0x30 bytes. mov rbp, rsp is equivalent to lea rbp, qword ptr ss:[ rsp +0], so in sub rsp, 60; mov rbp, rsp, the first space occupies 0x60 bytes, and the second space occupies 0 bytes ------> t_a4
----------- > t_a5 ----------- > ----------- >









----------->
----------->
----------->
----------->
----------->
-----------> a1
-----------> a2
-----------> a3
-----------> a4
-----------> a5

Main function stack diagram
------esp>
-----------> a1
-----------> a2
-----------> a3
-----------> a4
-----------> a5
------ebp>
------------>
------------>
------------>
------------>
------------>
------------>
------------>
16-byte alignment problem
Ensure that the size of the stack before each call is an integer multiple of 0X10 (including the stack lifted by the call)

//The stack graph of the X64 calling convention is really ugly

Guess you like

Origin blog.csdn.net/sanqiuai/article/details/124386045