1 use core::{mem, ptr}; 2 use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader}; 3 4 use self::tcb::{Master, Tcb}; 5 use crate::unix::start::Stack; 6 use crate::unix::platform; 7 use crate::eprintln; 8 9 #[cfg(target_os = "redox")] 10 pub const PATH_SEP: char = ';'; 11 12 #[cfg(target_os = "linux")] 13 pub const PATH_SEP: char = ':'; 14 15 #[cfg(target_os = "dragonos")] 16 pub const PATH_SEP: char = ':'; 17 18 mod access; 19 pub mod callbacks; 20 pub mod debug; 21 mod dso; 22 pub mod linker; 23 pub mod start; 24 pub mod tcb; 25 26 static mut STATIC_TCB_MASTER: Master = Master { 27 ptr: ptr::null_mut(), 28 len: 0, 29 offset: 0, 30 }; 31 32 fn panic_notls(msg: impl core::fmt::Display) -> ! { 33 eprintln!("panicked in ld.so: {}", msg); 34 35 unsafe { 36 core::intrinsics::abort(); 37 } 38 } 39 40 pub trait ExpectTlsFree { 41 type Unwrapped; 42 43 fn expect_notls(self, msg: &str) -> Self::Unwrapped; 44 } 45 impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> { 46 type Unwrapped = T; 47 48 fn expect_notls(self, msg: &str) -> T { 49 match self { 50 Ok(t) => t, 51 Err(err) => panic_notls(format_args!( 52 "{}: expect failed for Result with err: {:?}", 53 msg, err 54 )), 55 } 56 } 57 } 58 impl<T> ExpectTlsFree for Option<T> { 59 type Unwrapped = T; 60 61 fn expect_notls(self, msg: &str) -> T { 62 match self { 63 Some(t) => t, 64 None => panic_notls(format_args!("{}: expect failed for Option", msg)), 65 } 66 } 67 } 68 69 #[inline(never)] 70 pub fn static_init(sp: &'static Stack) { 71 let mut phdr_opt = None; 72 let mut phent_opt = None; 73 let mut phnum_opt = None; 74 75 let mut auxv = sp.auxv(); 76 loop { 77 let (kind, value) = unsafe { *auxv }; 78 if kind == ::AT_NULL { 79 break; 80 } 81 82 match kind { 83 3 => phdr_opt = Some(value), 84 4 => phent_opt = Some(value), 85 5 => phnum_opt = Some(value), 86 _ => (), 87 } 88 89 auxv = unsafe { auxv.add(1) }; 90 } 91 92 let phdr = phdr_opt.expect_notls("failed to find AT_PHDR"); 93 let phent = phent_opt.expect_notls("failed to find AT_PHENT"); 94 let phnum = phnum_opt.expect_notls("failed to find AT_PHNUM"); 95 96 for i in 0..phnum { 97 let ph_addr = phdr + phent * i; 98 let ph: ProgramHeader = match phent { 99 program_header32::SIZEOF_PHDR => { 100 unsafe { *(ph_addr as *const program_header32::ProgramHeader) }.into() 101 } 102 program_header64::SIZEOF_PHDR => { 103 unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into() 104 } 105 _ => panic_notls(format_args!("unknown AT_PHENT size {}", phent)), 106 }; 107 108 let page_size = platform::pal::getpagesize(); 109 let voff = ph.p_vaddr as usize % page_size; 110 let vaddr = ph.p_vaddr as usize - voff; 111 let vsize = ((ph.p_memsz as usize + voff + page_size - 1) / page_size) * page_size; 112 113 match ph.p_type { 114 program_header::PT_TLS => { 115 let valign = if ph.p_align > 0 { 116 ((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align 117 } else { 118 ph.p_memsz 119 } as usize; 120 121 unsafe { 122 STATIC_TCB_MASTER.ptr = ph.p_vaddr as usize as *const u8; 123 STATIC_TCB_MASTER.len = ph.p_filesz as usize; 124 STATIC_TCB_MASTER.offset = valign; 125 126 let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB"); 127 tcb.masters_ptr = &mut STATIC_TCB_MASTER; 128 tcb.masters_len = mem::size_of::<Master>(); 129 tcb.copy_masters() 130 .expect_notls("failed to copy TLS master data"); 131 tcb.activate(); 132 } 133 134 //TODO: Warning on multiple TLS sections? 135 return; 136 } 137 _ => (), 138 } 139 } 140 } 141 142 #[cfg(any(target_os = "linux", target_os = "redox", target_os = "dragonos"))] 143 pub unsafe fn init(sp: &'static Stack) { 144 let mut tp = 0usize; 145 146 #[cfg(target_os = "linux")] 147 { 148 const ARCH_GET_FS: usize = 0x1003; 149 syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize); 150 } 151 #[cfg(target_os = "dragonos")] 152 { 153 const ARCH_GET_FS: usize = 0x1003; 154 // syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize); 155 // unimplemented!() 156 } 157 #[cfg(all(target_os = "redox", target_arch = "aarch64"))] 158 { 159 core::arch::asm!( 160 "mrs {}, tpidr_el0", 161 out(reg) tp, 162 ); 163 } 164 #[cfg(all(target_os = "redox", target_arch = "x86"))] 165 { 166 let mut env = syscall::EnvRegisters::default(); 167 168 let file = syscall::open( 169 "thisproc:current/regs/env", 170 syscall::O_CLOEXEC | syscall::O_RDONLY, 171 ) 172 .expect_notls("failed to open handle for process registers"); 173 174 let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase"); 175 176 let _ = syscall::close(file); 177 178 tp = env.gsbase as usize; 179 } 180 #[cfg(all(target_os = "redox", target_arch = "x86_64"))] 181 { 182 let mut env = syscall::EnvRegisters::default(); 183 184 let file = syscall::open( 185 "thisproc:current/regs/env", 186 syscall::O_CLOEXEC | syscall::O_RDONLY, 187 ) 188 .expect_notls("failed to open handle for process registers"); 189 190 let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase"); 191 192 let _ = syscall::close(file); 193 194 tp = env.fsbase as usize; 195 } 196 197 #[cfg(not(target_os = "dragonos"))] 198 if tp == 0 { 199 static_init(sp); 200 } 201 } 202 203 pub unsafe fn fini() { 204 if let Some(tcb) = Tcb::current() { 205 if tcb.linker_ptr != ptr::null_mut() { 206 let linker = (&*tcb.linker_ptr).lock(); 207 linker.fini(); 208 } 209 } 210 } 211