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