start.rs 7.0 KB

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