Soa*_*Box 5 c++ assembly exception
我有一些奇怪的自修改代码,但它的根本是一个非常简单的问题:我希望能够执行一个jmp(或一个call),然后从该任意点抛出异常并让它被try/catch捕获包含jmp/的块call.
但是当我这样做时(在gcc 4.4.1 x86_64中),terminate()如果从try/catch外部抛出异常,异常会导致异常.我真的没有看到这与从一些偏远的库中抛出异常有什么不同,但显然是因为它不起作用.
如何执行jmp或call仍然将异常抛回原始的try/catch?为什么这个try/catch不会继续处理这些异常,就像正常调用函数一样?
代码:
#include <iostream>
#include <stdexcept>
using namespace std;
void thrower()
{
cout << "Inside thrower" << endl;
throw runtime_error("some exception");
}
int main()
{
cout << "Top of main" << endl;
try {
asm volatile (
"jmp *%0" // same thing happens with a call instead of a jmp
:
: "r"((long)thrower)
:
);
} catch (exception &e) {
cout << "Caught : " << e.what() << endl;
}
cout << "Bottom of main" << endl << endl;
}
Run Code Online (Sandbox Code Playgroud)
预期产量:
Top of main
Inside thrower
Caught : some exception
Bottom of main
Run Code Online (Sandbox Code Playgroud)
实际输出:
Top of main
Inside thrower
terminate called after throwing an instance of 'std::runtime_error'
what(): some exception
Aborted
Run Code Online (Sandbox Code Playgroud)
小智 1
如果您在x86-64 linux上使用gcc 4.4.7(及更高版本),并且具有矮异常处理机制(可能是默认的),我有一种方法可以解决这个问题。
假设您的内联汇编代码是一个函数inline_add。它将调用另一个函数add,这可能会引发异常。这是代码:
extern "C" int add(int a, int b) {
throw "in add";
}
int inline_add(int a, int b) {
int r = 0;
__asm__ __volatile__ (
"movl %1, %%edi\n\t"
"movl %2, %%esi\n\t"
"call add\n\t"
"movl %%eax, %0\n\t"
:"=r"(r)
:"r"(a), "r"(b)
:"%eax"
);
return r;
}
Run Code Online (Sandbox Code Playgroud)
如果你inline_add这样调用:
try {
inline_add(1, 1);
} catch (...) {
std::cout << "in catch" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它会崩溃,因为 gcc 不提供inline_add. 当遇到异常时,就必须抓紧。(请参阅此处的“与 C 的兼容性”)
所以我们需要为它伪造一个异常框架,但是用 gcc 程序集很难破解,我们只需使用具有适当异常框架的函数来包围它
我们定义一个这样的函数:
void build_exception_frame(bool b) {
if (b) {
throw 0;
}
}
Run Code Online (Sandbox Code Playgroud)
inline_add并像这样调用:
try {
inline_add(1, 1);
build_exception_frame(false);
} catch (...) {
std::cout << "in catch" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它确实有效。
build_exception_frame应该在通话后出现,否则不起作用
此外,为了防止 gcc 可能进行优化build_exception_frame,我们需要添加以下内容:
void build_exception_frame(bool b) __attribute__((optimize("O0")));
Run Code Online (Sandbox Code Playgroud)
您可以检查 gcc 生成的汇编代码来验证代码。
看来 gcc 为整个try/提供了异常框架catch,只要有一个函数可能会抛出,并且位置很重要。
稍后需要看看 gcc 是如何工作的。
如果有人知道这一点,请好心告诉我。谢谢。