From 40328a0d092a222df0a357e8fdf2f0d6f8603b96 Mon Sep 17 00:00:00 2001 From: Ahmed Abd El Mawgood <ahmedsoliman@oddcoder.com> Date: Wed, 12 Aug 2020 10:19:32 +0000 Subject: [PATCH] Modify ld_script so that it works on linux. Honestly, I have no idea why are these modifications needed, but it seams they are needed --- .gitignore | 2 ++ Makefile | 4 +-- src/ld_so/access.rs | 17 +++++++++--- src/ld_so/ld_script | 18 ++++++++++-- src/ld_so/linker.rs | 18 +++--------- src/ld_so/start.rs | 67 +++++++++++++++++++++++++++++++++++++++------ 6 files changed, 95 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index ac81a4ad5..3d392c136 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ prefix/ sysroot/ **/target/ +.gdb_history +*.patch diff --git a/Makefile b/Makefile index 0939fc9bf..20cd11d0c 100644 --- a/Makefile +++ b/Makefile @@ -134,7 +134,7 @@ $(BUILD)/debug/ld_so.o: $(SRC) touch $@ $(BUILD)/debug/ld_so: $(BUILD)/debug/ld_so.o $(BUILD)/debug/crti.o $(BUILD)/debug/libc.a $(BUILD)/debug/crtn.o - $(LD) -T src/ld_so/ld_script --allow-multiple-definition --gc-sections --gc-keep-exported $^ -o $@ + $(LD) --no-relax -T src/ld_so/ld_script --allow-multiple-definition --gc-sections --gc-keep-exported $^ -o $@ # Release targets @@ -173,7 +173,7 @@ $(BUILD)/release/ld_so.o: $(SRC) touch $@ $(BUILD)/release/ld_so: $(BUILD)/release/ld_so.o $(BUILD)/release/crti.o $(BUILD)/release/libc.a $(BUILD)/release/crtn.o - $(LD) -T src/ld_so/ld_script --allow-multiple-definition --gc-sections --gc-keep-exported $^ -o $@ + $(LD) --no-relax -T src/ld_so/ld_script --allow-multiple-definition --gc-sections --gc-keep-exported $^ -o $@ # Other targets diff --git a/src/ld_so/access.rs b/src/ld_so/access.rs index 624edff86..7cf0d201d 100644 --- a/src/ld_so/access.rs +++ b/src/ld_so/access.rs @@ -1,20 +1,29 @@ // Wrapper over the access syscall that doesn't touch errno variable, // Do not use outside of ld_so -use crate::{c_str::CStr, platform::types::*}; - #[cfg(target_os = "redox")] use crate::header::unistd::{F_OK, R_OK, W_OK, X_OK}; +use crate::{ + c_str::{CStr, CString}, + platform::types::*, +}; + +pub fn accessible(path: &str, mode: c_int) -> c_int { + let path_c = CString::new(path.as_bytes()).unwrap(); /*.map_err(|err| { + Error::Malformed(format!("invalid path '{}': {}", path, err)) + })?;*/ + unsafe { access(path_c.as_ptr(), mode) } +} #[cfg(target_os = "linux")] -pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int { +unsafe fn access(path: *const c_char, mode: c_int) -> c_int { let path = CStr::from_ptr(path); syscall!(ACCESS, (path).as_ptr(), mode) as c_int } // Wrapper over the systemcall, Do not use outside of ld_so #[cfg(target_os = "redox")] -pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int { +unsafe fn access(path: *const c_char, mode: c_int) -> c_int { let path = CStr::from_ptr(path).to_bytes(); let fd = match syscall::open(path, syscall::O_CLOEXEC) { Ok(fd) => fd, diff --git a/src/ld_so/ld_script b/src/ld_so/ld_script index 7cfac6022..1ea6287d8 100644 --- a/src/ld_so/ld_script +++ b/src/ld_so/ld_script @@ -8,10 +8,20 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", OUTPUT_ARCH(i386:x86-64) ENTRY(_start) SEARCH_DIR("/x86_64-unknown-redox/lib"); +SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64"); +SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.164"); +SEARCH_DIR("/usr/local/lib64"); +SEARCH_DIR("/lib64"); +SEARCH_DIR("/usr/lib64"); +SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib"); +SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.1"); +SEARCH_DIR("/usr/local/lib"); +SEARCH_DIR("/lib"); +SEARCH_DIR("/usr/lib"); SECTIONS { /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS; + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x12340000)); . = SEGMENT_START("text-segment", 0x1234000) + SIZEOF_HEADERS; .interp : { *(.interp) } .note.gnu.build-id : { *(.note.gnu.build-id) } .hash : { *(.hash) } @@ -46,6 +56,7 @@ SECTIONS *(.rela.iplt) PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); .init : { KEEP (*(SORT_NONE(.init))) @@ -59,7 +70,6 @@ SECTIONS *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) - *(SORT(.text.sorted.*)) *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf.em. */ *(.gnu.warning) @@ -71,6 +81,10 @@ SECTIONS PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index c55e4a7d6..ee1f3ee7d 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -31,7 +31,7 @@ use crate::{ }; use super::{ - access::access, + access::accessible, callbacks::LinkerCallbacks, debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug}, library::{DepTree, Library}, @@ -39,10 +39,10 @@ use super::{ PAGE_SIZE, }; #[cfg(target_os = "redox")] -const PATH_SEP: char = ';'; +pub const PATH_SEP: char = ';'; #[cfg(target_os = "linux")] -const PATH_SEP: char = ':'; +pub const PATH_SEP: char = ':'; pub struct DSO { pub name: String, @@ -178,18 +178,8 @@ impl Linker { if self.verbose { println!("check {}", path); } - let access = unsafe { - let path_c = CString::new(path.as_bytes()).map_err(|err| { - Error::Malformed(format!("invalid path '{}': {}", path, err)) - })?; - - // TODO: Use R_OK | X_OK - // We cannot use unix stdlib because errno is thead local variable - // and fs:[0] is not set yet. - access(path_c.as_ptr(), unistd::F_OK) == 0 - }; - if access { + if accessible(&path, unistd::F_OK) == 0 { return Ok(Some(self.load_recursive(name, &path, lib)?)); } } diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index b6eb7a3b1..23296f035 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -1,6 +1,12 @@ // Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs -use alloc::{borrow::ToOwned, boxed::Box, collections::BTreeMap, string::String, vec::Vec}; +use alloc::{ + borrow::ToOwned, + boxed::Box, + collections::BTreeMap, + string::{String, ToString}, + vec::Vec, +}; use crate::{ c_str::CStr, @@ -12,8 +18,9 @@ use crate::{ }; use super::{ + access::accessible, debug::_r_debug, - linker::{Linker, DSO}, + linker::{Linker, DSO, PATH_SEP}, tcb::Tcb, }; use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR}; @@ -116,9 +123,41 @@ unsafe fn adjust_stack(sp: &'static mut Stack) { break; } } - sp.argc -= 1; } + +fn resolve_path_name( + name_or_path: &str, + envs: &BTreeMap<String, String>, +) -> Option<(String, String)> { + if accessible(name_or_path, unistd::F_OK) == 0 { + return Some(( + name_or_path.to_string(), + name_or_path + .split("/") + .collect::<Vec<&str>>() + .last() + .unwrap() + .to_string(), + )); + } + if name_or_path.split("/").collect::<Vec<&str>>().len() != 1 { + return None; + } + + let env_path = envs.get("PATH")?; + for part in env_path.split(PATH_SEP) { + let path = if part.is_empty() { + format!("./{}", name_or_path) + } else { + format!("{}/{}", part, name_or_path) + }; + if accessible(&path, unistd::F_OK) == 0 { + return Some((path.to_string(), name_or_path.to_string())); + } + } + None +} #[no_mangle] pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize { // First thing we initialize the mspace @@ -149,7 +188,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> None => "/lib".to_owned(), }; - let path = if is_manual { + let name_or_path = if is_manual { // ld.so is run directly by user and not via execve() or similar systemcall println!("argv: {:#?}", argv); println!("envs: {:#?}", envs); @@ -161,13 +200,23 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> loop {} } unsafe { adjust_stack(sp) }; - &argv[1] + argv[1].to_string() } else { - &argv[0] + argv[0].to_string() }; - // if we are not running in manual mode, then the main program is already - // loaded by the linux kernel and we want to use it. on redox, we treat it - // the same. + + let (path, name) = match resolve_path_name(&name_or_path, &envs) { + Some((p, n)) => (p, n), + None => { + eprintln!("ld.so: failed to locate '{}'", name_or_path); + unistd::_exit(1); + loop {} + } + }; + + // 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; if !is_manual && cfg!(not(target_os = "redox")) { -- GitLab