1use alloc::{boxed::Box, vec::Vec};
4use core::{intrinsics, ptr};
5
6#[cfg(target_os = "redox")]
7use generic_rt::ExpectTlsFree;
8
9use crate::{
10 ALLOCATOR,
11 header::{libgen, stdio, stdlib},
12 ld_so::{self, linker::Linker},
13 platform::{self, Pal, Sys, get_auxvs, types::*},
14 sync::mutex::Mutex,
15};
16
17#[repr(C)]
18pub struct Stack {
19 pub argc: isize,
20 pub argv0: *const c_char,
21}
22
23impl Stack {
24 pub fn argv(&self) -> *const *const c_char {
25 ptr::from_ref(&self.argv0)
26 }
27
28 pub fn envp(&self) -> *const *const c_char {
29 unsafe { self.argv().offset(self.argc + 1) }
30 }
31
32 pub fn auxv(&self) -> *const (usize, usize) {
33 unsafe {
34 let mut envp = self.envp();
35 while !(*envp).is_null() {
36 envp = envp.add(1);
37 }
38 envp.add(1).cast::<(usize, usize)>()
39 }
40 }
41}
42
43unsafe fn copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut c_char> {
44 use crate::header::string::strlen;
45
46 let mut vec = Vec::with_capacity(len + 1);
47 let mut lengths = Vec::with_capacity(len);
48 let mut size = 0;
49 for i in 0..len {
50 let item = unsafe { *array.add(i) };
51 lengths.push(unsafe { strlen(item) } + 1);
52 size += lengths[i];
53 }
54
55 let mut offset = 0;
58 let buf = unsafe { platform::alloc(size).cast::<c_char>() };
59
60 #[expect(clippy::needless_range_loop)]
61 for i in 0..len {
62 let dest_buf = unsafe { buf.add(offset) };
63 let item = unsafe { *array.add(i) };
64 let len = lengths[i];
65
66 unsafe {
67 ptr::copy_nonoverlapping(item, dest_buf, len);
68 }
69
70 vec.push(dest_buf);
71 offset += len;
72 }
73 vec.push(ptr::null_mut());
74 vec
75}
76
77#[unsafe(no_mangle)]
80pub unsafe fn relibc_verify_host() {
81 if !Sys::verify() {
82 intrinsics::abort();
83 }
84}
85#[unsafe(link_section = ".init_array")]
86#[used]
87static INIT_ARRAY: [extern "C" fn(); 1] = [init_array];
88
89static mut INIT_COMPLETE: bool = false;
90
91#[used]
92#[unsafe(no_mangle)]
93static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut();
94
95fn alloc_init() {
96 unsafe {
97 if INIT_COMPLETE {
98 return;
99 }
100 }
101 unsafe {
102 if let Some(tcb) = ld_so::tcb::Tcb::current()
103 && !tcb.mspace.is_null()
104 {
105 ALLOCATOR.set(tcb.mspace);
106 }
107 }
108}
109
110extern "C" fn init_array() {
111 unsafe {
117 if INIT_COMPLETE {
118 return;
119 }
120 }
121
122 alloc_init();
123 io_init();
124
125 unsafe {
126 if platform::environ.is_null() {
127 platform::environ = __relibc_init_environ;
128 }
129 }
130
131 unsafe {
132 crate::pthread::init();
133 INIT_COMPLETE = true
134 }
135}
136
137fn io_init() {
138 unsafe {
139 stdio::stdin = stdio::default_stdin().get();
142 stdio::stdout = stdio::default_stdout().get();
143 stdio::stderr = stdio::default_stderr().get();
144 }
145}
146
147#[inline(never)]
148#[unsafe(no_mangle)]
149pub unsafe extern "C" fn relibc_start_v1(
150 sp: &'static Stack,
151 main: unsafe extern "C" fn(
152 argc: isize,
153 argv: *mut *mut c_char,
154 envp: *mut *mut c_char,
155 ) -> c_int,
156) -> ! {
157 unsafe extern "C" {
158 static __preinit_array_start: extern "C" fn();
159 static __preinit_array_end: extern "C" fn();
160 static __init_array_start: extern "C" fn();
161 static __init_array_end: extern "C" fn();
162 }
163
164 unsafe { relibc_verify_host() };
166
167 #[cfg(target_os = "redox")]
168 let thr_fd = redox_rt::proc::FdGuard::new(
169 unsafe {
170 crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
171 }
172 .expect_notls("no thread fd present"),
173 )
174 .to_upper()
175 .expect_notls("failed to move thread fd to upper table");
176
177 #[cfg(target_os = "redox")]
178 {
179 if redox_rt::current_filetable().fd().is_none() {
180 let filetable_fd = unsafe {
181 crate::platform::get_auxv_raw(
182 sp.auxv().cast(),
183 redox_rt::auxv_defs::AT_REDOX_FILETABLE_FD,
184 )
185 }
186 .expect_notls("no filetable fd present");
187 let filetable_guard = redox_rt::proc::FdGuard::new(filetable_fd)
188 .to_upper()
189 .expect_notls("failed to move filetable fd to upper table");
190 *redox_rt::current_filetable() = redox_rt::sys::FdTbl::from_binary_fd(filetable_guard)
191 .expect_notls("failed to initialize FILETABLE");
192 }
193 }
194
195 unsafe {
197 ld_so::init(
198 sp,
199 #[cfg(target_os = "redox")]
200 thr_fd,
201 )
202 };
203
204 alloc_init();
207
208 if let Some(tcb) = unsafe { ld_so::tcb::Tcb::current() } {
209 if tcb.mspace.is_null() {
211 tcb.mspace = ALLOCATOR.get();
212 }
213
214 if tcb.linker_ptr.is_null() {
216 let linker = Linker::new(ld_so::linker::Config::default());
218 tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
220 }
221 #[cfg(target_os = "redox")]
222 redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
223 }
224
225 let argc = sp.argc;
227 let argv = sp.argv();
228 unsafe { platform::inner_argv.unsafe_set(copy_string_array(argv, argc as usize)) };
229 unsafe { platform::argv = platform::inner_argv.unsafe_mut().as_mut_ptr() };
230 if let Some(arg) = unsafe { platform::inner_argv.unsafe_ref() }.first() {
232 unsafe { platform::program_invocation_name = *arg };
233 unsafe { platform::program_invocation_short_name = libgen::basename(*arg) };
234 }
235 if unsafe { platform::environ }.is_null() {
239 let envp = sp.envp();
241 let mut len = 0;
242 while !(unsafe { *envp.add(len) }).is_null() {
243 len += 1;
244 }
245 unsafe { platform::OUR_ENVIRON.unsafe_set(copy_string_array(envp, len)) };
246 unsafe { platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() };
247 }
248
249 let auxvs = unsafe { get_auxvs(sp.auxv().cast()) };
250 unsafe { crate::platform::init(auxvs) };
251 init_array();
252 unsafe { crate::platform::logger::init() };
253
254 {
256 let mut f = core::ptr::from_ref(unsafe { &__preinit_array_start });
257 #[allow(clippy::op_ref)]
258 while f < &raw const __preinit_array_end {
259 (unsafe { *f })();
260 f = unsafe { f.offset(1) };
261 }
262 }
263
264 {
266 let mut f = core::ptr::from_ref(unsafe { &__init_array_start });
267 #[allow(clippy::op_ref)]
268 while f < &raw const __init_array_end {
269 (unsafe { *f })();
270 f = unsafe { f.offset(1) };
271 }
272 }
273
274 unsafe { stdlib::exit(main(argc, platform::argv, platform::environ)) };
276
277 unreachable!();
278}