编写自定义纯虚拟处理程序:调用时堆栈和寄存器的状态是什么
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 编译器以满足您的奇异需求!
因此可以使系统调用成为纯虚函数的自定义函数[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 编译器以满足您的奇异需求!