From a6ef415fa95661b67017f1bdc32d8f98db7d9c44 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Fri, 27 Aug 2021 15:55:36 -0400 Subject: [PATCH] arm64 changes merged from v3.3 arm64-changes patch --- src/aarch64/ffi.c | 29 +++++++++++++++++--- src/closures.c | 67 ++++++++++++++++++++++++++++++++++++++++------- src/x86/ffi64.c | 6 +++++ 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c index 5c85fcd..3ae983b 100644 --- a/src/aarch64/ffi.c +++ b/src/aarch64/ffi.c @@ -662,12 +662,13 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, state.ngrn = N_X_ARG_REG; /* Note that the default abi extends each argument to a full 64-bit slot, while the iOS abi allocates - only enough space. */ + only enough space, except for variadic arguments. */ #ifdef __APPLE__ - memcpy(d, a, s); -#else - *(ffi_arg *)d = ext; + if (!state.allocating_variadic) + memcpy(d, a, s); + else #endif + *(ffi_arg *)d = ext; } } break; @@ -813,7 +814,11 @@ ffi_prep_closure_loc (ffi_closure *closure, #ifdef HAVE_PTRAUTH codeloc = ptrauth_auth_data(codeloc, ptrauth_key_function_pointer, 0); #endif +#ifdef FFI_TRAMPOLINE_WHOLE_DYLIB + void **config = (void **)((uint8_t *)codeloc - 2*PAGE_MAX_SIZE); +#else void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE); +#endif config[0] = closure; config[1] = start; #endif @@ -864,6 +869,22 @@ out: return FFI_OK; } +ffi_closure * +ffi_find_closure_for_code(void *codeloc) +{ +#if FFI_EXEC_TRAMPOLINE_TABLE +# ifdef FFI_TRAMPOLINE_WHOLE_DYLIB + void **config = (void **)((uint8_t *)codeloc - 2*PAGE_MAX_SIZE); +# else + void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE); +# endif + return config[0]; +#else + return (ffi_closure*)codeloc; +#endif +} +ffi_closure *ffi_find_closure_for_code_np(void *codeloc) { return ffi_find_closure_for_code(codeloc); } /* Apple renamed this entry ... */ + #ifdef FFI_GO_CLOSURES extern void ffi_go_closure_SYSV (void) FFI_HIDDEN; extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN; diff --git a/src/closures.c b/src/closures.c index f7bead6..460606f 100644 --- a/src/closures.c +++ b/src/closures.c @@ -164,7 +164,13 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr) #include #include +#ifdef FFI_TRAMPOLINE_WHOLE_DYLIB +#include +#include +#include +#else extern void *ffi_closure_trampoline_table_page; +#endif typedef struct ffi_trampoline_table ffi_trampoline_table; typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry; @@ -192,6 +198,21 @@ struct ffi_trampoline_table_entry /* Total number of trampolines that fit in one trampoline table */ #define FFI_TRAMPOLINE_COUNT (PAGE_MAX_SIZE / FFI_TRAMPOLINE_SIZE) +/* The trampoline dylib has one page for the MACHO_HEADER and one page for the + * trampolines. iOS 12.0 and later, and macOS on Apple Silicon require that + * the entire dylib needs to be remapped as a unit. + * + * arm (legacy): Allocate two pages -- a config page and a placeholder for the trampolines + * arm64 (modern): Allocate three pages -- a config page and two placeholders for the trampoline dylib + */ +#ifdef FFI_TRAMPOLINE_WHOLE_DYLIB +#define FFI_TRAMPOLINE_ALLOCATION_PAGE_COUNT 3 +#define FFI_TRAMPOLINE_PAGE_SEGMENT_OFFSET PAGE_MAX_SIZE +#else +#define FFI_TRAMPOLINE_ALLOCATION_PAGE_COUNT 2 +#define FFI_TRAMPOLINE_PAGE_SEGMENT_OFFSET 0 +#endif + static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER; static ffi_trampoline_table *ffi_trampoline_tables = NULL; @@ -207,35 +228,63 @@ ffi_trampoline_table_alloc (void) kern_return_t kt; uint16_t i; - /* Allocate two pages -- a config page and a placeholder page */ config_page = 0x0; - kt = vm_allocate (mach_task_self (), &config_page, PAGE_MAX_SIZE * 2, + /* The entire allocation is: + * config_page + * trampoline_segment + * + * trampoline_segment is: + * trampoline dylib mach-o header (if FFI_TRAMPOLINE_WHOLE_DYLIB) + * trampoline page + */ + kt = vm_allocate (mach_task_self (), &config_page, FFI_TRAMPOLINE_ALLOCATION_PAGE_COUNT * PAGE_MAX_SIZE, VM_FLAGS_ANYWHERE); if (kt != KERN_SUCCESS) return NULL; - /* Remap the trampoline table on top of the placeholder page */ - trampoline_page = config_page + PAGE_MAX_SIZE; + static void *trampoline_table_page; + +#ifdef FFI_TRAMPOLINE_WHOLE_DYLIB + static dispatch_once_t trampoline_template_init_once; + + dispatch_once(&trampoline_template_init_once, ^{ + void * const trampoline_handle = dlopen("/usr/lib/libffi-trampolines.dylib", RTLD_NOW | RTLD_LOCAL | RTLD_FIRST); + assert(trampoline_handle); + + trampoline_table_page = dlsym(trampoline_handle, "ffi_closure_trampoline_table_page"); + assert(trampoline_table_page); + }); +#else + trampoline_table_page = &ffi_closure_trampoline_table_page; +#endif #ifdef HAVE_PTRAUTH - trampoline_page_template = (vm_address_t)(uintptr_t)ptrauth_auth_data((void *)&ffi_closure_trampoline_table_page, ptrauth_key_function_pointer, 0); + trampoline_page_template = (uintptr_t)ptrauth_auth_data(trampoline_table_page, ptrauth_key_function_pointer, 0); #else - trampoline_page_template = (vm_address_t)&ffi_closure_trampoline_table_page; + trampoline_page_template = (uintptr_t)trampoline_table_page; #endif #ifdef __arm__ /* ffi_closure_trampoline_table_page can be thumb-biased on some ARM archs */ trampoline_page_template &= ~1UL; #endif - kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_MAX_SIZE, 0x0, - VM_FLAGS_OVERWRITE, mach_task_self (), trampoline_page_template, + + vm_address_t trampoline_segment_template = trampoline_page_template - FFI_TRAMPOLINE_PAGE_SEGMENT_OFFSET; + vm_size_t trampoline_segment_size = (FFI_TRAMPOLINE_ALLOCATION_PAGE_COUNT - 1) * PAGE_MAX_SIZE; + + /* Remap the trampoline table on top of the placeholder page */ + vm_address_t trampoline_segment = config_page + PAGE_MAX_SIZE; + kt = vm_remap (mach_task_self(), &trampoline_segment, trampoline_segment_size, 0x0, + VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, mach_task_self(), trampoline_segment_template, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE); if (kt != KERN_SUCCESS || !(cur_prot & VM_PROT_EXECUTE)) { - vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2); + vm_deallocate (mach_task_self (), config_page, FFI_TRAMPOLINE_ALLOCATION_PAGE_COUNT * PAGE_MAX_SIZE); return NULL; } + trampoline_page = trampoline_segment + FFI_TRAMPOLINE_PAGE_SEGMENT_OFFSET; + /* We have valid trampoline and config pages */ table = calloc (1, sizeof (ffi_trampoline_table)); table->free_count = FFI_TRAMPOLINE_COUNT; diff --git a/src/x86/ffi64.c b/src/x86/ffi64.c index 438b374..8e47843 100644 --- a/src/x86/ffi64.c +++ b/src/x86/ffi64.c @@ -788,6 +788,12 @@ out: return FFI_OK; } +ffi_closure * +ffi_find_closure_for_code(void *code) +{ + return (ffi_closure *) code; +} + ffi_closure *ffi_find_closure_for_code_np(void *code) { return ffi_find_closure_for_code(code); } /* Apple renamed ... */ int FFI_HIDDEN ffi_closure_unix64_inner(ffi_cif *cif, void (*fun)(ffi_cif*, void*, void**, void*), -- 2.32.0