内联汇编跳转后引发C ++异常 [英] Throwing a C++ exception after an inline-asm jump

查看:183
本文介绍了内联汇编跳转后引发C ++异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些奇怪的自我修改代码,但从根本上讲是一个非常简单的问题:我希望能够执行 jmp (或 call ),然后从该任意点抛出异常,并使其被包含 jmp /的try / catch块捕获通话

I have some odd self modifying code, but at the root of it is a pretty simple problem: I want to be able to execute a jmp (or a call) and then from that arbitrary point throw an exception and have it caught by the try/catch block that contained the jmp/call.

但是当我这样做(在gcc 4.4.1 x86_64中)时,异常导致 terminate()如果异常是从try / catch之外抛出的话。我真的看不出它与从某个遥远的库中引发异常有什么不同,但这显然是因为它根本不起作用。

But when I do this (in gcc 4.4.1 x86_64) the exception results in a terminate() as it would if the exception was thrown from outside of a try/catch. I don't really see how this is different than throwing an exception from inside of some far-flung library, yet it obviously is because it just doesn't work.

如何执行 jmp 调用,但仍将异常返回到原始try / catch?为什么try / catch不能像正常调用该函数那样继续处理这些异常?

How can I execute a jmp or call but still throw an exception back to the original try/catch? Why doesn't this try/catch continue to handle these exceptions as it would if the function was called normally?

代码:

#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;
}

预期输出:

Top of main 
Inside thrower 
Caught : some exception
Bottom of main

实际输出:

Top of main
Inside thrower
terminate called after throwing an instance of 'std::runtime_error'
  what():  some exception
Aborted


推荐答案

如果在 x86-64 linux上使用 gcc 4.4.7 (及更高版本) ,使用 dwarf 异常处理机制(可能是默认的机制),我有办法解决这个问题。

If you are using gcc 4.4.7(and above) on x86-64 linux, with dwarf exception handle mechanism (which might be the default one), I have a way to work this out.

假设您的内联汇编代码是函数 inline_add 。它将调用另一个函数 add ,该函数可能会引发异常。代码如下:

Suppose your inline assembly code is a function inline_add. It'll call another function add, which might throw a exception. Here's code:

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;
}

如果您致电 inline_add 像这样:

try {
    inline_add(1, 1);
} catch (...) {
    std::cout << "in catch" << std::endl;
}

它会崩溃,因为gcc不会为 inline_add 。当涉及到例外时,它必须努力。 (有关与C的兼容性,请参见此处

it'll crash, because gcc doesn't provide the exception frame for inline_add. When it comes to a exception, it has to crach. (see here for the 'Compatibility with C')

所以我们需要为其伪造一个异常框架,但是用gcc汇编很难破解,我们只使用带有适当异常框架的函数来包围它

So we need to fake a exception frame for it, but it would be hard to hack with gcc assembly, we just use functions with proper exception frame to surround it

我们定义如下函数:

void build_exception_frame(bool b) {
    if (b) {
        throw 0;
    }
}

并致电 inline_add 像这样:

try {
    inline_add(1, 1);
    build_exception_frame(false);
} catch (...) {
    std::cout << "in catch" << std::endl;
}

即可。

build_exception_frame 应该在调用之后出现,否则将不起作用

build_exception_frame should come after the call, or it won't work

更多,以防止optimiziong gcc可能采用 build_exception_frame ,我们需要添加以下内容:

Further more, to prevent optimiziong gcc might take on build_exception_frame, we need to add this:

void build_exception_frame(bool b) __attribute__((optimize("O0")));

您可以检查gcc生成的汇编代码以验证代码。

You can check the assembly code that gcc generates to verify the code.

似乎gcc为整个 try / catch 提供了例外框架

It seems that gcc provide exception frame for the whole try/catch, as long as there's one function might throw, and position matters.

需要稍后查看gcc的工作原理。

Need to see how gcc works on that later.

如果对此有所了解,请足够好让我知道。谢谢。

If any knows about that, please be kind enough to let me know. Thanks.

这篇关于内联汇编跳转后引发C ++异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆