xref: /drstd/dlibc/src/unix/ld_so/mod.rs (revision 86982c5e9b2eaa583327251616ee822c36288824)
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