Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 9 additions & 20 deletions zjit/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2594,21 +2594,13 @@ fn iseq_get_return_value(iseq: IseqPtr, captured_opnd: Option<InsnId>, ci_flags:
struct FfiTrampoline {
param_types: Vec<u8>,
ffi_return_type: u8,
native_name: String,
native_func: *const u8,
}

/// Check if a cfunc pointer points to a naked trampoline with embedded FFI metadata.
/// Returns `Some(FfiTrampoline)` if the magic bytes "FFI0" are found at offset 4.
#[cfg(target_arch = "aarch64")]
unsafe fn check_ffi_trampoline(cfunc_ptr: *const u8) -> Option<FfiTrampoline> {
unsafe extern "C" {
fn dlsym(handle: *mut std::ffi::c_void, symbol: *const std::ffi::c_char) -> *mut std::ffi::c_void;
}

// RTLD_DEFAULT on macOS
const RTLD_DEFAULT: *mut std::ffi::c_void = -2isize as *mut std::ffi::c_void;

// Check magic at offset 4
let magic_ptr = unsafe { cfunc_ptr.add(4) as *const u32 };
if unsafe { magic_ptr.read_unaligned() } != 0x46464930 {
Expand All @@ -2627,22 +2619,19 @@ unsafe fn check_ffi_trampoline(cfunc_ptr: *const u8) -> Option<FfiTrampoline> {
// Read return_type at offset 9+param_count
let ffi_return_type = unsafe { *cfunc_ptr.add(9 + param_count) };

// Read null-terminated function name at offset 10+param_count
let name_ptr = unsafe { cfunc_ptr.add(10 + param_count) as *const std::ffi::c_char };
let native_name = unsafe { std::ffi::CStr::from_ptr(name_ptr) }.to_string_lossy().into_owned();

// Resolve the native function via dlsym
let c_name = std::ffi::CString::new(native_name.as_str()).ok()?;
let func_ptr = unsafe { dlsym(RTLD_DEFAULT, c_name.as_ptr()) };
if func_ptr.is_null() {
return None;
}
// At offset 10+param_count the trampoline stores a 4-byte signed PC-relative
// offset (`.long _ptr_var - .`) to a static void* variable. Reconstruct the
// variable's address by adding the offset to the field's own address, then
// dereference to get the actual native function pointer.
let field_ptr = unsafe { cfunc_ptr.add(10 + param_count) };
let rel = unsafe { (field_ptr as *const i32).read_unaligned() } as isize;
let var_addr = unsafe { field_ptr.offset(rel) as *const *const u8 };
let native_func = unsafe { *var_addr };

Some(FfiTrampoline {
param_types,
ffi_return_type,
native_name,
native_func: func_ptr as *const u8,
native_func,
})
}

Expand Down