zoukankan      html  css  js  c++  java
  • windows编程--x64调用约定

    windows32位程序包括stdcall,thiscall,fastcall,cdecl,clrcall,vectorcall,nakedcall等调用方式,x64位程序默认使用新的fastcall调用方式。

    这种调用方式得益于x64平台寄存器数量的增加。  

    x64 fastcall调用约定

    空间大于8字节的参数用参照传递,不能把一个参数分割到多个寄存器中进行传递;前四个整型或指针类型参数从左到右由RCX,RDX,R8,R9依次传递,前四个浮点类型参数从左到右由XMM0,XMM1,XMM2,XMM3依次传递。第五个和其后的参数通过栈传递,参数从右到左一次入栈。

    __m128 类型, 数组和字符串不能通过值传递,只能通过指针。

    结构体和union如果大小是1,2,4,8字节,用整数的传参方式;否则通过指针传递。

    小于等于64位的整型或指针类型返回值由RAX传递。
    浮点返回值由XMM0传递。

    更大的返回值(比如结构体),由调用方在栈上分配空间,并由RCX持有该空间的指针并传递给被调用函数,因
    此整型参数使用的寄存器依次右移一格,实际只可以利用3个寄存器,其余参数入栈。函数调用结束后,RAX返
    回该空间的指针(就是rcx的值)。

    Varargs(可变参数)也通过上述方式进行传参。

    调用函数为前四个参数在调用栈上保留相应的空间,称作shadow space或spill slot。即使被调用方没有或小
    于4个参数,调用函数仍然保留那么多的栈空间,这有助于在某些特殊情况下简化调用约定。
    由调用函数负责清理调用栈。

    除RCX,RDX,R8,R9以外,RAX、R10、R11、XMM4 和 XMM5也是易变化的(volatile)寄存器。


    RBX, RBP, RDI, RSI, R12, R14, R14, and R15寄存器则必须在使用时进行保护。
    在寄存器中,所有参数都是右对齐的。小于64位的参数并不进行高位零扩展,也就是高位是无法预测的垃圾数据.

    参数传递示例

     1 int func1(int a, int b, int c, int d, int e, double f) {
     2     return 9;
     3 }
     4 
     5 int func2(int a, int b, int c, int d, int e, double f,int g) {
     6     return 90;
     7 }
     8 
     9 int main() {
    10     int r = func1(1, 2, 3, 4, 5, 6.6);
    11     int r2 = func2(1, 2, 3, 4, 5, 6.6,7);
    12     return 0;
    13 }

    反汇编:

     1 int r2 = func2(1, 2, 3, 4, 5, 6.6,7);
     2 00007FF65F263D0E  mov         dword ptr [rsp+30h],7  
     3 00007FF65F263D16  movsd       xmm0,mmword ptr [__real@401a666666666666 (07FF65F269BB0h)]  
     4 00007FF65F263D1E  movsd       mmword ptr [rsp+28h],xmm0  
     5 00007FF65F263D24  mov         dword ptr [rsp+20h],5  
     6 00007FF65F263D2C  mov         r9d,4  
     7 00007FF65F263D32  mov         r8d,3  
     8 00007FF65F263D38  mov         edx,2  
     9 00007FF65F263D3D  mov         ecx,1  
    10 00007FF65F263D42  call        func2 (07FF65F261375h)  
    11 00007FF65F263D47  mov         dword ptr [r2],eax  
    12     return 0;
    13 00007FF65F263D4A  xor         eax,eax  

    返回结构体示例:

     1 S1 func3(int a, int b, int c, int d) {
     2     S1 s{6,7,8,9,11,12};
     3     return s;
     4 }
     5 int main() {
     6     int r = func1(1, 2, 3, 4, 5, 6.6);
     7     int r2 = func2(1, 2, 3, 4, 5, 6.6,7);
     8     S1 r3 = func3(1, 2, 3, 4);
     9     return 0;
    10 }

    反汇编

     1 S1 func3(int a, int b, int c, int d) {
     2 00007FF68A271750  mov         dword ptr [rsp+20h],r9d  
     3 00007FF68A271755  mov         dword ptr [rsp+18h],r8d  
     4 00007FF68A27175A  mov         dword ptr [rsp+10h],edx  
     5 00007FF68A27175E  mov         qword ptr [rsp+8],rcx   //这里rcx存放着调用函数提前分配好的用于存放返回的结构体的指针,由于rcx用来存放返回值地址,第一个参数改由edx传递,后面的参数一次后延。
     6 00007FF68A271763  push        rbp  
     7 00007FF68A271764  push        rsi  
     8 00007FF68A271765  push        rdi  
     9 00007FF68A271766  sub         rsp,110h  
    10 00007FF68A27176D  lea         rbp,[rsp+20h]  
    11 00007FF68A271772  mov         rdi,rsp  
    12 00007FF68A271775  mov         ecx,44h  
    13 00007FF68A27177A  mov         eax,0CCCCCCCCh  
    14 00007FF68A27177F  rep stos    dword ptr [rdi]  
    15 00007FF68A271781  mov         rcx,qword ptr [rsp+138h]  
    16 00007FF68A271789  lea         rcx,[__AD28E9E4_源@cpp (07FF68A280000h)]  
    17 00007FF68A271790  call        __CheckForDebuggerJustMyCode (07FF68A271082h)  
    18     S1 s{6,7,8,9,11,12};
    19 00007FF68A271795  mov         dword ptr [s],6  
    20 00007FF68A27179C  mov         dword ptr [rbp+0Ch],7  
    21 00007FF68A2717A3  mov         dword ptr [rbp+10h],8  
    22 00007FF68A2717AA  mov         dword ptr [rbp+14h],9  
    23 00007FF68A2717B1  mov         dword ptr [rbp+18h],0Bh  
    24 00007FF68A2717B8  mov         dword ptr [rbp+1Ch],0Ch  
    25     return s;
    26 00007FF68A2717BF  lea         rax,[s]  
    27 00007FF68A2717C3  mov         rdi,qword ptr [rbp+110h]  //rbp+110h里存放的是从rcx里传进来的调用函数分配的用户存放返回值的指针
    28 00007FF68A2717CA  mov         rsi,rax  
    29 00007FF68A2717CD  mov         ecx,18h  
    30 00007FF68A2717D2  rep movs    byte ptr [rdi],byte ptr [rsi]  //上面几行是将s结构体的数据复制到调用函数分配好的空间里(rcx传进来的)
    31 00007FF68A2717D4  mov         rax,qword ptr [rbp+110h]  //将返回值指针赋值给rax
    32 }

     

  • 相关阅读:
    Unity The Method Signature Matching Rule
    Unity The Property Matching Rule
    Unity The Type Matching Rule
    Unity The Custom Attribute Matching Rule
    Unity The Member Name Matching Rule
    Unity No Policies
    Unity The Return Type Matching Rule
    Unity The Parameter Type Matching Rule
    Unity The Namespace Matching Rule
    关于TSQL递归查询的(转)
  • 原文地址:https://www.cnblogs.com/niao-ge/p/12055729.html
Copyright © 2011-2022 走看看