在寄存器前加星号的含义是什么?

13

我正在研究C++如何通过汇编语言调用正确的成员函数。 我想到的一个简单程序如下:

class A                        
{                              
    public:                    
        virtual void show() {} 
};                             

class B : public A             
{                              
    public:                    
        void show() {}         
};                             


int main()                     
{                              
    A* pA = new B;             
    pA->show();                

    return 0;                  
}                              

它的组装如下:

main:
.LFB2:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $24, %rsp
    movl    $8, %edi
    .cfi_offset 3, -24
    call    _Znwm            <<<================ 1
    movq    %rax, %rbx
    movq    %rbx, %rax
    movq    %rax, %rdi
    call    _ZN1BC1Ev
.L11:
    movq    %rbx, %rax
    movq    %rax, -24(%rbp)
    movq    -24(%rbp), %rax
    movq    (%rax), %rax
    movq    (%rax), %rdx
    movq    -24(%rbp), %rax
    movq    %rax, %rdi
    call    *%rdx             <<<=== 2
    movl    $0, %eax
    addq    $24, %rsp
    popq    %rbx
    leave
    ret
    .cfi_endproc

我的问题是:

  1. 我在谷歌上搜索nwm,只发现它用于C++中分配内存,有人可以告诉我更多吗?它在一个库中吗?如果可能的话,我可以获得它的源代码吗?
  2. 我对这种语法不太熟悉,它想要做什么?

2
你的代码存在内存泄漏问题,顺便说一下...每个new操作都必须与一个delete操作相匹配... - Goz
4
@Goz: 可能Alex已经知道这一点,只是想创建一个“简短、自包含、正确(可编译)、示例”的示例 - Martin Liversage
@Goz,我认为Martin Liversage已经回答了你的问题,感谢Martin的回答,也感谢你为我指出这个问题。 - Alex
1
在编译的C++代码中,通常会看到call *%reg,其中使用动态分派调用虚拟方法。 _Znwm::operator new (size_t)函数的名称修饰。 - Brett Hale
可能是What does an asterisk * before an address mean in x86-64 AT&T assembly?的重复问题。我也是在反编译virtual后来到这里的,所以点了+1。 - Ciro Santilli OurBigBook.com
1个回答

19
在AT&T汇编语法中,对于调用或跳转指令, * 用于绝对地址。这意味着它将跳转到寄存器中包含的地址。另一种方法是相对跳转,相对于当前指令。
来自GNU as手册

AT&T绝对(而不是PC相对)跳转/调用操作数以`*`为前缀;在Intel语法中,它们没有分隔符。

在您的代码中,使用寄存器中的地址进行调用是有意义的。调用pA->show()需要查找要调用的正确函数。这是因为它是类A上的虚拟函数。

我写这个是为了确保自己理解正确。根据你提供的链接,这是否意味着它将调用存储在该寄存器中的地址开始的函数? - Alex
@GavinSmith,一个寄存器是否也可以包含一个偏移量,以便跳转到该偏移地址,而不是绝对地址?否则,这个引用无论如何都没有意义。 - Devolus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接