用于多态调用的x86-64汇编程序

时间:2014-03-07 02:45:34

标签: c++ assembly x86 x86-64

我有C ++代码:

int main(){
    M* m;

    O* o = new IO();
    H* h = new H("A");

    if(__rdtsc() % 5 == 0){
        m = new Y(o, h);
    }
    else{
        m = new Z(o, h);
    }

    m->my_virtual();

    return 1;
}

虚拟呼叫由此asm表示:

mov         rax,qword ptr [x]  
mov         rax,qword ptr [rax]  
mov         rcx,qword ptr [x]  
call        qword ptr [rax]

这比我对vtable方法调用的预期要多一行。是否所有四条ASM行都特定于多态调用?

以上四行怎么读伪?

这是完整的ASM和C ++(虚拟调用在最后进行):

int main(){
 add         byte ptr [rax-33333334h],bh  
 rep stos    dword ptr [rdi]  
 mov         qword ptr [rsp+0A8h],0FFFFFFFFFFFFFFFEh  
    M* x;

    o* o = new IO();
 mov         ecx,70h  
 call        operator new (013F6B7A70h) 
 mov         qword ptr [rsp+40h],rax  
 cmp         qword ptr [rsp+40h],0  
 je          main+4Fh (013F69687Fh)  
 mov         rcx,qword ptr [rsp+40h]  
 call        IO::IO (013F6814F6h)  
 mov         qword ptr [rsp+0B0h],rax  
 jmp         main+5Bh (013F69688Bh)  
 mov         qword ptr [rsp+0B0h],0  
 mov         rax,qword ptr [rsp+0B0h]  
 mov         qword ptr [rsp+38h],rax  
 mov         rax,qword ptr [rsp+38h]  
 mov         qword ptr [o],rax  
    H* h = new H("A");
 mov         ecx,150h  
 call        operator new (013F6B7A70h)  
 mov         qword ptr [rsp+50h],rax  
 cmp         qword ptr [rsp+50h],0  
 je          main+0CEh (013F6968FEh)  
 lea         rax,[rsp+58h]  
 mov         qword ptr [rsp+80h],rax  
 lea         rdx,[ec_table+11Ch (013F7C073Ch)]  
 mov         rcx,qword ptr [rsp+80h]  
 call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (013F681104h)  
 mov         qword ptr [rsp+0B8h],rax  
 mov         rdx,qword ptr [rsp+0B8h]  
 mov         rcx,qword ptr [rsp+50h]  
 call        H::H (013F6826A3h)  
 mov         qword ptr [rsp+0C0h],rax  
 jmp         main+0DAh (013F69690Ah)  
 mov         qword ptr [rsp+0C0h],0  
 mov         rax,qword ptr [rsp+0C0h]  
 mov         qword ptr [rsp+48h],rax  
 mov         rax,qword ptr [rsp+48h]  
 mov         qword ptr [h],rax  

    if(__rdtsc() % 5 == 0){
 rdtsc  
 shl         rdx,20h  
 or          rax,rdx  
 xor         edx,edx  
 mov         ecx,5  
 div         rax,rcx  
 mov         rax,rdx  
 test        rax,rax  
 jne         main+175h (013F6969A5h)  
        x = new Y(o, h);
 mov         ecx,18h  
 call        operator new (013F6B7A70h)  
 mov         qword ptr [rsp+90h],rax  
 cmp         qword ptr [rsp+90h],0  
 je          main+14Ah (013F69697Ah)  
 mov         r8,qword ptr [h]  
 mov         rdx,qword ptr [o]  
 mov         rcx,qword ptr [rsp+90h]  
 call        Y::Y (013F681B4Fh)  
 mov         qword ptr [rsp+0C8h],rax  
 jmp         main+156h (013F696986h)  
 mov         qword ptr [rsp+0C8h],0  
 mov         rax,qword ptr [rsp+0C8h]  
 mov         qword ptr [rsp+88h],rax  
 mov         rax,qword ptr [rsp+88h]  
 mov         qword ptr [x],rax  
    }
    else{
 jmp         main+1DCh (013F696A0Ch)  
        x = new Z(o, h);
 mov         ecx,18h  
 call        operator new (013F6B7A70h)  
 mov         qword ptr [rsp+0A0h],rax  
 cmp         qword ptr [rsp+0A0h],0  
 je          main+1B3h (013F6969E3h)  
 mov         r8,qword ptr [h]  
 mov         rdx,qword ptr [o]  
 mov         rcx,qword ptr [rsp+0A0h]  
 call        Z::Z (013F68160Eh)  
 mov         qword ptr [rsp+0D0h],rax  
 jmp         main+1BFh (013F6969EFh)  
 mov         qword ptr [rsp+0D0h],0  
 mov         rax,qword ptr [rsp+0D0h]  
 mov         qword ptr [rsp+98h],rax  
 mov         rax,qword ptr [rsp+98h]  
 mov         qword ptr [x],rax  
    }

    x->my_virtual();
 mov         rax,qword ptr [x]  
 mov         rax,qword ptr [rax]  
 mov         rcx,qword ptr [x]  
 call        qword ptr [rax]  

    return 1;
 mov         eax,1  
}

3 个答案:

答案 0 :(得分:6)

您可能正在查看未经优化的代码:

mov         rax,qword ptr [x]       ; load rax with object pointer
mov         rax,qword ptr [rax]     ; load rax with the vtable pointer
mov         rcx,qword ptr [x]       ; load rcx with the object pointer (the 'this' pointer)
call        qword ptr [rax]         ; call through the vtable slot for the virtual function

答案 1 :(得分:4)

mov         rax,qword ptr [x]  

获取x

指向的地址
mov         rax,qword ptr [rax]  

获取x类的vtable的地址(使用我们刚刚编写的rax)。把它放在rax中

mov         rcx,qword ptr [x]  

获取指针x并将其放在rcx中,因此它可以用作被调用函数中的“this”指针。

call        qword ptr [rax]

使用我们之前找到的vtable中的地址调用该函数(没有偏移,因为它是第一个虚函数)。

肯定有更短的方法,如果你打开优化,编译器可能会使用它(例如只有get [x]一次)。

更新了Ben Voigt的更多信息

答案 2 :(得分:2)

在伪代码中:

(*(*m->__vtbl)[0])(m)

优化版本(可以rcx用于索引吗?):

mov         rcx,qword ptr [x]       ; load rcx with object pointer
mov         rax,qword ptr [rcx]     ; load rax with the vtable pointer
call        qword ptr [rax]         ; call through the vtable slot for the virtual function

mov         rax,qword ptr [x]       ; load rax with object pointer
mov         rcx,rax                 ; copy object pointer to rcx (the 'this' pointer)
mov         rax,qword ptr [rax]     ; load rax with the vtable pointer
call        qword ptr [rax]         ; call through the vtable slot for the virtual function