xref: /relibc/src/ld_so/mod.rs (revision be35961d82cd98f2a2e61c4f1869271b9f4af571)
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