zaas 发表于 2014-11-6 21:23:51

x64 传参再分析

本帖最后由 zaas 于 2014-11-6 21:51 编辑

老飘写的还有一点没看懂:为啥第五个参数从rsp + 20开始??自己写代码测试下:
#include <windows.h>

INT64 xxx(INT64 a,INT64 b ,INT64 c,INT64 d,INT64 e,INT64 f,INT64 g,INT64 h)
{
      return a + b + c + d + e + f + g + h;

}

int yyy(int a,int b ,int c,int d,int e,int f,int g,int h)
{
      return a + b + c + d + e + f + g + h;
}

int _tmain(int argc, _TCHAR* argv[])
{
      INT64 a,b,c,d,e,f,g,h;
      int p,q,r,s,t,u,v,w;

      scanf("%I64d %I64d %I64d %I64d %I64d %I64d %I64d %I64d",&a,&b,&c,&d,&e,&f,&g,&h);
      printf("%I64d\n",xxx(a,b,c,d,e,f,g,h));
      fflush(stdin);
      scanf("%d %d %d %d %d %d %d %d",&p,&q,&r,&s,&t,&u,&v,&w);
      printf("%d\n",yyy(p,q,r,s,t,u,v,w));
      return 0;
}传参:


000000013FDF1147   mov         rax,
000000013FDF114F   mov         ,rax
000000013FDF1154   mov         rax,
000000013FDF115C   mov         ,rax
000000013FDF1161   mov         rax,
000000013FDF1169   mov         ,rax
000000013FDF116E   mov         rax,
000000013FDF1176   mov         ,rax
000000013FDF117B   mov         r9,
000000013FDF1183   mov         r8,
000000013FDF118B   mov         rdx,
000000013FDF1190   mov         rcx,
000000013FDF1195   call      @ILT+0(?xxx@@YA_J_J0000000@Z)rcx,rdx,r8,r9,,,,
到函数里边:
00000013FDF1030   mov         ,r9
000000013FDF1035   mov         ,r8
000000013FDF103A   mov         ,rdx
000000013FDF103F   mov         ,rcx也就是说到函数里边,还是先把rcx,rdx,r8,r9放到堆栈对应的位置去。。。
即使被调用函数的参数少于 4 个,该函数实际上也占有这 4 个堆栈位置,并可将这几个位置用于保存参数寄存器值以外的其他目的。 因此,在整个函数调用过程中,调用方不会将信息保存在此堆栈区域中。
少于4个参数的情况
00000013F441088   mov         rdx,
000000013F44108D   mov         rcx,
000000013F441092   call      @ILT+0(?xxx@@YA_J_J0@Z)函数内部:
000000013F441020   mov         ,rdx
000000013F441025   mov         ,rcx这样的话,如果已知函数参数已知,没必要从rsp去取参数了,少于5个的参数可以直接从寄存器得到

那么,传指针的情况呢?
#include <windows.h>

void xxx(INT64 a,INT64 b ,INT64 c,INT64 d,INT64 e,INT64 *p)
{
                *p = a + b + c + d + e;
}

int _tmain(int argc, _TCHAR* argv[])
{
      INT64 a,b,c,d,e;
      INT64 x = 0;      

      scanf("%I64d %I64d %I64d %I64d %I64d",&a,&b,&c,&d,&e);
      xxx(a,b,c,d,e,&x);
      printf("%I64d\n",x);

      return 0;
}000000013FE210D9   lea         rax,
000000013FE210E1   mov         ,rax
000000013FE210E6   mov         rax,
000000013FE210EE   mov         ,rax
000000013FE210F3   mov         r9,
000000013FE210FB   mov         r8,
000000013FE21100   mov         rdx,
000000013FE21105   mov         rcx,
000000013FE2110A   call      @ILT+0(?xxx@@YAX_J0000PEA_J@Z)
000000013FE2110F   mov         rdx,
传参方式不变。传入的 x在
取的时候还直接取
函数内部:
000000013FE21054   mov         rcx,
000000013FE21059   mov         ,rax那么,局部变量呢?#include <windows.h>

void xxx(INT64 a,INT64 b ,INT64 c,INT64 *p)
{
                int d = 4;
                int e = 5;
                *p = a + b + c + d + e;
}

int _tmain(int argc, _TCHAR* argv[])
{
        INT64 a,b,c;
        INT64 x = 0;       

        scanf("%I64d %I64d %I64d",&a,&b,&c);
        xxx(a,b,c,&x);
        printf("%I64d\n",x);

        return 0;
}永远不变的是先把rcx,rdx,r8,r9放到堆栈,然后sub esp,给局部变量腾空间
000000013F121020   mov         ,r9
000000013F121025   mov         ,r8
000000013F12102A   mov         ,rdx
000000013F12102F   mov         ,rcx
000000013F121034   push      rdi
000000013F121035   sub         rsp,0x10
000000013F121039   mov         rdi,rsp
000000013F12103C   mov         ecx,0x4
000000013F121041   mov         eax,0xCCCCCCCC
000000013F121046   rep stosd   
000000013F121048   mov         rcx,
000000013F12104D   mov         dword ptr ,0x4
000000013F121054   mov         dword ptr ,0x5

vipcrack 发表于 2014-11-6 23:28:44

膜拜大神……

lucky_789 发表于 2014-11-7 02:20:02

这个是否和编译优化有关系呢?

Nisy 发表于 2014-11-7 09:52:02

不错 有时间再试试浮点型数据传参 大大的惊喜

Dxer 发表于 2014-11-7 14:09:39

我来收藏了。谢谢zaas大侠

小柯师傅 发表于 2014-11-7 18:49:14

学习 看懂就可以调用64位未知DLL了

F8LEFT 发表于 2014-11-8 18:22:05

厉害,学到不少东西
页: [1]
查看完整版本: x64 传参再分析