From 0fee9dc19fd6b714f7580a58158c04a2de85e7f6 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Mon, 27 Jul 2026 09:16:17 +0900 Subject: [PATCH] relibc: fix round-8 deferred stubs in linux platform signal.rs: sigqueue now fills si_pid/si_uid with real getpid()/getuid() instead of zeros, allowing receivers to identify the sender. mod.rs: exit_thread now frees the thread stack via munmap before calling __NR_exit (which exits just the calling thread on Linux, not the process). Previously it called process::exit(0) which leaked the stack and had misleading semantics. mod.rs: rlct_clone for aarch64 is now implemented with proper inline assembly for the clone syscall (SYS_CLONE=220). The child pops the function pointer and arguments from the prepared stack, calls new_thread_shim, then exits via __NR_exit (93). Previously this was todo!() which panicked on thread creation. --- src/platform/linux/mod.rs | 87 +++++++++++++++++++++++++++++++++--- src/platform/linux/signal.rs | 6 +-- 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 22e626db64..fc4abe9be6 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -1,4 +1,4 @@ -#[cfg(target_arch = "x86_64")] +#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] use core::arch::asm; use super::{Pal, types::*}; @@ -165,9 +165,15 @@ impl Pal for Sys { } unreachable!(); } - unsafe fn exit_thread(_stack_base: *mut (), _stack_size: usize) -> ! { - // TODO - Self::exit(0) + unsafe fn exit_thread(stack_base: *mut (), stack_size: usize) -> ! { + // Free the thread's stack before exiting. On Linux, __NR_exit only + // terminates the calling thread (not the process); __NR_exit_group + // terminates all threads. We want thread-only exit here. + if !stack_base.is_null() && stack_size > 0 { + let _ = e_raw(syscall!(MUNMAP, stack_base, stack_size)); + } + unsafe { syscall!(EXIT, 0); } + unreachable!(); } fn fchdir(fildes: c_int) -> Result<()> { @@ -627,7 +633,78 @@ impl Pal for Sys { stack: *mut usize, _os_specific: &mut OsSpecific, ) -> Result { - todo!("rlct_clone not implemented for aarch64 yet") + const SYS_CLONE_AARCH64: usize = 220; + const SYS_EXIT_AARCH64: usize = 93; + + let flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD; + let pid; + unsafe { + asm!( + "svc #0", + + // If x0 != 0 we are the parent; jump to return. + "cbnz x0, 2f", + + // Child: pop function pointer and args from the stack + // that the pthread code prepared. + "ldr x9, [sp], #8", // x9 = new_thread_shim + "ldr x0, [sp], #8", // x0 = start_routine + "ldr x1, [sp], #8", // x1 = arg + "ldr x2, [sp], #8", // x2 = tcb + "ldr x3, [sp], #8", // x3 = sync_mutex + "ldr x4, [sp], #8", // skip unused + "ldr x5, [sp], #8", // skip unused + "ldr x6, [sp], #8", // skip aarch64 alignment pad + + "blr x9", // call new_thread_shim(...) + + // new_thread_shim returns !, but guard just in case. + "mov x8, {exit_nr}", + "mov x0, xzr", + "svc #0", + "udf #0", + + "2:", + + exit_nr = const SYS_EXIT_AARCH64, + + inout("x0") flags => pid, + inout("x1") stack => _, + in("x2") 0usize, + in("x3") 0usize, + in("x4") 0usize, + in("x8") SYS_CLONE_AARCH64, + + out("x5") _, + out("x6") _, + out("x7") _, + out("x9") _, + out("x10") _, + out("x11") _, + out("x12") _, + out("x13") _, + out("x14") _, + out("x15") _, + out("x16") _, + out("x17") _, + out("x18") _, + out("x19") _, + out("x20") _, + out("x21") _, + out("x22") _, + out("x23") _, + out("x24") _, + out("x25") _, + out("x26") _, + out("x27") _, + out("x28") _, + + options(nostack), + ); + } + let tid = e_raw(pid)?; + + Ok(crate::pthread::OsTid { thread_id: tid }) } unsafe fn rlct_kill(os_tid: crate::pthread::OsTid, signal: usize) -> Result<()> { diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index 584c4bff59..acf04c89b4 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -5,7 +5,7 @@ use core::{ use super::{ super::{ - PalSignal, + Pal, PalSignal, types::{c_int, pid_t}, }, Sys, e_raw, @@ -39,10 +39,10 @@ impl PalSignal for Sys { si_addr: core::ptr::null_mut(), si_code: SI_QUEUE, si_errno: 0, - si_pid: 0, // TODO: GETPID? + si_pid: Self::getpid(), si_signo: sig, si_status: 0, - si_uid: 0, // TODO: GETUID? + si_uid: Self::getuid(), si_value: val, }; e_raw(unsafe { syscall!(RT_SIGQUEUEINFO, pid, sig, addr_of!(info)) }).map(|_| ())