diff --git a/ld_so/ld_script/aarch64-unknown-redox.ld b/ld_so/ld_script/aarch64-unknown-redox.ld index b6c6efc3b3..64ead42b5e 100644 --- a/ld_so/ld_script/aarch64-unknown-redox.ld +++ b/ld_so/ld_script/aarch64-unknown-redox.ld @@ -110,13 +110,13 @@ SECTIONS KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } - /* .init_array : + .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); - } */ + } .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); @@ -248,9 +248,8 @@ SECTIONS * ld.so will be moved out of relibc. So, till that time, we have to discard any sections * that may reference use thread local storage. * - * .init_array also depends on TLS and is discarded as we don't need it. + * .init_array need to be not discarded unlike x86_64 linker variant */ *(.gnu.linkonce.tb.*) *(.tcommon) - *(.init_array) } } diff --git a/src/cxa.rs b/src/cxa.rs index e2179e4c8d..417a05faa3 100644 --- a/src/cxa.rs +++ b/src/cxa.rs @@ -1,29 +1,104 @@ -use crate::{platform::types::*, raw_cell::RawCell}; - -// TODO: Implement cxa_finalize and uncomment this +use crate::platform::types::*; +use alloc::vec::Vec; +use core::{cell::RefCell, ptr}; +use spin::Mutex; #[derive(Clone, Copy)] struct CxaAtExitFunc { - //func: extern "C" fn(*mut c_void), - //arg: *mut c_void, - //dso: *mut c_void, + func: extern "C" fn(*mut c_void), + arg: usize, + dso: usize, } -static CXA_ATEXIT_FUNCS: RawCell<[Option; 32]> = RawCell::new([None; 32]); +#[derive(Clone, Copy)] +struct CxaThreadAtExitFunc { + func: extern "C" fn(*mut c_void), + obj: *mut c_void, + dso: *mut c_void, +} + +static CXA_ATEXIT_FUNCS: Mutex>> = Mutex::new(Vec::new()); +#[thread_local] +static DTORS: RefCell> = RefCell::new(Vec::new()); #[unsafe(no_mangle)] pub unsafe extern "C" fn __cxa_atexit( - func_opt: Option, + func: Option, arg: *mut c_void, dso: *mut c_void, ) -> c_int { - for i in 0..CXA_ATEXIT_FUNCS.unsafe_ref().len() { - if CXA_ATEXIT_FUNCS.unsafe_ref()[i].is_none() { - CXA_ATEXIT_FUNCS.unsafe_mut()[i] = - func_opt.map(|func| CxaAtExitFunc {} /*{ func, arg, dso }*/); + let Some(func) = func else { + return 0; + }; + + let entry = CxaAtExitFunc { + func, + arg: arg as usize, + dso: dso as usize, + }; + + let mut funcs = CXA_ATEXIT_FUNCS.lock(); + + for slot in funcs.iter_mut() { + if slot.is_none() { + *slot = Some(entry); return 0; } } - -1 + // No empty slots + funcs.push(Some(entry)); + 0 +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __cxa_finalize(dso: *mut c_void) { + let mut funcs = CXA_ATEXIT_FUNCS.lock(); + + let dso_usize = dso as usize; + + for slot in funcs.iter_mut().rev() { + if let Some(entry) = slot.as_ref() { + if dso.is_null() || entry.dso == dso_usize { + if let Some(entry_to_run) = slot.take() { + (entry_to_run.func)(entry_to_run.arg as *mut c_void); + } + } + } + } + + // clean up remaining list + if dso.is_null() { + funcs.clear(); + } else { + funcs.retain(|opt| opt.is_some()); + } +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __cxa_thread_atexit_impl( + func: extern "C" fn(*mut c_void), + obj: *mut c_void, + dso: *mut c_void, +) { + let entry = CxaThreadAtExitFunc { func, obj, dso }; + DTORS.borrow_mut().push(entry); +} + +// called internally +pub unsafe fn __cxa_thread_finalize() { + let mut dtors = DTORS.borrow_mut(); + while let Some(entry) = dtors.pop() { + (entry.func)(entry.obj); + } +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn _ITM_deregisterTMCloneTable(_ptr: *mut c_void) { + // No-op +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn _ITM_registerTMCloneTable(_ptr: *mut c_void, _len: usize) { + // No-op } diff --git a/src/header/pthread/mod.rs b/src/header/pthread/mod.rs index 8457e6a8d0..25252f307a 100644 --- a/src/header/pthread/mod.rs +++ b/src/header/pthread/mod.rs @@ -302,6 +302,8 @@ pub unsafe extern "C" fn __relibc_internal_pthread_cleanup_pop(execute: c_int) { } pub(crate) unsafe fn run_destructor_stack() { + unsafe { crate::cxa::__cxa_thread_finalize() }; + let mut ptr = CLEANUP_LL_HEAD.get(); while !ptr.is_null() {