diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 3c36707c5..ff6dbe2d1 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -2,11 +2,15 @@ #include #include +extern "C" void __register_frame(uint8_t *); +extern "C" void __deregister_frame(uint8_t *); + struct MemoryManager : llvm::RuntimeDyld::MemoryManager { public: MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} virtual ~MemoryManager() override { + deregisterEHFrames(); // Deallocate all of the allocated memory. callbacks.dealloc_memory(code_section.base, code_section.size); callbacks.dealloc_memory(read_section.base, read_section.size); @@ -62,12 +66,17 @@ public: return true; } - virtual void registerEHFrames(uint8_t* Addr, uint64_t LoadAddr, size_t Size) override { - std::cout << "should register eh frames" << std::endl; + virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override { + eh_frame_ptr = addr; + eh_frame_size = size; + eh_frames_registered = true; + callbacks.visit_fde(addr, size, __register_frame); } virtual void deregisterEHFrames() override { - std::cout << "should deregister eh frames" << std::endl; + if (eh_frames_registered) { + callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame); + } } virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override { @@ -111,6 +120,9 @@ private: Section code_section, read_section, readwrite_section; uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr; + uint8_t* eh_frame_ptr; + size_t eh_frame_size; + bool eh_frames_registered = false; callbacks_t callbacks; }; @@ -154,7 +166,7 @@ WasmModule::WasmModule( const uint8_t *object_start, size_t object_size, callbacks_t callbacks -) : memory_manager(new MemoryManager(callbacks)) +) : memory_manager(std::unique_ptr(new MemoryManager(callbacks))) { object_file = llvm::cantFail(llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef( llvm::StringRef((const char *)object_start, object_size), "object" diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index 8134385fd..d31d33266 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -21,6 +21,8 @@ typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect, uint8_t** typedef result_t (*protect_memory_t)(uint8_t* ptr, size_t size, mem_protect_t protect); typedef result_t (*dealloc_memory_t)(uint8_t* ptr, size_t size); typedef uintptr_t (*lookup_vm_symbol_t)(const char* name_ptr, size_t length); +typedef void (*fde_visitor_t)(uint8_t *fde); +typedef result_t (*visit_fde_t)(uint8_t *fde, size_t size, fde_visitor_t visitor); typedef struct { /* Memory management. */ @@ -29,6 +31,8 @@ typedef struct { dealloc_memory_t dealloc_memory; lookup_vm_symbol_t lookup_vm_symbol; + + visit_fde_t visit_fde; } callbacks_t; class WasmModule { @@ -41,7 +45,7 @@ public: void *get_func(llvm::StringRef name) const; private: - llvm::RuntimeDyld::MemoryManager* memory_manager; + std::unique_ptr memory_manager; std::unique_ptr object_file; std::unique_ptr runtime_dyld; }; diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index a7d700e90..66f29cbbb 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -59,6 +59,7 @@ struct Callbacks { dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult, lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func, + visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)), } extern "C" { @@ -165,11 +166,18 @@ fn get_callbacks() -> Callbacks { } } + extern "C" fn visit_fde(fde: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) { + unsafe { + crate::platform::visit_fde(fde, size, visitor); + } + } + Callbacks { alloc_memory, protect_memory, dealloc_memory, lookup_vm_symbol, + visit_fde, } } diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index f46520383..3a18d7d48 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -14,6 +14,7 @@ use wasmparser::{self, WasmDecoder}; mod backend; mod code; mod intrinsics; +mod platform; mod read_info; mod state; mod trampolines; diff --git a/lib/llvm-backend/src/platform/mod.rs b/lib/llvm-backend/src/platform/mod.rs index bcc0378c2..01b81b022 100644 --- a/lib/llvm-backend/src/platform/mod.rs +++ b/lib/llvm-backend/src/platform/mod.rs @@ -1,8 +1,7 @@ - -#[cfg(target_family = "unix")] +#[cfg(unix)] mod unix; -#[cfg(target_family = "unix")] +#[cfg(unix)] pub use self::unix::*; #[cfg(target_family = "windows")] -compile_error!("windows not yet supported for the llvm-based compiler backend"); \ No newline at end of file +compile_error!("windows not yet supported for the llvm-based compiler backend"); diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs new file mode 100644 index 000000000..ee03ea08f --- /dev/null +++ b/lib/llvm-backend/src/platform/unix.rs @@ -0,0 +1,35 @@ +/// `__register_frame` and `__deregister_frame` on macos take a single fde as an +/// argument, so we need to parse the fde table here. +/// +/// This is a pretty direct port of llvm's fde handling code: +/// https://llvm.org/doxygen/RTDyldMemoryManager_8cpp_source.html. +#[cfg(target_os = "macos")] +pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) { + unsafe fn process_fde(entry: *mut u8, visitor: extern "C" fn(*mut u8)) -> *mut u8 { + let mut p = entry; + let length = (p as *const u32).read_unaligned(); + p = p.add(4); + let offset = (p as *const u32).read_unaligned(); + + if offset != 0 { + visitor(entry); + } + p.add(length as usize) + } + + let mut p = addr; + let end = p.add(size); + + loop { + if p >= end { + break; + } + + p = process_fde(p, visitor); + } +} + +#[cfg(not(target_os = "macos"))] +pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) { + visitor(addr); +} diff --git a/lib/llvm-backend/src/platform/unix/mod.rs b/lib/llvm-backend/src/platform/unix/mod.rs deleted file mode 100644 index c0e86f7ef..000000000 --- a/lib/llvm-backend/src/platform/unix/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ - -extern "C" { - fn __register_frame(frame: *const u8); - fn __deregister_frame(frame: *const u8); -} - -pub unsafe fn register_eh_frames(eh_frames: *const u8, num_bytes: usize) { - visit_frame_desc_entries(eh_frames, num_bytes, |frame| __register_frame(frame)); -} - -unsafe fn visit_frame_desc_entries(eh_frames: *const u8, num_bytes: usize, visitor: F) -where - F: Fn(*const u8), -{ - let mut next = eh_frames; - let mut end = eh_frames.add(num_bytes); - - loop { - if next >= end { - break; - } - - let cfi = next; - let mut cfi_num_bytes = (next as *const u32).read_unaligned() as u64; - assert!(cfi_num_bytes != 0); - - next = next.add(4); - if num_bytes == 0xffffffff { - let cfi_num_bytes64 = (next as *const u64).read_unaligned(); - cfi_num_bytes = cfi_num_bytes64; - next = next.add(8); - } - - let cie_offset = (next as *const u32).read_unaligned(); - if cie_offset != 0 { - visitor(cfi); - } - next = next.add(cfi_num_bytes as usize); - } -}