编程知识 cdmana.com

Windows / Linux x64 assembly function calling convention

Windows/Linux x64 Assembly function call Convention

The call contract details are accurate and complete   It has been verified that So reprinted   thank you :

https://www.cnblogs.com/shines77/p/3788514.html

The reference articles above are rubbish   deleted   It's better to read my blog :

https://my.oschina.net/zengfr   

The following is the original :

1. Preface

Recently, I'm writing some string function optimization , be used x64 assembly , It's also my first contact , So I want to share with you .

2. brief introduction

x86: also called x32 , Express Intel x86 framework , namely Intel Of 32 position 80386 Assembly instruction set .

x64: Express AMD64 and Intel Of EM64T , And do not include IA64 . As for the difference between the three , Search for .

 

x64 Follow x86 Compared to register changes , Pictured :

 

As you can see from the picture ,X64 Architecture is relative to X86 Major changes in Architecture , Is to double all the original registers , for example EAX Now expand to RAX, meanwhile , New addition from R8~R15 this 8 individual 64 The register of the bit , somewhat RISC The smell of (RISC The characteristic is that there are many registers ).

 

3. x64 Calling convention

stay x86 In mode , There are three common calling conventions ,cdecl (C standard ) / stdcall(WinAPI Default ) / fastcall Function calling convention .

And in the x64 In mode , There is only one calling convention , Namely fastcall, however Windows Lower and Linux It's a little different in the next few days , Here are the introduction .

 

3.1 Windows Under the x64

Some details :

  • Windows Of x64 There is only one function calling convention , namely __fastcall , Other call convention keywords are ignored , in other words ABI Only __fastcall ;
  • When a function is called , The first four parameters are stored from left to right in RCX、RDX、R8、R9 In the register , The remaining parameters are passed through the stack , Stack from right to left ;
  • If it is int f(double a, double b, double c, double d, double e, double f) A function like this , The first four floating-point type parameters are from left to right XMM0,XMM1,XMM2,XMM3 Pass on... In turn , The remaining parameters are passed through the stack , Stack from right to left ;
  • The caller is responsible for allocating 32 Bytes of “shadow space”, It is used to store the values of the four registers where the call parameters are stored ( That is, the first four call parameters );
  • Less than 64 position (bit) The high bits are not filled with zeros when passing the parameters of ( For example, only pass ecx), That is to say, structure or union If the size is 1,2,4,8 byte , Pass... By value ( Corresponding registers ), Greater than 8 byte (64 position ) It must be according to the address ( The pointer ) Pass on ;
  • The return value of the called function is 64 Within position ( Include 64 position ) When you use the shape or pointer of , The return value will be stored in RAX;
  • If the return value is a floating point value , The return value is stored in XMM0;
  • Larger return values ( For example, structure ), It's up to the caller to allocate space on the stack , And by the RCX Hold a pointer to the space and pass it to the called function , Therefore, the registers used by integer parameters are shifted one space to the right in turn , Actually, we can only use RDX,R8,R9,3 A register , The rest of the parameters are passed through the stack . After the function call ,RAX Returns a pointer to the space ( At the beginning of a function call RCX value ).
  • caller (caller) Responsible for cleaning the stack , The called function (callee) There's no need to clear the stack , But why do we sometimes see callers (caller) I didn't clear the stack ? The back can speak ;
  • except RCX,RDX,R8,R9 outside ,RAX,R10,R11 and XMM5,XMM6 It's also “ volatile ” Of , No special protection , The remaining registers need to be protected .(x86 There is only eax, ecx, edx It's volatile )
  • Stack needs 16 Byte alignment ,“call” The instruction will be put on the stack 8 Byte function returns the address ( The address of the next instruction after a function call instruction )( notes : That is, before the function call, the original RIP The value of the instruction register ), thus , The stacks are out of alignment ( because RCX、RDX、R8、R9 Four registers are exactly 32 Bytes , yes 16 Byte Alignment , Now there are more 8 Bytes ). therefore , The leaf function of a node is not all , Must adjust the stack RSP The address for 16n+8, Align the stack .
  • about R8~R15 register , We can use r8, r8d, r8w, r8b Represent the r8 The register of 64 position 、 low 32 position 、 low 16 Bit and low 8 position .

 

About Windows x64 Call convention of , You can refer to Microsoft's official documents :

x64 Calling convention

https://docs.microsoft.com/zh-cn/cpp/build/x64-calling-convention?view=vs-2017

 

Some other small issues to pay attention to :

  • There are other small problems to pay attention to ,AMD64 I won't support it push 32bit Register instructions ,push and pop You have to use 64 Bit register , namely push rbx , Out of commission push ebx .
  • Another thing to add is , In general ,x64 Platform RBP Stack base pointers are discarded , It is only used as a general register , All stack operations go through RSP Pointer to complete .

 

About sometimes we see callers (caller) There is no reason to clear the stack :

   All say x64 Next __fastcall By the caller (caller) Clean up stack space . But we sometimes find that main() Function or by main() In the function called by the function , There is no process to clean up the sub function stack space ?

   This is because 64 The problem of stack space development on bit platform leads to . I am here CSDN I saw such a sentence on : And through PUSH and POP Instructions explicitly add and remove parameters from the stack x86 Compilers are different ,x64 In mode , The compiler leaves enough stack space , To call the maximum objective function ( Parameter method ) Anything used . And then , When calling a subfunction , It repeatedly uses the same stack area to set these parameters , So that there is no caller (caller) The process of clearing the stack repeatedly .

   What does this sentence mean ? It means that we are x64 In mode, the system will start with main() Function opens up a large stack area , however main() Function does not consume so much stack space , What do you do then ? The subfunction will continue to use main() The reserved stack space of the function , therefore main() Functions or other functions are main() Called function , There is no need to clean up the sub function stack space .

 

Example :

 Copy code
;  Sample code  1.asm
;  grammar :GoASM

DATA SECTION
text     db 'Hello x64!', 0
caption  db 'My First x64 Application', 0

CODE SECTION
START:

sub rsp, 28h           ;  Stack reservation  shadow space (32) byte  + 8  byte , Align the stack to  16  byte 

xor r9d, r9d           ; r9
lea r8, caption        ; r8
lea rdx, text          ; rdx
xor rcx, rcx           ; rcx

call MessageBoxA

add rsp, 28h           ;  The caller restores the stack himself 

ret
 Copy code

 

3.2 Linux Under the x64

Call convention details :

  • Linux The calling convention under is called “System V AMD64 ABI”, This agreement is mainly in Solaris,GNU/Linux,FreeBSD And other non Microsoft OS Upper use ;
  • Linux Of x64 There's only one function calling convention , namely __fastcall , Other call convention keywords are ignored , in other words ABI Only __fastcall ;
  • When a function is called , If the number of parameters is less than or equal to 6 Time , front 6 The parameters are stored from left to right RDI,RSI,RDX,RCX,R8,R9  In the register , The remaining parameters are passed through the stack , Stack from right to left ;
  • If the number of parameters is greater than 6 Time , front 5 The parameters are stored from left to right RDI,RSI,RDX,RCX,RAX  In the register , The remaining parameters are passed through the stack , Stack from right to left ;
  • For system calls , Use R10 Instead of RCX;
  • XMM0 ~ XMM7 Used to pass floating point parameters ;
  • Less than 64 position (bit) The high bits are not filled with zeros when passing the parameters of ( For example, only pass ecx), That is to say, structure or union If the size is 1,2,4,8 byte , Pass... By value ( Corresponding registers ), Greater than 8 byte (64 position ) It must be according to the address ( The pointer ) Pass on ;
  • The return value of the called function is 64 Within position ( Include 64 position ) When you use the shape or pointer of , The return value will be stored in RAX, If the return value is 128 Bit , Then high 64 Bit in RDX;
  • If the return value is a floating point value , The return value is stored in XMM0;
  • Larger return values ( For example, structure ), It's up to the caller to allocate space on the stack , And by the RCX Hold a pointer to the space and pass it to the called function , Therefore, the registers used by integer parameters are shifted one space to the right in turn , Actually, we can only use RDI,RSI,RDX,R8,R9,5 A register , The rest of the parameters are passed through the stack . After the function call ,RAX Returns a pointer to the space ( At the beginning of a function call RCX value ).
  • Optionally , The tuned function pushes into RBP, In order to make caller-return-rip Above it 8 Bytes , And will RBP Set to saved RBP The address of . This allows you to traverse existing stack frames , By designation GCC Of -fomit-frame-pointer Option can eliminate this problem .
  • caller (caller) Responsible for cleaning the stack , The called function (callee) There's no need to clear the stack ;
  • except  RDI,RSI,RDX,RCX,R8,R9 outside ,RAX,R10,R11 It's also “ volatile ” Of , No special protection , The remaining registers need to be protected .
  • Calling call Before the order , You have to make sure that the stack is 16 Byte Alignment ;
  • about R8~R15 register , We can use r8, r8d, r8w, r8b Represent the r8 The register of 64 position 、 low 32 position 、 low 16 Bit and low 8 position .

5. Update history

2020/09/18: Rearrange , Fix bugs , And the new Linux Under the x64 Calling convention .

2014/06/14: The initial release .

版权声明
本文为[Prosperity 3000]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201225135150346a.html

Scroll to Top