1 use alloc::{boxed::Box, vec::Vec};
2 use core::{fmt::Debug, intrinsics, ptr};
3
4 use crate::{
5 header::{libgen, stdio, stdlib},
6 ld_so::{self, linker::Linker},
7 platform::{self, get_auxvs, new_mspace, types::*, Pal, Sys},
8 sync::mutex::Mutex,
9 ALLOCATOR,
10 };
11
12 #[repr(C)]
13 pub struct Stack {
14 pub argc: isize,
15 pub argv0: *const c_char,
16 }
17
18 impl Stack {
argv(&self) -> *const *const c_char19 pub fn argv(&self) -> *const *const c_char {
20 &self.argv0 as *const _
21 }
22
envp(&self) -> *const *const c_char23 pub fn envp(&self) -> *const *const c_char {
24 unsafe { self.argv().offset(self.argc + 1) }
25 }
26
auxv(&self) -> *const (usize, usize)27 pub fn auxv(&self) -> *const (usize, usize) {
28 unsafe {
29 let mut envp = self.envp();
30 while !(*envp).is_null() {
31 envp = envp.add(1);
32 }
33 envp.add(1) as *const (usize, usize)
34 }
35 }
36 }
37
38 impl Debug for Stack {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 f.debug_struct("Stack")
41 .field("argc", &self.argc)
42 .field("argv0", &self.argv0)
43 .finish()
44 }
45 }
46
copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut c_char>47 unsafe fn copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut c_char> {
48 // println!("copy_string_array: array: {:p}, len: {}", array, len);
49
50 let mut vec = Vec::with_capacity(len + 1);
51
52 for i in 0..len {
53 let item = *array.add(i);
54 let mut len = 0;
55 while *item.add(len) != 0 {
56 len += 1;
57 }
58
59 let buf = platform::alloc(len + 1) as *mut c_char;
60 for i in 0..=len {
61 *buf.add(i) = *item.add(i);
62 }
63 vec.push(buf);
64 }
65 vec.push(ptr::null_mut());
66 vec
67 }
68
69 // Since Redox and Linux are so similar, it is easy to accidentally run a binary from one on the
70 // other. This will test that the current system is compatible with the current binary
71 #[no_mangle]
relibc_verify_host()72 pub unsafe fn relibc_verify_host() {
73 if !Sys::verify() {
74 intrinsics::abort();
75 }
76 }
77 #[link_section = ".init_array"]
78 #[used]
79 static INIT_ARRAY: [extern "C" fn(); 1] = [init_array];
80
81 static mut init_complete: bool = false;
82
83 #[used]
84 #[no_mangle]
85 static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut();
86
alloc_init()87 fn alloc_init() {
88 unsafe {
89 if init_complete {
90 return;
91 }
92 }
93 unsafe {
94 // dbg!("in alloc init");
95 if let Some(tcb) = ld_so::tcb::Tcb::current() {
96 // println!("tcb.mspace {}",tcb.mspace);
97 if tcb.mspace != 0 {
98 ALLOCATOR.set_book_keeper(tcb.mspace);
99 } else if ALLOCATOR.get_book_keeper() == 0 {
100 ALLOCATOR.set_book_keeper(new_mspace());
101 }
102 } else if ALLOCATOR.get_book_keeper() == 0 {
103 // dbg!("TRY");
104 ALLOCATOR.set_book_keeper(new_mspace());
105 // dbg!("ALLOCATOR OWARI DAWA");
106 }
107 }
108 }
109
init_array()110 extern "C" fn init_array() {
111 // The thing is that we cannot guarantee if
112 // init_array runs first or if relibc_start runs first
113 // Still whoever gets to run first must initialize rust
114 // memory allocator before doing anything else.
115
116 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 extern "C" {
132 fn pthread_init();
133 }
134 unsafe {
135 pthread_init();
136 init_complete = true
137 }
138 }
139
io_init()140 fn io_init() {
141 unsafe {
142 // Initialize stdin/stdout/stderr,
143 // see https://github.com/rust-lang/rust/issues/51718
144 stdio::stdin = stdio::default_stdin.get();
145 stdio::stdout = stdio::default_stdout.get();
146 stdio::stderr = stdio::default_stderr.get();
147 }
148 }
149
150 #[cfg(target_os = "redox")]
setup_sigstack()151 fn setup_sigstack() {
152 use syscall::{Map, MapFlags};
153 const SIGSTACK_SIZE: usize = 1024 * 256;
154 let sigstack = unsafe {
155 syscall::fmap(
156 !0,
157 &Map {
158 address: 0,
159 offset: 0,
160 flags: MapFlags::MAP_PRIVATE | MapFlags::PROT_READ | MapFlags::PROT_WRITE,
161 size: SIGSTACK_SIZE,
162 },
163 )
164 }
165 .expect("failed to allocate sigstack")
166 + SIGSTACK_SIZE;
167
168 let fd = syscall::open(
169 "thisproc:current/sigstack",
170 syscall::O_WRONLY | syscall::O_CLOEXEC,
171 )
172 .expect("failed to open thisproc:current/sigstack");
173 syscall::write(fd, &usize::to_ne_bytes(sigstack))
174 .expect("failed to write to thisproc:current/sigstack");
175 let _ = syscall::close(fd);
176 }
177
178 #[inline(never)]
179 #[no_mangle]
relibc_start(sp: &'static Stack) -> !180 pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
181 extern "C" {
182 static __preinit_array_start: extern "C" fn();
183 static __preinit_array_end: extern "C" fn();
184 static __init_array_start: extern "C" fn();
185 static __init_array_end: extern "C" fn();
186
187 fn _init();
188 fn main(argc: isize, argv: *mut *mut c_char, envp: *mut *mut c_char) -> c_int;
189 }
190
191 // Ensure correct host system before executing more system calls
192 relibc_verify_host();
193 use core::arch::asm;
194
195 // Initialize TLS, if necessary
196 ld_so::init(sp);
197
198 // println!("alloc init");
199
200 // Set up the right allocator...
201 // if any memory rust based memory allocation happen before this step .. we are doomed.
202 alloc_init();
203
204 // println!("alloc init ok");
205
206 if let Some(tcb) = ld_so::tcb::Tcb::current() {
207 // Update TCB mspace
208 tcb.mspace = ALLOCATOR.get_book_keeper();
209
210 // Set linker pointer if necessary
211 if tcb.linker_ptr.is_null() {
212 //TODO: get ld path
213 let linker = Linker::new(None);
214 //TODO: load root object
215 tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
216 }
217 }
218
219 // println!("to copy args");
220 // Set up argc and argv
221 let argc = sp.argc;
222 let argv = sp.argv();
223
224 platform::inner_argv = copy_string_array(argv, argc as usize);
225
226 // println!("copy args ok");
227 platform::argv = platform::inner_argv.as_mut_ptr();
228 // Special code for program_invocation_name and program_invocation_short_name
229 if let Some(arg) = platform::inner_argv.get(0) {
230 platform::program_invocation_name = *arg;
231 platform::program_invocation_short_name = libgen::basename(*arg);
232 }
233 // println!("to check environ");
234
235 // We check for NULL here since ld.so might already have initialized it for us, and we don't
236 // want to overwrite it if constructors in .init_array of dependency libraries have called
237 // setenv.
238 if platform::environ.is_null() {
239 // Set up envp
240 let envp = sp.envp();
241 let mut len = 0;
242 while !(*envp.add(len)).is_null() {
243 len += 1;
244 }
245 platform::OUR_ENVIRON = copy_string_array(envp, len);
246 platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
247 }
248 // println!("to get auxvs");
249 let auxvs = get_auxvs(sp.auxv().cast());
250 // println!("to init platform");
251 crate::platform::init(auxvs);
252
253 // Setup signal stack, otherwise we cannot handle any signals besides SIG_IGN/SIG_DFL behavior.
254 #[cfg(target_os = "redox")]
255 setup_sigstack();
256 // println!("before init_array()");
257 init_array();
258 // println!("init_array() ok");
259
260 // Run preinit array
261 {
262 let mut f = &__preinit_array_start as *const _;
263 #[allow(clippy::op_ref)]
264 while f < &__preinit_array_end {
265 (*f)();
266 f = f.offset(1);
267 }
268 }
269
270 // println!("before _init()");
271 // Call init section
272 _init();
273 // println!("after _init()");
274 // Run init array
275 {
276 let mut f = &__init_array_start as *const _;
277 #[allow(clippy::op_ref)]
278 while f < &__init_array_end {
279 (*f)();
280 f = f.offset(1);
281 }
282 }
283
284 // println!("to run main()");
285 // not argv or envp, because programs like bash try to modify this *const* pointer :|
286 stdlib::exit(main(argc, platform::argv, platform::environ));
287
288 unreachable!();
289 }
290