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

时间:2022-02-04 02:55:37

I have the C++ code:

我有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;
}

where the virtual call is represented by this asm:

其中虚拟调用由asm表示:

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

It is one more line than I was expecting for the vtable method invoccation. Are all four of the ASM lines specific to the polymorphic call?

这比我预期的vtable方法调用多了一行。ASM中所有的四条线都是针对多态调用的吗?

How do the above four lines read pseudo-ly?

以上四行如何读伪ly?

This is the complete ASM and C++ (the virtual call is made right at the end):

这是完整的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 个解决方案

#1


6  

You're probably looking at unoptimized code:

您可能会看到未优化的代码:

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

#2


4  

mov         rax,qword ptr [x]  

get the address pointed to by x

得到x指向的地址

mov         rax,qword ptr [rax]  

get the address of the vtable for x's class (using rax we just worked out). Put it in rax

获取x类的vtable的地址(使用我们刚刚计算出来的rax)。把它放在伸展

mov         rcx,qword ptr [x]  

get the pointer x and put it in rcx, so it can be used as the "this" pointer in the called function.

获取指针x并将其放入rcx中,以便在调用函数中将其用作“this”指针。

call        qword ptr [rax]

call the function using the address from the vtable we found earlier (no offset as it is the first virtual function).

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

There are definitely shorter ways to do it, which the compiler might use if you switch optimizations on (e.g. only get [x] once).

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

Updated with more info from Ben Voigt

Ben Voigt更新了更多信息

#3


2  

In pseudo-code:

在伪代码:

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

Optimized version (can rcx be used for indexing?):

优化版本(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

or

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

#1


6  

You're probably looking at unoptimized code:

您可能会看到未优化的代码:

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

#2


4  

mov         rax,qword ptr [x]  

get the address pointed to by x

得到x指向的地址

mov         rax,qword ptr [rax]  

get the address of the vtable for x's class (using rax we just worked out). Put it in rax

获取x类的vtable的地址(使用我们刚刚计算出来的rax)。把它放在伸展

mov         rcx,qword ptr [x]  

get the pointer x and put it in rcx, so it can be used as the "this" pointer in the called function.

获取指针x并将其放入rcx中,以便在调用函数中将其用作“this”指针。

call        qword ptr [rax]

call the function using the address from the vtable we found earlier (no offset as it is the first virtual function).

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

There are definitely shorter ways to do it, which the compiler might use if you switch optimizations on (e.g. only get [x] once).

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

Updated with more info from Ben Voigt

Ben Voigt更新了更多信息

#3


2  

In pseudo-code:

在伪代码:

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

Optimized version (can rcx be used for indexing?):

优化版本(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

or

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