| 
注册时间2005-6-29
阅读权限255
最后登录1970-1-1UID2198 副坛主   
 
 该用户从未签到 | 
 
| 正好这三天看一下这方面的资料,希望可以有所收获。 
 看X64的汇编,得先去弄明白这几个事情:
 一方面是看官方文档,找点资料,另一方面自行事件,非亲眼所见的东西都不靠谱。
 
 http://msdn.microsoft.com/zh-cn/library/h2k70f3s.aspx
 
 
 先来个下马威,EXE的载入的默认基地址是大于 0xFFFF-FFFF的,当然用户也可以指定基地址。
 
 
   
 一、传参,先看非浮点的。
 
 参数小于4,参数大于4。谁去平衡堆栈,调用系统 stdcall 和 cdecl 的堆栈平衡。X64使用 __vectorcall 调用约定 ...
 
 
 复制代码
// DEBUG 编译
000000013F6B197D | B9 01 00 00 00           | mov ecx,1                               | ;crtexe.c:527
000000013F6B1982 | FF 15 10 9B 00 00        | call qword ptr ds:[<__imp__CrtSetCheckC |
000000013F6B1988 | 4C 8B 1D 11 9B 00 00     | mov r11,qword ptr ds:[<__imp___winitenv | ;crtexe.c:582
000000013F6B198F | 48 8B 05 DA 77 00 00     | mov rax,qword ptr ds:[<envp>]           |
000000013F6B1996 | 49 89 03                 | mov qword ptr ds:[r11],rax              | ;r11:__winitenv
000000013F6B1999 | 4C 8B 05 D0 77 00 00     | mov r8,qword ptr ds:[<envp>]            | ;crtexe.c:583
000000013F6B19A0 | 48 8B 15 D1 77 00 00     | mov rdx,qword ptr ds:[<argv>]           |
000000013F6B19A7 | 8B 0D BB 77 00 00        | mov ecx,dword ptr ds:[<argc>]           |
000000013F6B19AD | E8 6C F6 FF FF           | call <testasm64.@ILT+25(wmain)>         |
// 为什么没有看到调用函数前先把堆栈空间申请出来,函数内就直接用 RSP+XX 往里塞数据了,看下文解释 ....
int _tmain(int argc, _TCHAR* argv[]) 
000000013F6B1140 | 48 89 54 24 10           | mov qword ptr ss:[rsp+10],rdx           | ;testasm64.cpp:29
000000013F6B1145 | 89 4C 24 08              | mov dword ptr ss:[rsp+8],ecx            |
000000013F6B1149 | 57                       | push rdi                                |
000000013F6B114A | 48 81 EC 90 00 00 00     | sub rsp,90                              |
000000013F6B1151 | 48 8B FC                 | mov rdi,rsp                             |
000000013F6B1154 | 48 B9 24 00 00 00 00 00  | mov rcx,24                              |
000000013F6B115E | B8 CC CC CC CC           | mov eax,CCCCCCCC                        |
000000013F6B1163 | F3 AB                    | rep stos dword ptr es:[rdi]             |
....
000000013F6B1247 | 48 81 C4 90 00 00 00     | add rsp,90                              |
000000013F6B124E | 5F                       | pop rdi                                 |
000000013F6B124F | C3                       | ret                                     |
 
 01.  函数内基本看不到再用 EBP 去寻址,全部变成用 ESP 来寻址参数及其函数内局部变量了。
 
 函数内部无需保存的寄存器:
 RAX, RCX, RDX, R8, R9, R10, R11  (一下子可以多用4个寄存器,爽歪歪)
 函数内部无需保存的寄存器:
 RBX, RSP, RBP, RSI, RDI, R12~R15 (前五个寄存器和X86是一样的,后边四个算是福利了)
 
 所以编译器,在函数内部能不使用后边的寄存器就不使用,所以基本看不到 PUSHAD POPAD 这样的全部压栈指令了。
 
 02. 我们来看下,为啥函数调用方不去申请 RSP 空间,而函数内部就可以直接给 RSP+XX 赋值:
 
 
 复制代码
__declspec(noinline)
int
__tmainCRTStartup(
        void
        )
{
        __try
        {
            void *lock_free=0;
            void *fiberid=((PNT_TIB)NtCurrentTeb())->StackBase;
            int nested=FALSE;
            while((lock_free=InterlockedCompareExchangePointer((volatile PVOID *)&__native_startup_lock, fiberid, 0))!=0)
            {
                 ....
            }
            if (__native_startup_state == __initializing)
            {
                _amsg_exit( _RT_CRT_INIT_CONFLICT);
            }
            else if (__native_startup_state == __uninitialized)
            {
                __native_startup_state = __initializing;
                if (_initterm_e( __xi_a, __xi_z ) != 0)    // here ...
                {
                    return 255;
                }
            }
            else
            {
                has_cctor = 1;
            }
000000013F6F1820 | 48 83 EC 68              | sub rsp,68                                    | ;crtexe.c:410
000000013F6F1824 | 48 C7 44 24 40 00 00 00  | mov qword ptr ss:[rsp+40],0                   | ;+40 // void *lock_free
000000013F6F182D | E8 EE 01 00 00           | call <testasm64.NtCurrentTeb>                 | ;crtexe.c:458
000000013F6F1832 | 48 8B 40 08              | mov rax,qword ptr ds:[rax+8]                  |
000000013F6F1836 | 48 89 44 24 38           | mov qword ptr ss:[rsp+38],rax                 | ;+38 // void *fiberid
000000013F6F183B | C7 44 24 30 00 00 00 00  | mov dword ptr ss:[rsp+30],0                   | ;+30 // int nested
000000013F6F1843 | 48 8B 54 24 38           | mov rdx,qword ptr ss:[rsp+38]                 | ;crtexe.c:460
000000013F6F1848 | 48 8D 0D 01 7F 00 00     | lea rcx,qword ptr ds:[<__native_startup_lock> | ;rcx:__xi_a
000000013F6F184F | 33 C0                    | xor eax,eax                                   | ;0
000000013F6F1851 | F0 48 0F B1 11           | lock cmpxchg qword ptr ds:[rcx],rdx           | ;rcx:__xi_a, rdx:__xi_z
000000013F6F1856 | 48 89 44 24 40           | mov qword ptr ss:[rsp+40],rax                 |
000000013F6F185B | 48 83 7C 24 40 00        | cmp qword ptr ss:[rsp+40],0                   | ;跟0比较
000000013F6F1861 | 74 23                    | je testasm64.13F6F1886                        |
000000013F6F1863 | 48 8B 44 24 38           | mov rax,qword ptr ss:[rsp+38]                 | ;crtexe.c:462
000000013F6F1868 | 48 39 44 24 40           | cmp qword ptr ss:[rsp+40],rax                 |
000000013F6F186D | 75 0A                    | jnz testasm64.13F6F1879                       |
000000013F6F186F | C7 44 24 30 01 00 00 00  | mov dword ptr ss:[rsp+30],1                   | ;crtexe.c:464
000000013F6F1877 | EB 0D                    | jmp testasm64.13F6F1886                       | ;crtexe.c:465
000000013F6F1879 | B9 E8 03 00 00           | mov ecx,3E8                                   | ;crtexe.c:472
000000013F6F187E | FF 15 6C 9A 00 00        | call qword ptr ds:[<__imp_Sleep>]             |
000000013F6F1884 | EB BD                    | jmp testasm64.13F6F1843                       | ;crtexe.c:473
000000013F6F1886 | 8B 05 B4 7E 00 00        | mov eax,dword ptr ds:[<__native_startup_state | ;crtexe.c:475
000000013F6F188C | 83 F8 01                 | cmp eax,1                                     |
000000013F6F188F | 75 0C                    | jnz testasm64.13F6F189D                       |
000000013F6F1891 | B9 1F 00 00 00           | mov ecx,1F                                    | ;crtexe.c:477
000000013F6F1896 | E8 95 0D 00 00           | call <testasm64._amsg_exit>                   |
000000013F6F189B | EB 41                    | jmp testasm64.13F6F18DE                       |
000000013F6F189D | 8B 05 9D 7E 00 00        | mov eax,dword ptr ds:[<__native_startup_state | ;crtexe.c:479
000000013F6F18A3 | 85 C0                    | test eax,eax                                  |
000000013F6F18A5 | 75 2D                    | jnz testasm64.13F6F18D4                       |
000000013F6F18A7 | C7 05 8F 7E 00 00 01 00  | mov dword ptr ds:[<__native_startup_state>],1 | ;crtexe.c:481
000000013F6F18B1 | 48 8D 15 A8 4D 00 00     | lea rdx,qword ptr ds:[<__xi_z>]               | ;crtexe.c:483
000000013F6F18B8 | 48 8D 0D 71 4A 00 00     | lea rcx,qword ptr ds:[<__xi_a>]               | ;rcx:__xi_a
000000013F6F18BF | E8 74 10 00 00           | call <testasm64._initterm_e>                  | ;这个时候 RSP 就没有变过 ... 
000000013F6F18C4 | 85 C0                    | test eax,eax                                  |
// call <testasm64._initterm_e>
000000005B992A60 | 48 89 54 24 10           | mov qword ptr ss:[rsp+10],rdx                 | ;rdx:__xi_z
000000005B992A65 | 48 89 4C 24 08           | mov qword ptr ss:[rsp+8],rcx                  | ;rcx:__xi_a
000000005B992A6A | 48 83 EC 38              | sub rsp,38                                    |
 
   
 
 000-002BFCC0 : -68 // sub rsp,68
 
 XXXX  // 函数参数 START 这里预留给本函数内,调用其他函数(B)时函数B的预留参数位置。猜测预留参数个数是本函数内调用函数的参数最大值。
 XXXX
 XXXX
 XXXX
 XXXX  // 超过四个参数时 第五个之后直接从这里开始赋值
 XXXX  // 函数参数 End 最大参数个数
 CCCC // 局部变量 START 这里是函数内部的变量 预留空间,DEBUG是有多少分配多少,Release应该会有所优化。
 CCCC
 CCCC
 CCCC // 局部变量 END
 
 000-002BFD28 : 进到函数时的 ESP
 
 所以,函数内调用函数B时,ESP总在 000-002BFCC0(-68) 这里,为什么这么NB,因为X64空间无限大,有内存就可以这样任性 。。。
 
 3. Release 编译:
 
 
 复制代码
// scanf( "%d %c",&a,&c);
0000000070A62E30 | 48 8B C4                 | mov rax,rsp                                   |
0000000070A62E33 | 48 89 48 08              | mov qword ptr ds:[rax+8],rcx                  |
0000000070A62E37 | 48 89 50 10              | mov qword ptr ds:[rax+10],rdx                 |
0000000070A62E3B | 4C 89 40 18              | mov qword ptr ds:[rax+18],r8                  |
0000000070A62E3F | 4C 89 48 20              | mov qword ptr ds:[rax+20],r9                  |
0000000070A62E43 | 48 83 EC 28              | sub rsp,28                                    |
0000000070A62E47 | 48 8B D1                 | mov rdx,rcx                                   |
0000000070A62E4A | 4C 8D 48 10              | lea r9,qword ptr ds:[rax+10]                  |
0000000070A62E4E | 48 8D 0D 13 16 02 00     | lea rcx,qword ptr ds:[70A84468]               |
0000000070A62E55 | 45 33 C0                 | xor r8d,r8d                                   |
0000000070A62E58 | E8 A7 48 00 00           | call msvcr90.70A67704                         |
0000000070A62E5D | 48 83 C4 28              | add rsp,28                                    |
0000000070A62E61 | C3                       | ret                                           |
 用 RAX 来寻址参数
 
 在X64下,全部由函数内部来维护堆栈平衡,自己获取参数,自己申请空间处理变量, sub rsp, xx,  最后恢复堆栈 ret .
 
 4. 参数全部为浮点数,或参数为浮点+非浮点。
 以后再看 ...
 
 二、类机制传参分析。
 
 
 
 复制代码
NsTestX64::NsTestX64(void)
{
    double bb = 12.36;
    m_a = 0;
    m_b = TRUE;
}
000000013FB71360 | 48 89 4C 24 08           | mov qword ptr ss:[rsp+8],rcx                  | ;this 指针仍然放于 rcx
000000013FB71365 | 57                       | push rdi                                      |
000000013FB71366 | 48 83 EC 10              | sub rsp,10                                    |
000000013FB7136A | 48 8B FC                 | mov rdi,rsp                                   |
000000013FB7136D | 48 B9 04 00 00 00 00 00  | mov rcx,4                                     |
000000013FB71377 | B8 CC CC CC CC           | mov eax,CCCCCCCC                              |
000000013FB7137C | F3 AB                    | rep stos dword ptr es:[rdi]                   |
000000013FB7137E | 48 8B 4C 24 20           | mov rcx,qword ptr ss:[rsp+20]                 |
000000013FB71383 | F2 0F 10 05 6D 55 00 00  | movsd xmm0,qword ptr ds:[13FB768F8]           |
000000013FB7138B | F2 0F 11 04 24           | movsd qword ptr ss:[rsp],xmm0                 |
000000013FB71390 | 48 8B 44 24 20           | mov rax,qword ptr ss:[rsp+20]                 | ;this 给 rax 去寻址
000000013FB71395 | 48 C7 00 00 00 00 00     | mov qword ptr ds:[rax],0                      |
000000013FB7139C | 48 8B 44 24 20           | mov rax,qword ptr ss:[rsp+20]                 |
000000013FB713A1 | C7 40 08 01 00 00 00     | mov dword ptr ds:[rax+8],1                    |
000000013FB713A8 | 48 8B 44 24 20           | mov rax,qword ptr ss:[rsp+20]                 |
000000013FB713AD | 48 83 C4 10              | add rsp,10                                    |
000000013FB713B1 | 5F                       | pop rdi                                       |
000000013FB713B2 | C3                       | ret                                           |
 复制代码
obj.NsSetThreeParam( TRUE, &a, ii );
// this 指针仍处于 RCX 中
000000013FB71213 | 4C 8B 8C 24 80 00 00 00  | mov r9,qword ptr ss:[rsp+80]                  | ;__int64
000000013FB7121B | 4C 8D 44 24 44           | lea r8,qword ptr ss:[rsp+44]                  | ;PVOID
000000013FB71220 | BA 01 00 00 00           | mov edx,1                                     | ;TURE
000000013FB71225 | 48 8D 8C 24 98 00 00 00  | lea rcx,qword ptr ss:[rsp+98]                 | ;this 
000000013FB7122D | E8 D3 FD FF FF           | call testasm64_.13FB71005                     |
 类机制的话和X86传参一样 this指针放 rcx 中,可认为是普通函数多了第一个参数。
 
 
 三、异常机制分析。(不使用SEH链了 )
 以后再看 ...
 
 | 
 评分
查看全部评分
 |