Kaynağa Gözat

Merge branch 'globalsyms' into 'master'

Fix global symbols relocations

See merge request redox-os/relibc!325
Jeremy Soller 4 yıl önce
ebeveyn
işleme
261951bcba

+ 2 - 0
.gitignore

@@ -4,3 +4,5 @@ sysroot/
 **/target/
 .gdb_history
 *.patch
+*.swp
+*.swo

+ 11 - 15
src/header/dl-tls/mod.rs

@@ -17,21 +17,17 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
         (*ti).ti_offset
     );
     if let Some(tcb) = Tcb::current() {
-        if let Some(tls) = tcb.tls() {
-            if let Some(masters) = tcb.masters() {
-                if let Some(master) = masters.get((*ti).ti_module as usize) {
-                    let addr = tls
-                        .as_mut_ptr()
-                        .add(master.offset + (*ti).ti_offset as usize);
-                    trace!(
-                        "__tls_get_addr({:p}: {:#x}, {:#x}) = {:p}",
-                        ti,
-                        (*ti).ti_module,
-                        (*ti).ti_offset,
-                        addr
-                    );
-                    return addr as *mut c_void;
-                }
+        if let Some(masters) = tcb.masters() {
+            if let Some(master) = masters.get((*ti).ti_module as usize) {
+                let addr = tcb.tls_end.sub(master.offset).add((*ti).ti_offset as usize);
+                trace!(
+                    "__tls_get_addr({:p}: {:#x}, {:#x}) = {:p}",
+                    ti,
+                    (*ti).ti_module,
+                    (*ti).ti_offset,
+                    addr
+                );
+                return addr as *mut c_void;
             }
         }
     }

+ 6 - 32
src/header/dlfcn/mod.rs

@@ -50,13 +50,11 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
     let tcb = match Tcb::current() {
         Some(tcb) => tcb,
         None => {
-            eprintln!("dlopen: tcb not found");
             ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
             return ptr::null_mut();
         }
     };
     if tcb.linker_ptr.is_null() {
-        eprintln!("dlopen: linker not found");
         ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
         return ptr::null_mut();
     }
@@ -67,28 +65,12 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
 
     let id = match (cbs.load_library)(&mut linker, filename) {
         Err(err) => {
-            eprintln!("dlopen: failed to load {:?}", filename);
             ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
             return ptr::null_mut();
         }
         Ok(id) => id,
     };
 
-    if let Some(fname) = filename {
-        if let Err(err) = (cbs.link)(&mut linker, None, None, Some(id)) {
-            (cbs.unload)(&mut linker, id);
-            eprintln!("dlopen: failed to link '{}': {}", fname, err);
-            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-            return ptr::null_mut();
-        };
-
-        if let Err(err) = (cbs.run_init)(&mut linker, Some(id)) {
-            (cbs.unload)(&mut linker, id);
-            eprintln!("dlopen: failed to link '{}': {}", fname, err);
-            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-            return ptr::null_mut();
-        };
-    }
     id as *mut c_void
 }
 
@@ -104,14 +86,12 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
     let tcb = match Tcb::current() {
         Some(tcb) => tcb,
         None => {
-            eprintln!("dlsym: tcb not found");
             ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
             return ptr::null_mut();
         }
     };
 
     if tcb.linker_ptr.is_null() {
-        eprintln!("dlsym: linker not found");
         ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
         return ptr::null_mut();
     }
@@ -119,12 +99,12 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
     let linker = (&*tcb.linker_ptr).lock();
     let cbs_c = linker.cbs.clone();
     let cbs = cbs_c.borrow();
-    if let Some(global) = (cbs.get_sym)(&linker, symbol_str, Some(handle as usize)) {
-        global.as_ptr()
-    } else {
-        eprintln!("dlsym: symbol not found");
-        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-        ptr::null_mut()
+    match (cbs.get_sym)(&linker, handle as usize, symbol_str) {
+        Some(sym) => sym,
+        _ => {
+            ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
+            ptr::null_mut()
+        }
     }
 }
 
@@ -133,24 +113,18 @@ pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
     let tcb = match Tcb::current() {
         Some(tcb) => tcb,
         None => {
-            eprintln!("dlclose: tcb not found");
             ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
             return -1;
         }
     };
 
     if tcb.linker_ptr.is_null() {
-        eprintln!("dlclose: linker not found");
         ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
         return -1;
     };
     let mut linker = (&*tcb.linker_ptr).lock();
     let cbs_c = linker.cbs.clone();
     let cbs = cbs_c.borrow();
-    if let Err(err) = (cbs.run_fini)(&mut linker, Some(handle as usize)) {
-        ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
-        return -1;
-    };
     (cbs.unload)(&mut linker, handle as usize);
     0
 }

+ 1 - 1
src/header/stdio/scanf.rs

@@ -222,7 +222,7 @@ unsafe fn inner_scanf(
                         r.commit();
                         width = width.map(|w| w - 1);
                         if width.map(|w| w > 0).unwrap_or(true) && !read!() {
-                            return Ok(matched);
+                            break;
                         }
                     }
 

+ 7 - 28
src/ld_so/callbacks.rs

@@ -1,15 +1,12 @@
-use super::linker::{Linker, Symbol, DSO};
+use super::linker::Linker;
+use crate::platform::types::c_void;
 use alloc::boxed::Box;
 use goblin::error::Result;
 
 pub struct LinkerCallbacks {
     pub unload: Box<dyn Fn(&mut Linker, usize)>,
     pub load_library: Box<dyn Fn(&mut Linker, Option<&str>) -> Result<usize>>,
-    pub link:
-        Box<dyn Fn(&mut Linker, Option<&str>, Option<DSO>, Option<usize>) -> Result<Option<usize>>>,
-    pub get_sym: Box<dyn Fn(&Linker, &str, Option<usize>) -> Option<Symbol>>,
-    pub run_init: Box<dyn Fn(&Linker, Option<usize>) -> Result<()>>,
-    pub run_fini: Box<dyn Fn(&Linker, Option<usize>) -> Result<()>>,
+    pub get_sym: Box<dyn Fn(&Linker, usize, &str) -> Option<*mut c_void>>,
 }
 
 impl LinkerCallbacks {
@@ -17,37 +14,19 @@ impl LinkerCallbacks {
         LinkerCallbacks {
             unload: Box::new(unload),
             load_library: Box::new(load_library),
-            link: Box::new(link),
             get_sym: Box::new(get_sym),
-            run_init: Box::new(run_init),
-            run_fini: Box::new(run_fini),
         }
     }
 }
 
-fn unload(linker: &mut Linker, libspace: usize) {
-    linker.unload(libspace)
+fn unload(linker: &mut Linker, lib_id: usize) {
+    linker.unload(lib_id)
 }
 
 fn load_library(linker: &mut Linker, name: Option<&str>) -> Result<usize> {
     linker.load_library(name)
 }
 
-fn link(
-    linker: &mut Linker,
-    primary_opt: Option<&str>,
-    dso: Option<DSO>,
-    libspace: Option<usize>,
-) -> Result<Option<usize>> {
-    linker.link(primary_opt, dso, libspace)
-}
-
-fn get_sym(linker: &Linker, name: &str, libspace: Option<usize>) -> Option<Symbol> {
-    linker.get_sym(name, libspace)
-}
-fn run_init(linker: &Linker, libspace: Option<usize>) -> Result<()> {
-    linker.run_init(libspace)
-}
-fn run_fini(linker: &Linker, libspace: Option<usize>) -> Result<()> {
-    linker.run_fini(libspace)
+fn get_sym(linker: &Linker, lib_id: usize, name: &str) -> Option<*mut c_void> {
+    linker.get_sym(lib_id, name)
 }

+ 429 - 0
src/ld_so/dso.rs

@@ -0,0 +1,429 @@
+use super::{
+    debug::{RTLDDebug, _r_debug},
+    linker::Symbol,
+    tcb::{round_up, Master},
+};
+use crate::{
+    header::{errno::STR_ERROR, sys_mman},
+    platform::{errno, types::c_void},
+};
+use alloc::{
+    collections::BTreeMap,
+    string::{String, ToString},
+    vec::Vec,
+};
+use core::{
+    mem::{size_of, transmute},
+    ptr, slice,
+};
+use goblin::{
+    elf::{
+        header::ET_DYN,
+        program_header,
+        r#dyn::{Dyn, DT_DEBUG, DT_RUNPATH},
+        section_header::{SHN_UNDEF, SHT_FINI_ARRAY, SHT_INIT_ARRAY},
+        sym, Elf,
+    },
+    error::{Error, Result},
+};
+
+/// Use to represent a library as well as all the symbols that is loaded withen it.
+#[derive(Default)]
+pub struct DSO {
+    pub name: String,
+    pub id: usize,
+    pub dlopened: bool,
+    pub entry_point: usize,
+    pub runpath: Option<String>,
+    /// Loaded library in-memory data
+    pub mmap: &'static mut [u8],
+    pub global_syms: BTreeMap<String, Symbol>,
+    pub weak_syms: BTreeMap<String, Symbol>,
+    pub dependencies: Vec<String>,
+    /// .init_array addr and len
+    pub init_array: (usize, usize),
+    /// .fini_array addr and len
+    pub fini_array: (usize, usize),
+    pub tls_module_id: usize,
+    pub tls_offset: usize,
+    pub use_count: usize,
+}
+
+impl DSO {
+    pub fn new(
+        path: &str,
+        data: &Vec<u8>,
+        base_addr: Option<usize>,
+        dlopened: bool,
+        id: usize,
+        tls_module_id: usize,
+        tls_offset: usize,
+    ) -> Result<(DSO, Option<Master>)> {
+        let elf = Elf::parse(data)?;
+        let (mmap, tcb_master) = DSO::mmap_and_copy(&path, &elf, &data, base_addr, tls_offset)?;
+        let (global_syms, weak_syms) = DSO::collect_syms(&elf, &mmap)?;
+        let (init_array, fini_array) = DSO::init_fini_arrays(&elf, mmap.as_ptr() as usize);
+
+        let name = match elf.soname {
+            Some(soname) => soname.to_string(),
+            _ => basename(&path),
+        };
+        let tls_offset = match tcb_master {
+            Some(ref master) => master.offset,
+            _ => 0,
+        };
+        let entry_point = if is_pie_enabled(&elf) {
+            mmap.as_ptr() as usize + elf.header.e_entry as usize
+        } else {
+            elf.header.e_entry as usize
+        };
+        let dso = DSO {
+            name: name,
+            id: id,
+            use_count: 1,
+            dlopened: dlopened,
+            entry_point: entry_point,
+            runpath: DSO::get_runpath(&path, &elf)?,
+            mmap: mmap,
+            global_syms: global_syms,
+            weak_syms: weak_syms,
+            dependencies: elf.libraries.iter().map(|s| s.to_string()).collect(),
+            init_array: init_array,
+            fini_array: fini_array,
+            tls_module_id: tls_module_id,
+            tls_offset: tls_offset,
+        };
+        return Ok((dso, tcb_master));
+    }
+
+    pub fn get_sym(&self, name: &str) -> Option<Symbol> {
+        if let Some(value) = self.global_syms.get(name) {
+            Some(*value)
+        } else if let Some(value) = self.weak_syms.get(name) {
+            Some(*value)
+        } else {
+            None
+        }
+    }
+
+    pub fn run_init(&self) {
+        unsafe {
+            let (addr, size) = self.init_array;
+            for i in (0..size).step_by(8) {
+                let func = transmute::<usize, *const Option<extern "C" fn()>>(addr + i);
+                (*func).map(|x| x());
+            }
+        }
+    }
+
+    pub fn run_fini(&self) {
+        unsafe {
+            let (addr, size) = self.fini_array;
+            for i in (0..size).step_by(8).rev() {
+                let func = transmute::<usize, *const Option<extern "C" fn()>>(addr + i);
+                (*func).map(|x| x());
+            }
+        }
+    }
+
+    fn get_runpath(path: &str, elf: &Elf) -> Result<Option<String>> {
+        if let Some(dynamic) = &elf.dynamic {
+            let entry = dynamic.dyns.iter().find(|d| d.d_tag == DT_RUNPATH);
+            match entry {
+                Some(entry) => {
+                    let runpath = elf
+                        .dynstrtab
+                        .get(entry.d_val as usize)
+                        .ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??;
+                    let base = dirname(path);
+                    return Ok(Some(runpath.replace("$ORIGIN", &base)));
+                }
+                _ => return Ok(None),
+            }
+        }
+        return Ok(None);
+    }
+
+    fn mmap_and_copy(
+        path: &str,
+        elf: &Elf,
+        data: &Vec<u8>,
+        base_addr: Option<usize>,
+        tls_offset: usize,
+    ) -> Result<(&'static mut [u8], Option<Master>)> {
+        // data for struct LinkMap
+        let mut l_ld = 0;
+        // Calculate virtual memory bounds
+        let bounds = {
+            let mut bounds_opt: Option<(usize, usize)> = None;
+            for ph in elf.program_headers.iter() {
+                let voff = ph.p_vaddr % ph.p_align;
+                let vaddr = (ph.p_vaddr - voff) as usize;
+                let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
+
+                match ph.p_type {
+                    program_header::PT_DYNAMIC => {
+                        l_ld = ph.p_vaddr;
+                    }
+                    program_header::PT_LOAD => {
+                        trace!("  load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
+                        if let Some(ref mut bounds) = bounds_opt {
+                            if vaddr < bounds.0 {
+                                bounds.0 = vaddr;
+                            }
+                            if vaddr + vsize > bounds.1 {
+                                bounds.1 = vaddr + vsize;
+                            }
+                        } else {
+                            bounds_opt = Some((vaddr, vaddr + vsize));
+                        }
+                    }
+                    _ => (),
+                }
+            }
+            bounds_opt.ok_or(Error::Malformed(
+                "Unable to find PT_LOAD section".to_string(),
+            ))?
+        };
+        trace!("  bounds {:#x}, {:#x}", bounds.0, bounds.1);
+        // Allocate memory
+        let mmap = unsafe {
+            if let Some(addr) = base_addr {
+                let size = if is_pie_enabled(&elf) {
+                    bounds.1
+                } else {
+                    bounds.1 - bounds.0
+                };
+                _r_debug.insert_first(addr as usize, path, addr + l_ld as usize);
+                slice::from_raw_parts_mut(addr as *mut u8, size)
+            } else {
+                let (start, end) = bounds;
+                let size = end - start;
+                let mut flags = sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE;
+                if start != 0 {
+                    flags |= sys_mman::MAP_FIXED_NOREPLACE;
+                }
+                trace!("mmap({:#x}, {:x}, {:x})", start, size, flags);
+                let ptr = sys_mman::mmap(
+                    start as *mut c_void,
+                    size,
+                    //TODO: Make it possible to not specify PROT_EXEC on Redox
+                    sys_mman::PROT_READ | sys_mman::PROT_WRITE,
+                    flags,
+                    -1,
+                    0,
+                );
+                if ptr as usize == !0
+                /* MAP_FAILED */
+                {
+                    return Err(Error::Malformed(format!(
+                        "failed to map {}. errno: {}",
+                        path, STR_ERROR[errno as usize]
+                    )));
+                }
+                if start as *mut c_void != ptr::null_mut() {
+                    assert_eq!(
+                        ptr, start as *mut c_void,
+                        "mmap must always map on the destination we requested"
+                    );
+                }
+                ptr::write_bytes(ptr as *mut u8, 0, size);
+                _r_debug.insert(ptr as usize, path, ptr as usize + l_ld as usize);
+                slice::from_raw_parts_mut(ptr as *mut u8, size)
+            }
+        };
+
+        let skip_load_segment_copy = base_addr.is_some();
+        let mut tcb_master = None;
+
+        // Copy data
+        for ph in elf.program_headers.iter() {
+            let voff = ph.p_vaddr % ph.p_align;
+            let vaddr = (ph.p_vaddr - voff) as usize;
+            let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
+
+            match ph.p_type {
+                program_header::PT_LOAD => {
+                    if skip_load_segment_copy {
+                        continue;
+                    }
+                    let obj_data = {
+                        let range = ph.file_range();
+                        match data.get(range.clone()) {
+                            Some(some) => some,
+                            None => {
+                                return Err(Error::Malformed(format!(
+                                    "failed to read {:x?}",
+                                    range
+                                )))
+                            }
+                        }
+                    };
+
+                    let mmap_data = {
+                        let range = if is_pie_enabled(elf) {
+                            let addr = ph.p_vaddr as usize;
+                            addr..addr + obj_data.len()
+                        } else {
+                            let addr = ph.p_vaddr as usize - mmap.as_ptr() as usize;
+                            addr..addr + obj_data.len()
+                        };
+                        match mmap.get_mut(range.clone()) {
+                            Some(some) => some,
+                            None => {
+                                return Err(Error::Malformed(format!(
+                                    "failed to write {:x?}",
+                                    range
+                                )));
+                            }
+                        }
+                    };
+                    trace!(
+                        "  copy {:#x}, {:#x}: {:#x}, {:#x}",
+                        vaddr,
+                        vsize,
+                        voff,
+                        obj_data.len()
+                    );
+                    mmap_data.copy_from_slice(obj_data);
+                }
+                program_header::PT_TLS => {
+                    let ptr = unsafe {
+                        if is_pie_enabled(elf) {
+                            mmap.as_ptr().add(ph.p_vaddr as usize)
+                        } else {
+                            ph.p_vaddr as *const u8
+                        }
+                    };
+                    tcb_master = Some(Master {
+                        ptr: ptr,
+                        len: ph.p_filesz as usize,
+                        offset: tls_offset + vsize,
+                    });
+                    trace!("  tcb master {:x?}", tcb_master);
+                }
+                program_header::PT_DYNAMIC => {
+                    // overwrite DT_DEBUG if exist in DYNAMIC segment
+                    // first we identify the location of DYNAMIC segment
+                    let dyn_start = ph.p_vaddr as usize;
+                    let mut debug_start = None;
+                    // next we identify the location of DT_DEBUG in .dynamic section
+                    if let Some(dynamic) = elf.dynamic.as_ref() {
+                        let mut i = 0;
+                        for entry in &dynamic.dyns {
+                            if entry.d_tag == DT_DEBUG {
+                                debug_start = Some(i as usize);
+                                break;
+                            }
+                            i += 1;
+                        }
+                    }
+                    if let Some(i) = debug_start {
+                        let bytes: [u8; size_of::<Dyn>() / 2] =
+                            unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
+                        let start = if is_pie_enabled(elf) {
+                            dyn_start + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
+                        } else {
+                            dyn_start + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
+                                - mmap.as_mut_ptr() as usize
+                        };
+                        mmap[start..start + size_of::<Dyn>() / 2].clone_from_slice(&bytes);
+                    }
+                }
+                _ => (),
+            }
+        }
+        return Ok((mmap, tcb_master));
+    }
+
+    fn collect_syms(
+        elf: &Elf,
+        mmap: &[u8],
+    ) -> Result<(BTreeMap<String, Symbol>, BTreeMap<String, Symbol>)> {
+        let mut globals = BTreeMap::new();
+        let mut weak_syms = BTreeMap::new();
+        for sym in elf.dynsyms.iter() {
+            let bind = sym.st_bind();
+            if sym.st_shndx == SHN_UNDEF as usize
+                || ![sym::STB_GLOBAL, sym::STB_WEAK].contains(&bind)
+            {
+                continue;
+            }
+            let name: String;
+            let value: Symbol;
+            if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
+                name = name_res?.to_string();
+                value = if is_pie_enabled(elf) {
+                    Symbol {
+                        base: mmap.as_ptr() as usize,
+                        value: sym.st_value as usize,
+                        size: sym.st_size as usize,
+                    }
+                } else {
+                    Symbol {
+                        base: 0,
+                        value: sym.st_value as usize,
+                        size: sym.st_size as usize,
+                    }
+                };
+            } else {
+                continue;
+            }
+            match sym.st_bind() {
+                sym::STB_GLOBAL => {
+                    trace!("  global {}: {:x?} = {:p}", &name, sym, value.as_ptr());
+                    globals.insert(name, value);
+                }
+                sym::STB_WEAK => {
+                    trace!("  weak {}: {:x?} = {:p}", &name, sym, value.as_ptr());
+                    weak_syms.insert(name, value);
+                }
+                _ => unreachable!(),
+            }
+        }
+        return Ok((globals, weak_syms));
+    }
+
+    fn init_fini_arrays(elf: &Elf, mmap_addr: usize) -> ((usize, usize), (usize, usize)) {
+        let mut init_array: (usize, usize) = (0, 0);
+        let mut fini_array: (usize, usize) = (0, 0);
+        for section in elf
+            .section_headers
+            .iter()
+            .filter(|s| s.sh_type == SHT_INIT_ARRAY || s.sh_type == SHT_FINI_ARRAY)
+        {
+            let addr = if is_pie_enabled(&elf) {
+                mmap_addr + section.vm_range().start
+            } else {
+                section.vm_range().start
+            };
+            if section.sh_type == SHT_INIT_ARRAY {
+                init_array = (addr, section.sh_size as usize);
+            } else {
+                fini_array = (addr, section.sh_size as usize);
+            }
+        }
+        return (init_array, fini_array);
+    }
+}
+
+impl Drop for DSO {
+    fn drop(&mut self) {
+        self.run_fini();
+        unsafe { sys_mman::munmap(self.mmap.as_mut_ptr() as *mut c_void, self.mmap.len()) };
+    }
+}
+
+pub fn is_pie_enabled(elf: &Elf) -> bool {
+    return elf.header.e_type == ET_DYN;
+}
+
+fn basename(path: &str) -> String {
+    return path.split("/").last().unwrap_or(path).to_string();
+}
+
+fn dirname(path: &str) -> String {
+    let mut parts: Vec<&str> = path.split("/").collect();
+    parts.truncate(parts.len() - 1);
+    return parts.join("/");
+}

+ 0 - 54
src/ld_so/library.rs

@@ -1,54 +0,0 @@
-use super::linker::Symbol;
-use alloc::{
-    boxed::Box,
-    collections::{BTreeMap, BTreeSet},
-    string::String,
-    vec::Vec,
-};
-
-#[derive(Default, Debug)]
-pub struct DepTree {
-    pub name: String,
-    pub deps: Vec<DepTree>,
-}
-
-impl DepTree {
-    pub fn new(name: String) -> DepTree {
-        DepTree {
-            name,
-            deps: Vec::new(),
-        }
-    }
-}
-
-/// Use to represnt a library as well as all th symbols that is loaded withen it.
-#[derive(Default)]
-pub struct Library {
-    /// Global symbols
-    pub globals: BTreeMap<String, Symbol>,
-    /// Weak symbols
-    pub weak_syms: BTreeMap<String, Symbol>,
-    /// Loaded library raw data
-    pub objects: BTreeMap<String, Box<[u8]>>,
-    /// Loaded library in-memory data
-    pub mmaps: BTreeMap<String, (usize, &'static mut [u8])>,
-    /// Each object will have its children called once with no repetition.
-    pub dep_tree: DepTree,
-    /// A set used to detect circular dependencies in the Linker::load function
-    pub cir_dep: BTreeSet<String>,
-    pub runpath: Option<String>,
-}
-impl Library {
-    pub fn new() -> Library {
-        Default::default()
-    }
-    pub fn get_sym(&self, name: &str) -> Option<Symbol> {
-        if let Some(value) = self.globals.get(name) {
-            Some(*value)
-        } else if let Some(value) = self.weak_syms.get(name) {
-            Some(*value)
-        } else {
-            None
-        }
-    }
-}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 222 - 672
src/ld_so/linker.rs


+ 8 - 2
src/ld_so/mod.rs

@@ -6,10 +6,16 @@ use crate::{header::sys_auxv::AT_NULL, start::Stack};
 
 pub const PAGE_SIZE: usize = 4096;
 
+#[cfg(target_os = "redox")]
+pub const PATH_SEP: char = ';';
+
+#[cfg(target_os = "linux")]
+pub const PATH_SEP: char = ':';
+
 mod access;
 pub mod callbacks;
 pub mod debug;
-mod library;
+mod dso;
 pub mod linker;
 pub mod start;
 pub mod tcb;
@@ -73,7 +79,7 @@ pub fn static_init(sp: &'static Stack) {
                 unsafe {
                     STATIC_TCB_MASTER.ptr = ph.p_vaddr as usize as *const u8;
                     STATIC_TCB_MASTER.len = ph.p_filesz as usize;
-                    STATIC_TCB_MASTER.offset = vsize - valign;
+                    STATIC_TCB_MASTER.offset = valign;
 
                     let tcb = Tcb::new(vsize).expect("failed to allocate TCB");
                     tcb.masters_ptr = &mut STATIC_TCB_MASTER;

+ 9 - 41
src/ld_so/start.rs

@@ -17,13 +17,9 @@ use crate::{
     ALLOCATOR,
 };
 
-use super::{
-    access::accessible,
-    debug::_r_debug,
-    linker::{Linker, DSO, PATH_SEP},
-    tcb::Tcb,
-};
+use super::{access::accessible, debug::_r_debug, linker::Linker, tcb::Tcb, PATH_SEP};
 use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR};
+use goblin::elf::header::header64::SIZEOF_EHDR;
 
 unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
     //traverse the stack and collect argument vector
@@ -214,53 +210,25 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
     // if we are not running in manual mode, then the main
     // program is already loaded by the kernel and we want
     // to use it. on redox, we treat it the same.
-    let program = {
-        let mut pr = None;
+    let base_addr = {
+        let mut base = None;
         if !is_manual && cfg!(not(target_os = "redox")) {
             let phdr = *auxv.get(&AT_PHDR).unwrap();
             if phdr != 0 {
-                let p = DSO {
-                    name: path.to_owned(),
-                    entry_point: *auxv.get(&AT_ENTRY).unwrap(),
-                    // The 0x40 is the size of Elf header not a good idea for different bit size
-                    // compatiablility but it will always work on 64 bit systems,
-                    base_addr: phdr - 0x40,
-                };
-                pr = Some(p);
+                base = Some(phdr - SIZEOF_EHDR);
             }
         }
-        pr
+        base
     };
-    let mut linker = Linker::new(ld_library_path, false);
-    match linker.load(&path, &path) {
-        Ok(()) => (),
-        Err(err) => {
-            eprintln!("ld.so: failed to load '{}': {}", path, err);
-            unistd::_exit(1);
-            loop {}
-        }
-    }
-
-    let entry = match linker.link(Some(&path), program, None) {
-        Ok(ok) => match ok {
-            Some(some) => some,
-            None => {
-                eprintln!("ld.so: failed to link '{}': missing entry", path);
-                unistd::_exit(1);
-                loop {}
-            }
-        },
+    let mut linker = Linker::new(ld_library_path);
+    let entry = match linker.load_program(&path, base_addr) {
+        Ok(entry) => entry,
         Err(err) => {
             eprintln!("ld.so: failed to link '{}': {}", path, err);
             unistd::_exit(1);
             loop {}
         }
     };
-    if let Err(e) = linker.run_init(None) {
-        eprintln!("ld.so: failed to run .init_array");
-        unistd::_exit(1);
-        loop {}
-    }
     if let Some(tcb) = unsafe { Tcb::current() } {
         tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
         tcb.mspace = ALLOCATOR.get_book_keeper();

+ 44 - 24
src/ld_so/tcb.rs

@@ -1,5 +1,5 @@
-use alloc::boxed::Box;
-use core::{mem, ops::Range, ptr, slice};
+use alloc::vec::Vec;
+use core::{mem, ptr, slice};
 use goblin::error::{Error, Result};
 
 use crate::{header::sys_mman, ld_so::linker::Linker, sync::mutex::Mutex};
@@ -7,6 +7,7 @@ use crate::{header::sys_mman, ld_so::linker::Linker, sync::mutex::Mutex};
 use super::PAGE_SIZE;
 
 #[repr(C)]
+#[derive(Debug)]
 pub struct Master {
     /// Pointer to initial data
     pub ptr: *const u8,
@@ -21,11 +22,6 @@ impl Master {
     pub unsafe fn data(&self) -> &'static [u8] {
         slice::from_raw_parts(self.ptr, self.len)
     }
-
-    /// The region of TLS that the master will initialize
-    pub fn range(&self) -> Range<usize> {
-        self.offset..self.offset + self.len
-    }
 }
 
 #[derive(Debug)]
@@ -43,6 +39,8 @@ pub struct Tcb {
     pub masters_ptr: *mut Master,
     /// Size of the masters list in bytes (multiple of mem::size_of::<Master>())
     pub masters_len: usize,
+    /// Index of last copied Master
+    pub last_master_copied: usize,
     /// Pointer to dynamic linker
     pub linker_ptr: *const Mutex<Linker>,
     /// pointer to rust memory allocator structure
@@ -52,10 +50,10 @@ pub struct Tcb {
 impl Tcb {
     /// Create a new TCB
     pub unsafe fn new(size: usize) -> Result<&'static mut Self> {
-        let (tls, tcb_page) = Self::os_new(size)?;
+        let (tls, tcb_page) = Self::os_new(round_up(size, PAGE_SIZE))?;
 
         let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self;
-        // println!("New TCB: {:p}", tcb_ptr);
+        trace!("New TCB: {:p}", tcb_ptr);
         ptr::write(
             tcb_ptr,
             Self {
@@ -65,6 +63,7 @@ impl Tcb {
                 tcb_len: tcb_page.len(),
                 masters_ptr: ptr::null_mut(),
                 masters_len: 0,
+                last_master_copied: 0,
                 linker_ptr: ptr::null(),
                 mspace: 0,
             },
@@ -109,26 +108,34 @@ impl Tcb {
     }
 
     /// Copy data from masters
-    pub unsafe fn copy_masters(&self) -> Result<()> {
+    pub unsafe fn copy_masters(&mut self) -> Result<()> {
         //TODO: Complain if masters or tls exist without the other
         if let Some(tls) = self.tls() {
             if let Some(masters) = self.masters() {
-                for (i, master) in masters.iter().enumerate() {
-                    let range = master.range();
-                    let data = master.data();
+                for (i, master) in masters
+                    .iter()
+                    .skip(self.last_master_copied)
+                    .filter(|m| m.len > 0)
+                    .enumerate()
+                {
+                    let range =
+                        self.tls_len - master.offset..self.tls_len - master.offset + master.len;
                     if let Some(tls_data) = tls.get_mut(range) {
-                        // println!(
-                        //     "tls master {}: {:p}, {:#x}: {:p}, {:#x}",
-                        //     i,
-                        //     data.as_ptr(), data.len(),
-                        //     tls_data.as_mut_ptr(), tls_data.len()
-                        // );
-
+                        let data = master.data();
+                        trace!(
+                            "tls master {}: {:p}, {:#x}: {:p}, {:#x}",
+                            i,
+                            data.as_ptr(),
+                            data.len(),
+                            tls_data.as_mut_ptr(),
+                            tls_data.len()
+                        );
                         tls_data.copy_from_slice(data);
                     } else {
                         return Err(Error::Malformed(format!("failed to copy tls master {}", i)));
                     }
                 }
+                self.last_master_copied = masters.len();
             }
         }
 
@@ -136,10 +143,19 @@ impl Tcb {
     }
 
     /// The initial images for TLS
-    pub unsafe fn set_masters(&mut self, mut masters: Box<[Master]>) {
-        self.masters_ptr = masters.as_mut_ptr();
-        self.masters_len = masters.len() * mem::size_of::<Master>();
-        mem::forget(masters);
+    pub unsafe fn append_masters(&mut self, mut new_masters: Vec<Master>) {
+        if self.masters_ptr.is_null() {
+            self.masters_ptr = new_masters.as_mut_ptr();
+            self.masters_len = new_masters.len() * mem::size_of::<Master>();
+            mem::forget(new_masters);
+        } else {
+            let len = self.masters_len / mem::size_of::<Master>();
+            let mut masters = Vec::from_raw_parts(self.masters_ptr, len, len);
+            masters.extend(new_masters.into_iter());
+            self.masters_ptr = masters.as_mut_ptr();
+            self.masters_len = masters.len() * mem::size_of::<Master>();
+            mem::forget(masters);
+        }
     }
 
     /// Activate TLS
@@ -217,3 +233,7 @@ impl Tcb {
         //TODO: Consider setting FS offset to TCB pointer
     }
 }
+
+pub fn round_up(value: usize, alignment: usize) -> usize {
+    return (value + alignment - 1) & (!(alignment - 1));
+}

+ 0 - 1
src/macros.rs

@@ -78,7 +78,6 @@ macro_rules! trace {
     ($($arg:tt)*) => ({
         use $crate::{Pal, Sys};
         eprintln!($($arg)*);
-        Sys::fsync(2);
     });
 }
 

+ 2 - 2
src/sync/semaphore.rs

@@ -1,8 +1,8 @@
 // From https://www.remlab.net/op/futex-misc.shtml
 //TODO: improve implementation
 
-use crate::platform::{types::*, Pal, Sys};
 use super::AtomicLock;
+use crate::platform::{types::*, Pal, Sys};
 use core::sync::atomic::Ordering;
 
 pub struct Semaphore {
@@ -29,7 +29,7 @@ impl Semaphore {
                 value,
                 value - 1,
                 Ordering::Acquire,
-                Ordering::Relaxed
+                Ordering::Relaxed,
             ) {
                 Ok(ok) => return,
                 Err(err) => {

+ 35 - 40
tests/Makefile

@@ -12,6 +12,7 @@ EXPECT_NAMES=\
 	fcntl/create \
 	fcntl/fcntl \
 	fnmatch \
+	futimens \
 	libgen \
 	locale \
 	math \
@@ -22,18 +23,25 @@ EXPECT_NAMES=\
 	setjmp \
 	sigaction \
 	signal \
+	stdio/all \
+	stdio/buffer \
+	stdio/fgets \
 	stdio/fputs \
 	stdio/fread \
+	stdio/freopen \
 	stdio/fseek \
 	stdio/fwrite \
+	stdio/getc_unget \
 	stdio/mutex \
 	stdio/popen \
 	stdio/printf \
 	stdio/rename \
 	stdio/scanf \
+	stdio/setvbuf \
 	stdio/sprintf \
 	stdio/printf_space_pad \
 	stdio/ungetc_ftell \
+	stdio/ungetc_multiple \
 	stdio/fscanf_offby1 \
 	stdio/fscanf \
 	stdio/printf_neg_pad \
@@ -69,6 +77,7 @@ EXPECT_NAMES=\
 	sys_mman \
 	time/asctime \
 	time/gmtime \
+	time/localtime \
 	time/macros \
 	time/mktime \
 	time/strftime \
@@ -82,6 +91,8 @@ EXPECT_NAMES=\
 	unistd/fork \
 	unistd/fsync \
 	unistd/ftruncate \
+	unistd/getopt \
+	unistd/getopt_long \
 	unistd/pipe \
 	unistd/rmdir \
 	unistd/sleep \
@@ -98,34 +109,20 @@ EXPECT_NAMES=\
 	wchar/wcsrchr \
 	wchar/wcsstr \
 	wchar/wcstod \
+	wchar/wcstok \
 	wchar/wcstol \
 	wchar/wcscasecmp \
 	wchar/wcsncasecmp \
+	wctype/towlower \
+	wctype/towupper
 	# TODO: Fix these
 	# mkfifo
 	# netdb/netdb \
 
-# issues with linking stdin, stdout, stderr
-STATIC_ONLY_NAMES=\
-	futimens \
-	stdio/all \
-	stdio/buffer \
-	stdio/fgets \
-	stdio/freopen \
-	stdio/getc_unget \
-	stdio/setvbuf \
-	stdio/ungetc_multiple \
-	time/localtime \
-	wchar/wcstok \
-	wctype/towlower \
-	wctype/towupper \
 # need to call fini in ld_so's _start
-STATIC_ONLY_NAMES+=\
-	destructor \
-# issues with linking optarg, optind etc.
-STATIC_ONLY_NAMES+=\
-	unistd/getopt \
-	unistd/getopt_long \
+STATIC_ONLY_NAMES=\
+	destructor
+
 
 DYNAMIC_ONLY_NAMES=\
 	dlfcn
@@ -205,9 +202,15 @@ FLAGS=\
 	-I .
 
 STATIC_FLAGS=\
-	../sysroot/lib/libc.a \
 	-static
 
+DYNAMIC_FLAGS=\
+	-Wl,--enable-new-dtags \
+	-Wl,-export-dynamic
+
+../sysroot:
+	$(MAKE) -C .. sysroot
+
 NATIVE_RELIBC?=0
 ifeq ($(NATIVE_RELIBC),0)
 FLAGS+=\
@@ -218,32 +221,24 @@ FLAGS+=\
 	../sysroot/lib/crti.o \
 	../sysroot/lib/crtn.o
 
-../sysroot:
-	$(MAKE) -C .. sysroot
-
-bins_static/%: %.c ../sysroot
-	mkdir -p "$$(dirname "$@")"
-	$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
-
 SYSROOT_LIB=$(shell realpath ../sysroot/lib/)
 
-DYNAMIC_FLAGS=\
+STATIC_FLAGS+=\
+	$(SYSROOT_LIB)/libc.a
+
+DYNAMIC_FLAGS+=\
 	-Wl,-dynamic-linker=$(SYSROOT_LIB)/ld64.so.1 \
-	-Wl,--enable-new-dtags \
-	-Wl,-rpath=$(SYSROOT_LIB) \
-	-Wl,-export-dynamic \
+	-Wl,-rpath=$(SYSROOT_LIB):\$$ORIGIN \
 	-L $(SYSROOT_LIB) \
 	-lc
 
-bins_dynamic/%: %.c ../sysroot
-	mkdir -p "$$(dirname "$@")"
-	$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
-else
-bins_static/%: %.c
+DEPS=../sysroot
+endif
+
+bins_static/%: %.c $(DEPS)
 	mkdir -p "$$(dirname "$@")"
 	$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
 
-bins_dynamic/%: %.c
+bins_dynamic/%: %.c $(DEPS)
 	mkdir -p "$$(dirname "$@")"
-	$(CC) "$<" -o "$@" $(FLAGS)
-endif
+	$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)

+ 1 - 1
tests/futimens.c

@@ -12,7 +12,7 @@ int main(int argc, char** argv) {
   char temp[] = "/tmp/stattest-XXXXXX";
   const char file[] = "/mkfifo_fifo";
   int len = sizeof(temp) + sizeof(int);
-  char* path = malloc(len * sizeof(char));
+  char* path = calloc(len, sizeof(char));
 
   if (path == NULL) {
     fprintf(stderr, "Could not allocate: %s\n", strerror(errno));

+ 1 - 1
tests/stdio/scanf.c

@@ -33,7 +33,7 @@ void test(char* fmt_in, char* input, struct params *p, ...) {
 int main(void) {
     struct params p = { .c = 'a' };
 
-    test("%hhd %d", "12 345", &p, &p.sa, &p.ia);
+    test("%hd %d", "12 345", &p, &p.sa, &p.ia);
     test("%x %i %i", "12 0x345 010", &p, &p.ia, &p.ib, &p.ic);
     test("%f.%lf", "0.1.0.2", &p, &p.fa, &p.da);
     test("%p", "0xABCDEF", &p, &p.ptr);

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor