xref: /relibc/src/start.rs (revision be35961d82cd98f2a2e61c4f1869271b9f4af571)
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