xref: /relibc/src/ld_so/mod.rs (revision a7480ea65652f7bb2211c2a70623165ff2e3bd7f)
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::{header::sys_auxv::AT_NULL, start::Stack};
6 
7 pub const PAGE_SIZE: usize = 4096;
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 mod access;
16 pub mod callbacks;
17 pub mod debug;
18 mod dso;
19 pub mod linker;
20 pub mod start;
21 pub mod tcb;
22 
23 static mut STATIC_TCB_MASTER: Master = Master {
24     ptr: ptr::null_mut(),
25     len: 0,
26     offset: 0,
27 };
28 
29 pub fn static_init(sp: &'static Stack) {
30     let mut phdr_opt = None;
31     let mut phent_opt = None;
32     let mut phnum_opt = None;
33 
34     let mut auxv = sp.auxv();
35     loop {
36         let (kind, value) = unsafe { *auxv };
37         if kind == AT_NULL {
38             break;
39         }
40 
41         match kind {
42             3 => phdr_opt = Some(value),
43             4 => phent_opt = Some(value),
44             5 => phnum_opt = Some(value),
45             _ => (),
46         }
47 
48         auxv = unsafe { auxv.add(1) };
49     }
50 
51     let phdr = phdr_opt.expect("failed to find AT_PHDR");
52     let phent = phent_opt.expect("failed to find AT_PHENT");
53     let phnum = phnum_opt.expect("failed to find AT_PHNUM");
54 
55     for i in 0..phnum {
56         let ph_addr = phdr + phent * i;
57         let ph: ProgramHeader = match phent {
58             program_header32::SIZEOF_PHDR => {
59                 unsafe { *(ph_addr as *const program_header32::ProgramHeader) }.into()
60             }
61             program_header64::SIZEOF_PHDR => {
62                 unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into()
63             }
64             _ => panic!("unknown AT_PHENT size {}", phent),
65         };
66 
67         let voff = ph.p_vaddr as usize % PAGE_SIZE;
68         let vaddr = ph.p_vaddr as usize - voff;
69         let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
70 
71         match ph.p_type {
72             program_header::PT_TLS => {
73                 let valign = if ph.p_align > 0 {
74                     ((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align
75                 } else {
76                     ph.p_memsz
77                 } as usize;
78 
79                 unsafe {
80                     STATIC_TCB_MASTER.ptr = ph.p_vaddr as usize as *const u8;
81                     STATIC_TCB_MASTER.len = ph.p_filesz as usize;
82                     STATIC_TCB_MASTER.offset = valign;
83 
84                     let tcb = Tcb::new(vsize).expect("failed to allocate TCB");
85                     tcb.masters_ptr = &mut STATIC_TCB_MASTER;
86                     tcb.masters_len = mem::size_of::<Master>();
87                     tcb.copy_masters().expect("failed to copy TLS master data");
88                     tcb.activate();
89                 }
90 
91                 //TODO: Warning on multiple TLS sections?
92                 return;
93             }
94             _ => (),
95         }
96     }
97 }
98 
99 #[cfg(target_os = "linux")]
100 pub unsafe fn init(sp: &'static Stack) {
101     let mut tp = 0usize;
102     const ARCH_GET_FS: usize = 0x1003;
103     syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize);
104     if tp == 0 {
105         static_init(sp);
106     }
107 }
108 
109 #[cfg(target_os = "redox")]
110 pub unsafe fn init(_sp: &'static Stack) {}
111