编写自定义纯虚拟处理程序:调用时堆栈和寄存器的状态是什么

Writing a custom pure virtual handler: What is the state of the stack and registers when it is called

因此可以使系统调用成为纯虚函数的自定义函数[1]。这就提出了这样一个功能可以做什么的问题。对于海湾合作委员会

Vtable for Foo
Foo::_ZTV3Foo: 5u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI3Foo)
16    0u
24    0u
32    (int (*)(...))__cxa_pure_virtual

并且,直接放在纯虚函数的槽中。由于函数原型 void foo() 与真实签名不匹配,堆栈是否仍然正常?特别是,我可以抛出异常并在某处捕获它并继续执行吗?

[1] Is there an equivilant of _set_purecall_handler() in Linux?

阅读x86-64 ABI supplement to understand what is really happening; notably about calling conventions

在你的情况下,堆栈是安全的(因为调用 void foo(void) 比调用任何其他签名更安全),你可能会抛出一些异常。

详细信息是特定于编译器和处理器的。您的 hack 可能有效 - 但可能无效 - 但确实不可移植(因为从技术上讲是未定义的行为,IIUC)。

我不确定它是否有效。也许编译器会发出一个间接跳转,你会跳转到 nil 地址,那是一个 SIGSEGV

注意虚拟调用只是间接跳转;与

class Foo {
public:
  virtual void bar(void) =0;
  virtual ~Foo();
};

extern "C" void doit(Foo*f) {
   f->bar();
}

汇编代码(用g++-4.9 -Wall -O -fverbose-asm -S foo.cc生成)为:

        .type   doit, @function
doit:
.LFB0:
        .file 1 "foo.cc"
        .loc 1 7 0
        .cfi_startproc
.LVL0:
        subq    , %rsp        #,
        .cfi_def_cfa_offset 16
        .loc 1 8 0
        movq    (%rdi), %rax    # f_2(D)->_vptr.Foo, f_2(D)->_vptr.Foo
        call    *(%rax) # *_3
.LVL1:
        .loc 1 9 0
        addq    , %rsp        #,
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE0:
        .size   doit, .-doit

而且我没有看到任何针对上述未绑定虚拟方法的检查。

在基础 class 中定义虚方法以抛出异常会更好,也更便于移植。

您可以使用 MELT 自定义 GCC 编译器以满足您的奇异需求!