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