Skip to main content

relibc/
cxa.rs

1use crate::platform::types::{c_int, c_void};
2use alloc::vec::Vec;
3use core::cell::RefCell;
4use spin::Mutex;
5
6#[derive(Clone, Copy)]
7struct CxaAtExitFunc {
8    func: extern "C" fn(*mut c_void),
9    arg: usize,
10    dso: usize,
11}
12
13#[derive(Clone, Copy)]
14struct CxaThreadAtExitFunc {
15    func: extern "C" fn(*mut c_void),
16    obj: *mut c_void,
17    dso: *mut c_void,
18}
19
20static CXA_ATEXIT_FUNCS: Mutex<Vec<Option<CxaAtExitFunc>>> = Mutex::new(Vec::new());
21#[thread_local]
22static DTORS: RefCell<Vec<CxaThreadAtExitFunc>> = RefCell::new(Vec::new());
23
24#[unsafe(no_mangle)]
25pub unsafe extern "C" fn __cxa_atexit(
26    func: Option<extern "C" fn(*mut c_void)>,
27    arg: *mut c_void,
28    dso: *mut c_void,
29) -> c_int {
30    let Some(func) = func else {
31        return 0;
32    };
33
34    let entry = CxaAtExitFunc {
35        func,
36        arg: arg as usize,
37        dso: dso as usize,
38    };
39
40    let mut funcs = CXA_ATEXIT_FUNCS.lock();
41
42    for slot in funcs.iter_mut() {
43        if slot.is_none() {
44            *slot = Some(entry);
45            return 0;
46        }
47    }
48
49    // No empty slots
50    funcs.push(Some(entry));
51    0
52}
53
54#[unsafe(no_mangle)]
55pub unsafe extern "C" fn __cxa_finalize(dso: *mut c_void) {
56    let mut funcs = CXA_ATEXIT_FUNCS.lock();
57
58    let dso_usize = dso as usize;
59
60    for slot in funcs.iter_mut().rev() {
61        if let Some(entry) = slot.as_ref()
62            && (dso.is_null() || entry.dso == dso_usize)
63            && let Some(entry_to_run) = slot.take()
64        {
65            (entry_to_run.func)(entry_to_run.arg as *mut c_void);
66        }
67    }
68
69    // clean up remaining list
70    if dso.is_null() {
71        funcs.clear();
72    } else {
73        funcs.retain(|opt| opt.is_some());
74    }
75}
76
77#[unsafe(no_mangle)]
78pub unsafe extern "C" fn __cxa_thread_atexit_impl(
79    func: extern "C" fn(*mut c_void),
80    obj: *mut c_void,
81    dso: *mut c_void,
82) {
83    let entry = CxaThreadAtExitFunc { func, obj, dso };
84    DTORS.borrow_mut().push(entry);
85}
86
87// called internally
88pub unsafe fn __cxa_thread_finalize() {
89    let mut dtors = DTORS.borrow_mut();
90    while let Some(entry) = dtors.pop() {
91        (entry.func)(entry.obj);
92    }
93}
94
95#[unsafe(no_mangle)]
96pub unsafe extern "C" fn _ITM_deregisterTMCloneTable(_ptr: *mut c_void) {
97    // No-op
98}
99
100#[unsafe(no_mangle)]
101pub unsafe extern "C" fn _ITM_registerTMCloneTable(_ptr: *mut c_void, _len: usize) {
102    // No-op
103}