From a6ef415fa95661b67017f1bdc32d8f98db7d9c44 Mon Sep 17 00:00:00 2001
From: Daniel Holth <dholth@anaconda.com>
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 6544ac0..3f936d3 100644
--- a/src/aarch64/ffi.c
+++ b/src/aarch64/ffi.c
@@ -715,12 +715,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;
@@ -867,7 +868,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
@@ -920,6 +925,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 9aafbec..af1c3b8 100644
--- a/src/closures.c
+++ b/src/closures.c
@@ -168,7 +168,13 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
#include <stdio.h>
#include <stdlib.h>
+#ifdef FFI_TRAMPOLINE_WHOLE_DYLIB
+#include <assert.h>
+#include <dispatch/dispatch.h>
+#include <dlfcn.h>
+#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;
@@ -196,6 +202,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;
@@ -211,35 +232,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)
{
- 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;
+
if (!(cur_prot & VM_PROT_EXECUTE))
{
/* If VM_PROT_EXECUTE isn't set on the remapped trampoline page, set it */
kt = vm_protect (mach_task_self (), trampoline_page, PAGE_MAX_SIZE,
FALSE, cur_prot | VM_PROT_EXECUTE);
if (kt != KERN_SUCCESS)
{
vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
return NULL;
}
}
/* 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 6a8e37f..a3d51bc 100644
--- a/src/x86/ffi64.c
+++ b/src/x86/ffi64.c
@@ -809,6 +809,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