start.rs 6.3 KB

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