Custom setjmp/longjmp to avoid SEH. (will it work?)

This commit is contained in:
losfair 2019-08-07 00:38:42 +08:00
parent b50fd31adb
commit 4b1d337ebe
3 changed files with 43 additions and 11 deletions

View File

@ -209,12 +209,14 @@ fn main() {
cc::Build::new()
.cpp(true)
.file("cpp/object_loader.cpp")
.file("cpp/unwinding.s")
.compile("llvm-backend");
println!("cargo:rustc-link-lib=static=llvm-backend");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=cpp/object_loader.cpp");
println!("cargo:rerun-if-changed=cpp/object_loader.hh");
println!("cargo:rerun-if-changed=cpp/unwinding.s");
// Enable "nightly" cfg if the current compiler is nightly.
if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly {

View File

@ -4,37 +4,40 @@
extern "C" void __register_frame(uint8_t *);
extern "C" void __deregister_frame(uint8_t *);
extern "C" void unwinding_setjmp(uint8_t **stack_out, void (*func)(void *), void *userdata);
[[noreturn]] extern "C" void unwinding_longjmp(uint8_t *stack_in);
struct UnwindPoint {
UnwindPoint *prev;
jmp_buf unwind_info;
uint8_t *stack;
std::function<void()> *f;
std::unique_ptr<std::exception> exception;
};
static thread_local UnwindPoint *unwind_state = nullptr;
static void unwind_payload(void *_point) {
UnwindPoint *point = (UnwindPoint *) _point;
(*point->f)();
}
void catch_unwind(std::function<void()>&& f) {
UnwindPoint current;
current.prev = unwind_state;
current.f = &f;
unwind_state = &current;
bool rethrow = false;
if(setjmp(current.unwind_info)) {
rethrow = true;
} else {
f();
unwinding_setjmp(&current.stack, unwind_payload, (void *) &current);
if(current.exception) {
throw *current.exception;
}
unwind_state = current.prev;
if(rethrow) throw *current.exception;
}
void unsafe_unwind(std::exception *exception) {
UnwindPoint *state = unwind_state;
if(state) {
state->exception.reset(exception);
longjmp(state->unwind_info, 42);
unwinding_longjmp(state->stack);
} else {
abort();
}

View File

@ -0,0 +1,27 @@
# (save_place, func(userdata), userdata)
.globl _unwinding_setjmp
_unwinding_setjmp:
push %r15
push %r14
push %r13
push %r12
push %rbx
push %rbp
sub $8, %rsp # 16-byte alignment
mov %rsp, (%rdi)
mov %rdx, %rdi
callq *%rsi
setjmp_ret:
add $8, %rsp
pop %rbp
pop %rbx
pop %r12
pop %r13
pop %r14
pop %r15
ret
.globl _unwinding_longjmp
_unwinding_longjmp:
mov %rdi, %rsp
jmp setjmp_ret