Files
RedBear-OS/src/ld_so/mod.rs
T
oddcoder 02aa400c5c Add callbacks to ld.so version of Linker's function
It is fact that ld.so has libc statially linked into it.

Normally we wouldn't need ld.so functionality once the program is
finalyl loaded, but with the next few patches, we will have dlopen which
will reuse the same ld.so functionality.

The problem is that it seams that huge part of the code is possible not
referntially transparent. That is, it is not impossible that some of the
functions have internals states. So when using the struct Linker that is
initialized by ld.so's copy of libc. we must access it using the same
copy even if both copies are identical.
For example in dlopen if you do linker.load_library(..). That would
segfault because it is using the function from libc not ld.so

So I don't truly undestand why should this be needed, but after long
hours of being stuck I thought maybe.. maybe that is the issue and
indeed it turned out to be so.
2020-07-19 21:21:48 +02:00

97 lines
2.8 KiB
Rust

use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};
use self::tcb::{Master, Tcb};
use crate::start::Stack;
pub const PAGE_SIZE: usize = 4096;
mod access;
pub mod callbacks;
pub mod debug;
mod library;
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) {}