Merge branch 'linux-ld' of gitlab.redox-os.org:oddcoder/relibc
This commit is contained in:
@@ -2,7 +2,33 @@
|
||||
|
||||
use crate::platform::types::*;
|
||||
|
||||
pub const AT_HWCAP: usize = 16;
|
||||
pub const AT_NULL: usize = 0; /* End of vector */
|
||||
pub const AT_IGNORE: usize = 1; /* Entry should be ignored */
|
||||
pub const AT_EXECFD: usize = 2; /* File descriptor of program */
|
||||
pub const AT_PHDR: usize = 3; /* Program headers for program */
|
||||
pub const AT_PHENT: usize = 4; /* Size of program header entry */
|
||||
pub const AT_PHNUM: usize = 5; /* Number of program headers */
|
||||
pub const AT_PAGESZ: usize = 6; /* System page size */
|
||||
pub const AT_BASE: usize = 7; /* Base address of interpreter */
|
||||
pub const AT_FLAGS: usize = 8; /* Flags */
|
||||
pub const AT_ENTRY: usize = 9; /* Entry point of program */
|
||||
pub const AT_NOTELF: usize = 10; /* Program is not ELF */
|
||||
pub const AT_UID: usize = 11; /* Real uid */
|
||||
pub const AT_EUID: usize = 12; /* Effective uid */
|
||||
pub const AT_GID: usize = 13; /* Real gid */
|
||||
pub const AT_EGID: usize = 14; /* Effective gid */
|
||||
pub const AT_CLKTCK: usize = 17; /* Frequency of times() */
|
||||
pub const AT_PLATFORM: usize = 15; /* String identifying platform. */
|
||||
pub const AT_HWCAP: usize = 16; /* Machine-dependent hints about */
|
||||
pub const AT_FPUCW: usize = 18; /* Used FPU control word. */
|
||||
pub const AT_DCACHEBSIZE: usize = 19; /* Data cache block size. */
|
||||
pub const AT_ICACHEBSIZE: usize = 20; /* Instruction cache block size. */
|
||||
pub const AT_UCACHEBSIZE: usize = 21; /* Unified cache block size. */
|
||||
pub const AT_IGNOREPPC: usize = 22; /* Entry should be ignored. */
|
||||
pub const AT_BASE_PLATFORM: usize = 24; /* String identifying real platforms.*/
|
||||
pub const AT_RANDOM: usize = 25; /* Address of 16 random bytes. */
|
||||
pub const AT_HWCAP2: usize = 26; /* More machine-dependent hints about*/
|
||||
pub const AT_EXECFN: usize = 31; /* Filename of executable. */
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getauxval(_t: c_ulong) -> c_ulong {
|
||||
|
||||
+57
-45
@@ -41,21 +41,24 @@ pub struct Linker {
|
||||
pub globals: BTreeMap<String, usize>,
|
||||
/// Loaded library in-memory data
|
||||
mmaps: BTreeMap<String, &'static mut [u8]>,
|
||||
verbose: bool
|
||||
}
|
||||
|
||||
impl Linker {
|
||||
pub fn new(library_path: &str) -> Self {
|
||||
pub fn new(library_path: &str, verbose: bool) -> Self {
|
||||
Self {
|
||||
library_path: library_path.to_string(),
|
||||
objects: BTreeMap::new(),
|
||||
globals: BTreeMap::new(),
|
||||
mmaps: BTreeMap::new(),
|
||||
verbose: verbose
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
|
||||
println!("load {}: {}", name, path);
|
||||
|
||||
if self.verbose {
|
||||
println!("load {}: {}", name, path);
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
|
||||
let path_c = CString::new(path)
|
||||
@@ -102,9 +105,9 @@ impl Linker {
|
||||
} else {
|
||||
format!("{}/{}", part, name)
|
||||
};
|
||||
|
||||
println!("check {}", path);
|
||||
|
||||
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))
|
||||
@@ -140,8 +143,9 @@ impl Linker {
|
||||
let mut tls_primary = 0;
|
||||
let mut tls_size = 0;
|
||||
for (elf_name, elf) in elfs.iter() {
|
||||
println!("map {}", elf_name);
|
||||
|
||||
if self.verbose {
|
||||
println!("map {}", elf_name);
|
||||
}
|
||||
let object = match self.objects.get(*elf_name) {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
@@ -158,8 +162,9 @@ impl Linker {
|
||||
|
||||
match ph.p_type {
|
||||
program_header::PT_LOAD => {
|
||||
println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
|
||||
|
||||
if self.verbose {
|
||||
println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
|
||||
}
|
||||
if let Some(ref mut bounds) = bounds_opt {
|
||||
if vaddr < bounds.0 {
|
||||
bounds.0 = vaddr;
|
||||
@@ -172,7 +177,9 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
program_header::PT_TLS => {
|
||||
println!(" load tls {:#x}: {:x?}", vsize, ph);
|
||||
if self.verbose{
|
||||
println!(" load tls {:#x}: {:x?}", vsize, ph);
|
||||
}
|
||||
tls_size += vsize;
|
||||
if Some(*elf_name) == primary_opt {
|
||||
tls_primary += vsize;
|
||||
@@ -186,8 +193,9 @@ impl Linker {
|
||||
None => continue,
|
||||
}
|
||||
};
|
||||
println!(" bounds {:#x}, {:#x}", bounds.0, bounds.1);
|
||||
|
||||
if self.verbose {
|
||||
println!(" bounds {:#x}, {:#x}", bounds.0, bounds.1);
|
||||
}
|
||||
// Allocate memory
|
||||
let mmap = unsafe {
|
||||
let size = bounds.1 /* - bounds.0 */;
|
||||
@@ -208,8 +216,9 @@ impl Linker {
|
||||
ptr::write_bytes(ptr as *mut u8, 0, size);
|
||||
slice::from_raw_parts_mut(ptr as *mut u8, size)
|
||||
};
|
||||
println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len());
|
||||
|
||||
if self.verbose {
|
||||
println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len());
|
||||
}
|
||||
// Locate all globals
|
||||
for sym in elf.dynsyms.iter() {
|
||||
if sym.st_bind() == sym::STB_GLOBAL && sym.st_value != 0 {
|
||||
@@ -231,8 +240,9 @@ impl Linker {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
println!("tcb {:x?}", tcb_opt);
|
||||
|
||||
if self.verbose{
|
||||
println!("tcb {:x?}", tcb_opt);
|
||||
}
|
||||
// Copy data
|
||||
let mut tls_offset = tls_primary;
|
||||
let mut tcb_masters = Vec::new();
|
||||
@@ -253,9 +263,9 @@ impl Linker {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
println!("load {}", elf_name);
|
||||
|
||||
if self.verbose {
|
||||
println!("load {}", elf_name);
|
||||
}
|
||||
// Copy data
|
||||
for ph in elf.program_headers.iter() {
|
||||
let voff = ph.p_vaddr as usize % PAGE_SIZE;
|
||||
@@ -289,15 +299,15 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!(
|
||||
" copy {:#x}, {:#x}: {:#x}, {:#x}",
|
||||
vaddr,
|
||||
vsize,
|
||||
voff,
|
||||
obj_data.len()
|
||||
);
|
||||
|
||||
if self.verbose {
|
||||
println!(
|
||||
" copy {:#x}, {:#x}: {:#x}, {:#x}",
|
||||
vaddr,
|
||||
vsize,
|
||||
voff,
|
||||
obj_data.len()
|
||||
);
|
||||
}
|
||||
mmap_data.copy_from_slice(obj_data);
|
||||
}
|
||||
program_header::PT_TLS => {
|
||||
@@ -312,12 +322,12 @@ impl Linker {
|
||||
len: ph.p_filesz as usize,
|
||||
offset: tls_size - valign,
|
||||
};
|
||||
|
||||
println!(
|
||||
" tls master {:p}, {:#x}: {:#x}, {:#x}",
|
||||
tcb_master.ptr, tcb_master.len, tcb_master.offset, valign,
|
||||
);
|
||||
|
||||
if self.verbose {
|
||||
println!(
|
||||
" tls master {:p}, {:#x}: {:#x}, {:#x}",
|
||||
tcb_master.ptr, tcb_master.len, tcb_master.offset, valign,
|
||||
);
|
||||
}
|
||||
if Some(*elf_name) == primary_opt {
|
||||
tls_ranges.insert(elf_name.to_string(), (0, tcb_master.range()));
|
||||
tcb_masters[0] = tcb_master;
|
||||
@@ -350,9 +360,9 @@ impl Linker {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
println!("link {}", elf_name);
|
||||
|
||||
if self.verbose {
|
||||
println!("link {}", elf_name);
|
||||
}
|
||||
// Relocate
|
||||
for rel in elf
|
||||
.dynrelas
|
||||
@@ -461,8 +471,9 @@ impl Linker {
|
||||
|
||||
let res = unsafe {
|
||||
let ptr = mmap.as_mut_ptr().add(vaddr);
|
||||
println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
|
||||
if self.verbose {
|
||||
println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
}
|
||||
sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
|
||||
};
|
||||
|
||||
@@ -487,9 +498,9 @@ impl Linker {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
println!("entry {}", elf_name);
|
||||
|
||||
if self.verbose {
|
||||
println!("entry {}", elf_name);
|
||||
}
|
||||
if Some(*elf_name) == primary_opt {
|
||||
entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize);
|
||||
}
|
||||
@@ -550,8 +561,9 @@ impl Linker {
|
||||
|
||||
let res = unsafe {
|
||||
let ptr = mmap.as_mut_ptr().add(vaddr);
|
||||
println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
|
||||
if self.verbose {
|
||||
println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
}
|
||||
sys_mman::mprotect(ptr as *mut c_void, vsize, prot)
|
||||
};
|
||||
|
||||
|
||||
@@ -8,12 +8,17 @@
|
||||
pub unsafe extern "C" fn _start() {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
asm!("
|
||||
# rsi = _start + 5
|
||||
call next
|
||||
next: pop rsi
|
||||
|
||||
# Save original stack and align stack to 16 bytes
|
||||
mov rbp, rsp
|
||||
and rsp, 0xFFFFFFFFFFFFFFF0
|
||||
|
||||
# Call ld_so_start(stack)
|
||||
# Call ld_so_start(stack, entry)
|
||||
mov rdi, rbp
|
||||
sub rsi, 5
|
||||
call relibc_ld_so_start
|
||||
|
||||
# Restore original stack, clear registers, and jump to new start function
|
||||
|
||||
+135
-80
@@ -1,105 +1,159 @@
|
||||
// Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, collections::BTreeMap, string::String, vec::Vec};
|
||||
|
||||
use crate::{c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex};
|
||||
use crate::{
|
||||
c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex,
|
||||
};
|
||||
|
||||
use super::linker::Linker;
|
||||
use super::tcb::Tcb;
|
||||
use super::{linker::Linker, tcb::Tcb};
|
||||
use crate::header::sys_auxv::AT_ENTRY;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
|
||||
if sp.argc < 2 {
|
||||
eprintln!("ld.so [executable] [arguments...]");
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
}
|
||||
|
||||
// Some variables that will be overridden by environment and auxiliary vectors
|
||||
let mut library_path = "/lib";
|
||||
//let mut page_size = 4096;
|
||||
|
||||
// Pop the first argument (path to ld_so), and get the path of the program
|
||||
let path_c = unsafe {
|
||||
let mut argv = sp.argv() as *mut usize;
|
||||
|
||||
// Move arguments
|
||||
loop {
|
||||
let next_argv = argv.add(1);
|
||||
let arg = *next_argv;
|
||||
*argv = arg;
|
||||
argv = next_argv;
|
||||
if arg == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() {
|
||||
println!(" arg: '{}'", arg_str);
|
||||
unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
|
||||
//traverse the stack and collect argument vector
|
||||
let mut argv = Vec::new();
|
||||
while *ptr != 0 {
|
||||
let arg = *ptr;
|
||||
match CStr::from_ptr(arg as *const c_char).to_str() {
|
||||
Ok(arg_str) => argv.push(arg_str.to_owned()),
|
||||
_ => {
|
||||
eprintln!("ld.so: failed to parse argv[{}]", argv.len());
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
return (argv, ptr);
|
||||
}
|
||||
|
||||
// Move environment
|
||||
loop {
|
||||
let next_argv = argv.add(1);
|
||||
let arg = *next_argv;
|
||||
*argv = arg;
|
||||
argv = next_argv;
|
||||
if arg == 0 {
|
||||
break;
|
||||
unsafe fn get_env(mut ptr: *const usize) -> (BTreeMap<String, String>, *const usize) {
|
||||
//traverse the stack and collect argument environment variables
|
||||
let mut envs = BTreeMap::new();
|
||||
while *ptr != 0 {
|
||||
let env = *ptr;
|
||||
if let Ok(arg_str) = CStr::from_ptr(env as *const c_char).to_str() {
|
||||
let mut parts = arg_str.splitn(2, '=');
|
||||
if let Some(key) = parts.next() {
|
||||
if let Some(value) = parts.next() {
|
||||
envs.insert(key.to_owned(), value.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
return (envs, ptr);
|
||||
}
|
||||
|
||||
if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() {
|
||||
println!(" env: '{}'", arg_str);
|
||||
unsafe fn get_auxv(mut ptr: *const usize) -> BTreeMap<usize, usize> {
|
||||
//traverse the stack and collect argument environment variables
|
||||
let mut auxv = BTreeMap::new();
|
||||
while *ptr != 0 {
|
||||
let kind = *ptr;
|
||||
ptr = ptr.add(1);
|
||||
let value = *ptr;
|
||||
ptr = ptr.add(1);
|
||||
auxv.insert(kind, value);
|
||||
}
|
||||
return auxv;
|
||||
}
|
||||
|
||||
let mut parts = arg_str.splitn(2, '=');
|
||||
if let Some(key) = parts.next() {
|
||||
if let Some(value) = parts.next() {
|
||||
if let "LD_LIBRARY_PATH" = key {
|
||||
library_path = value
|
||||
}
|
||||
unsafe fn adjust_stack(sp: &'static mut Stack) {
|
||||
let mut argv = sp.argv() as *mut usize;
|
||||
|
||||
// Move arguments
|
||||
loop {
|
||||
let next_argv = argv.add(1);
|
||||
let arg = *next_argv;
|
||||
*argv = arg;
|
||||
argv = next_argv;
|
||||
if arg == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Move environment
|
||||
loop {
|
||||
let next_argv = argv.add(1);
|
||||
let arg = *next_argv;
|
||||
*argv = arg;
|
||||
argv = next_argv;
|
||||
if arg == 0 {
|
||||
break;
|
||||
}
|
||||
if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() {
|
||||
let mut parts = arg_str.splitn(2, '=');
|
||||
if let Some(key) = parts.next() {
|
||||
if let Some(value) = parts.next() {
|
||||
if let "LD_LIBRARY_PATH" = key {
|
||||
//library_path = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move auxiliary vectors
|
||||
loop {
|
||||
let next_argv = argv.add(1);
|
||||
let kind = *next_argv;
|
||||
*argv = kind;
|
||||
argv = next_argv;
|
||||
|
||||
let next_argv = argv.add(1);
|
||||
let value = *next_argv;
|
||||
*argv = value;
|
||||
argv = next_argv;
|
||||
|
||||
if kind == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
println!(" aux: {}={:#x}", kind, value);
|
||||
//match kind {
|
||||
// 6 => page_size = value,
|
||||
// _ => (),
|
||||
//}
|
||||
// Move auxiliary vectors
|
||||
loop {
|
||||
let next_argv = argv.add(1);
|
||||
let kind = *next_argv;
|
||||
*argv = kind;
|
||||
argv = next_argv;
|
||||
let next_argv = argv.add(1);
|
||||
let value = *next_argv;
|
||||
*argv = value;
|
||||
argv = next_argv;
|
||||
if kind == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sp.argc -= 1;
|
||||
|
||||
CStr::from_ptr(sp.argv0)
|
||||
sp.argc -= 1;
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize {
|
||||
// first we get the arguments, the environment, and the auxilary vector
|
||||
let (argv, envs, auxv) = unsafe {
|
||||
let argv_start = sp.argv() as *mut usize;
|
||||
let (argv, argv_end) = get_argv(argv_start);
|
||||
let (envs, envs_end) = get_env(argv_end.add(1));
|
||||
let auxv = get_auxv(envs_end.add(1));
|
||||
(argv, envs, auxv)
|
||||
};
|
||||
|
||||
let path = match path_c.to_str() {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
eprintln!("ld.so: failed to parse path: {}", err);
|
||||
let img_entry = *auxv.get(&AT_ENTRY).unwrap_or_else(|| {
|
||||
eprintln!("failed to find AT_ENTRY");
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
});
|
||||
|
||||
// Some variables that will be overridden by environment and auxiliary vectors
|
||||
let library_path = match envs.get("LD_LIBRARY_PATH") {
|
||||
Some(lib_path) => lib_path,
|
||||
None => "/lib",
|
||||
};
|
||||
|
||||
let path;
|
||||
|
||||
let is_manual = img_entry == ld_entry;
|
||||
if is_manual {
|
||||
// ld.so is run directly by user and not via execve() or similar systemcall
|
||||
println!("argv: {:#?}", argv);
|
||||
println!("envs: {:#?}", envs);
|
||||
println!("auxv: {:#x?}", auxv);
|
||||
|
||||
if sp.argc < 2 {
|
||||
eprintln!("ld.so [executable] [arguments...]");
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
}
|
||||
};
|
||||
unsafe { adjust_stack(sp) };
|
||||
path = &argv[1];
|
||||
} else {
|
||||
path = &argv[0];
|
||||
}
|
||||
|
||||
let mut linker = Linker::new(library_path);
|
||||
let mut linker = Linker::new(library_path, is_manual);
|
||||
match linker.load(&path, &path) {
|
||||
Ok(()) => (),
|
||||
Err(err) => {
|
||||
@@ -128,7 +182,8 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
|
||||
if let Some(tcb) = unsafe { Tcb::current() } {
|
||||
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
|
||||
}
|
||||
|
||||
eprintln!("ld.so: entry '{}': {:#x}", path, entry);
|
||||
if is_manual {
|
||||
eprintln!("ld.so: entry '{}': {:#x}", path, entry);
|
||||
}
|
||||
entry
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user