The shared thread-create helper hand-builds the new thread's
register state via thread_get_state/thread_set_state. Today the
struct it uses (i386_thread_state) and the flavor it asks for
(i386_REGS_SEGS_STATE) are x86-only.
Mirror the existing __i386__/__x86_64__ logic for aarch64:
* stack push: aarch64 passes the first arg in x0 (AAPCS) and the
return address via LR rather than the stack, so the helper only
leaves a zero word at the stack top.
* thread state: use `struct aarch64_thread_state` and
AARCH64_REGS_SEGS_STATE; set pc = routine, sp = stack top,
x[0] = arg, x[29] = 0 (frame ptr base), x[30] = 0 (LR — any
accidental ret out of routine will trap on null).
These names come from <mach/aarch64/thread_status.h>, already
upstreamed alongside the rest of the aarch64 stub headers.
---
tests/testlib_thread_start.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/testlib_thread_start.c b/tests/testlib_thread_start.c
index df4b19ab..ef33a272 100644
--- a/tests/testlib_thread_start.c
+++ b/tests/testlib_thread_start.c
@@ -50,6 +50,9 @@ thread_t test_thread_start(task_t task,
void(*routine)(void*), void* arg) {
*(top - 1) = 0; /* The return address */
#elif defined(__x86_64__)
*top = 0; /* The return address */
+#elif defined(__aarch64__)
+ *top = 0; /* Unused; aarch64 passes its first arg in x0 (AAPCS),
+ and routine returns via the saved LR we set below. */
#endif
ret = vm_write(task, stack + stack_size - vm_page_size, local_stack,
vm_page_size);
ASSERT_RET(ret, "can't initialize the stack for the new thread");
@@ -61,11 +64,18 @@ thread_t test_thread_start(task_t task,
void(*routine)(void*), void* arg) {
ret = thread_create(task, &thread);
ASSERT_RET(ret, "thread_create()");
+#ifdef __aarch64__
+ struct aarch64_thread_state state;
+ unsigned int count = AARCH64_THREAD_STATE_COUNT;
+ ret = thread_get_state(thread, AARCH64_REGS_SEGS_STATE,
+ (thread_state_t) &state, &count);
+#else
struct i386_thread_state state;
unsigned int count;
count = i386_THREAD_STATE_COUNT;
ret = thread_get_state(thread, i386_REGS_SEGS_STATE,
(thread_state_t) &state, &count);
+#endif
ASSERT_RET(ret, "thread_get_state()");
#ifdef __i386__
@@ -77,9 +87,20 @@ thread_t test_thread_start(task_t task,
void(*routine)(void*), void* arg) {
state.ursp = (long) (stack + stack_size - sizeof(long) * 1);
state.rbp = 0;
state.rdi = (long)arg;
+#elif defined(__aarch64__)
+ state.pc = (long) routine;
+ state.sp = (long) (stack + stack_size - sizeof(long) * 1);
+ state.x[0] = (long) arg; /* AAPCS: first arg in x0 */
+ state.x[29] = 0; /* frame pointer base */
+ state.x[30] = 0; /* LR = 0 so any ret out of routine traps */
#endif
+#ifdef __aarch64__
+ ret = thread_set_state(thread, AARCH64_REGS_SEGS_STATE,
+ (thread_state_t) &state, AARCH64_THREAD_STATE_COUNT);
+#else
ret = thread_set_state(thread, i386_REGS_SEGS_STATE,
(thread_state_t) &state, i386_THREAD_STATE_COUNT);
+#endif
ASSERT_RET(ret, "thread_set_state");
ret = thread_resume(thread);
--
2.54.0