diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 05cc036e22e5df14a5beb00a5da8c611811daf3b..2eaf9061ebe10c4e4497b07b5d7262432b596d75 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -1,5 +1,94 @@ +use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader}; + +use crate::start::Stack; +use self::tcb::{Tcb, Master}; + pub const PAGE_SIZE: usize = 4096; pub mod linker; pub mod start; pub mod tcb; + +pub fn static_init(sp: &'static Stack) { + let mut phdr_opt = None; + let mut phent_opt = None; + let mut phnum_opt = None; + + let mut auxv = sp.auxv(); + loop { + let (kind, value) = unsafe { *auxv }; + if kind == 0 { + break; + } + + match kind { + 3 => phdr_opt = Some(value), + 4 => phent_opt = Some(value), + 5 => phnum_opt = Some(value), + _ => (), + } + + auxv = unsafe { auxv.add(1) }; + } + + let phdr = phdr_opt.expect("failed to find AT_PHDR"); + let phent = phent_opt.expect("failed to find AT_PHENT"); + let phnum = phnum_opt.expect("failed to find AT_PHNUM"); + + for i in 0..phnum { + let ph_addr = phdr + phent * i; + let ph: ProgramHeader = match phent { + program_header32::SIZEOF_PHDR => { + unsafe { *(ph_addr as *const program_header32::ProgramHeader) }.into() + }, + program_header64::SIZEOF_PHDR => { + unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into() + }, + _ => panic!("unknown AT_PHENT size {}", phent), + }; + + let voff = ph.p_vaddr as usize % PAGE_SIZE; + let vaddr = ph.p_vaddr as usize - voff; + let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + match ph.p_type { + program_header::PT_TLS => { + let valign = if ph.p_align > 0 { + ((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align + } else { + ph.p_memsz + } as usize; + + let tcb_master = Master { + ptr: ph.p_vaddr as usize as *const u8, + len: ph.p_filesz as usize, + offset: vsize - valign, + }; + + unsafe { + let tcb = Tcb::new(vsize).expect("failed to allocate TCB"); + tcb.set_masters(vec![tcb_master].into_boxed_slice()); + tcb.copy_masters().expect("failed to copy TLS master data"); + tcb.activate(); + } + + //TODO: Warning on multiple TLS sections? + return; + } + _ => (), + } + } +} + +#[cfg(target_os = "linux")] +pub unsafe fn init(sp: &'static Stack) { + let mut tp = 0usize; + const ARCH_GET_FS: usize = 0x1003; + syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize); + if tp == 0 { + static_init(sp); + } +} + +#[cfg(target_os = "redox")] +pub unsafe fn init(_sp: &'static Stack) {} diff --git a/src/start.rs b/src/start.rs index 7da8250165a0f03cee2cbd0ecd859acf853ac913..a918e6dd7368afc07e2d6e20d1cff880ba97c395 100644 --- a/src/start.rs +++ b/src/start.rs @@ -5,6 +5,7 @@ use header::{stdio, stdlib}; use platform; use platform::types::*; use platform::{Pal, Sys}; +use ld_so; #[repr(C)] pub struct Stack { @@ -77,6 +78,8 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { // Ensure correct host system before executing more system calls relibc_verify_host(); + ld_so::init(sp); + // Set up argc and argv let argc = sp.argc; let argv = sp.argv();