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



所以可以让系统调用纯虚函数的自定义函数[1]。这就提出了这样一个函数能做什么的问题。为GCC

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]在Linux中是否有_set_purecall_handler()的等号?

阅读x86-64 ABI补充以了解实际发生的情况;特别是关于调用约定。

在您的情况下,堆栈是安全的(因为调用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    $8, %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    $8, %rsp        #,
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE0:
        .size   doit, .-doit

和我没有看到任何针对上面未绑定的虚方法的检查

在基类中定义抛出异常的虚方法要好得多,也更可移植。

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

最新更新