从硬件异常处理程序中抛出C异常.为什么-fnon-call-exceptions的
发布时间:2020-12-16 06:51:29 所属栏目:百科 来源:网络整理
导读:昨晚我有这个有趣的想法,以捕获硬件异常并抛出C异常.认为这可能对FPU异常有用,这些异常通常会崩溃,或者静默返回NaN然后导致意外行为.这里更加需要C异常. 所以我整个上午一直在黑客攻击,最后让它上班.好吧,差不多.编译器仍然没有意识到算术运算现在可以抛出C
昨晚我有这个有趣的想法,以捕获硬件异常并抛出C异常.认为这可能对FPU异常有用,这些异常通常会崩溃,或者静默返回NaN然后导致意外行为.这里更加需要C异常.
所以我整个上午一直在黑客攻击,最后让它上班.好吧,差不多.编译器仍然没有意识到算术运算现在可以抛出C异常,并且会静默地丢弃它周围的try / catch块.它在函数中发生异常时起作用. void throw_exception() { throw std::runtime_error("Division by zero!"); } __attribute__((noinline)) void try_div0() { cout << 1 / 0 << endl; } int main() { // this class traps a hardware exception (division by zero,in this case) and calls the supplied lambda function. // uh,no,you probably don't want to see the assembly code behind this... exception_wrapper div0_exc { 0,[] (exception_frame* frame,bool) { if (frame->address.segment != get_cs()) return false; // only handle exceptions that occured in our own code frame->stack.offset -= 4; // sub <fault esp>,4; auto* stack = reinterpret_cast<std::uintptr_t *>(frame->stack.offset); // get <fault esp> *stack = frame->address.offset; // mov [<fault esp>],<fault address>; frame->address.offset = reinterpret_cast<std::uintptr_t>(throw_exception); // set return address to throw_exception() return true; // exception handled! } }; try { // cout << 1 / 0 << endl; // this throws,as expected,but calls std::terminate(). try_div0(); // this exception is caught. } catch (std::exception& e) { cout << "oops: " << e.what() << endl; } } 我意识到这是一个不寻常的问题……但是我有什么方法可以让这项工作成功吗?告诉gcc可以在任何地方发生异常的方法吗? 我正在使用djgpp编译(我相信)它使用DWARF异常处理. 编辑:我刚刚找到了gcc标志-fnon-call-exceptions和-fasynchronous-unwind-tables,这似乎是我正在寻找的.但它仍然无效…… 编辑:现在使用前面提到的gcc标志,当两个函数调用之间发生异常时,它会捕获: inline void nop() { asm(""); } // or { cout << flush; } or something. empty function does not work. int main() { /* ... */ try { nop(); cout << 1 / 0 << endl; nop(); } /* ... */ } 编辑:嵌套的try / catch块具有相同的效果,除非捕获的指令前面有函数调用,否则不会捕获异常. inline void nop() { asm(""); } void try_div(int i) { try { // this works,catches exception in try_div(0). nop(); cout << 1 / i << endl; try_div(i - 1); // without the first nop(),calls std::terminate() //cout << 1 / i << endl; //try_div(i - 1); // reverse order,also terminates. //if (i != 0) try_div(i - 1); //cout << 1 / i << endl; //nop(); } catch (std::exception& e) { cout << "caught in try_div(" << i << "): " << e.what() << endl; } } int main() { /* ... */ try { try_div(4); } catch (std::exception& e) { cout << "caught in main(): " << e.what() << endl; } } 编辑:我已将此作为可能的bug in gcc提交,并将我的代码缩减为简单的test case. 解决方法
已经有一段时间了,但我终于明白了……投掷功能需要标记为有信号帧.
[[gnu::no_caller_saved_registers]] void throw_exception() { asm(".cfi_signal_frame"); throw std::runtime_error("Division by zero!"); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |