Skip to content
Snippets Groups Projects
Commit cc305fc5 authored by Ahmed Abd El Mawgood's avatar Ahmed Abd El Mawgood
Browse files

Use Kernel mapped binaries when available.

At least in linux kernel, assuming that a.out is an elf that is linked
against relibc's own ld.so. When a user attempts `./a.out`, Linux kernel
will map `./a.out`, then map `ld.so` and jump into ld.so entry point.
In relibc ld.so will simply ignore the kernel mapped a.out and create
its own mapping. This patch forces relic ld.so to use the already mapped
`a.out` when ever possible. This would normally have slight performance
improvement (especially that currently relibc doesn't map a.out but
instead copy the data into empty mmaped memory).

The real motivation behind this patch is while impelemnting Runtime
linker debugging protocol for relibc. part of the protocol is ld.so
inseting address of some ld.so managed data structure into .dynamic
seciton of a.out then the debugger would check it there. The thing is
that debuggers have information about the kernel loaded ./a.out and they
check that one specifically which is in our case totally ignored by
relibc.
parent 701e64b3
No related branches found
No related tags found
No related merge requests found
...@@ -66,7 +66,7 @@ pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c ...@@ -66,7 +66,7 @@ pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c
} }
} }
match linker.link(None) { match linker.link(None, None) {
Ok(ok) => (), Ok(ok) => (),
Err(err) => { Err(err) => {
eprintln!("dlopen: failed to link '{}': {}", filename, err); eprintln!("dlopen: failed to link '{}': {}", filename, err);
......
...@@ -29,6 +29,12 @@ const PATH_SEP: char = ';'; ...@@ -29,6 +29,12 @@ const PATH_SEP: char = ';';
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
const PATH_SEP: char = ':'; const PATH_SEP: char = ':';
pub struct DSO {
pub name: String,
pub base_addr: usize,
pub entry_point: usize,
}
pub struct Linker { pub struct Linker {
// Used by load // Used by load
/// Library path to search when loading library by name /// Library path to search when loading library by name
...@@ -190,7 +196,7 @@ impl Linker { ...@@ -190,7 +196,7 @@ impl Linker {
} }
} }
pub fn link(&mut self, primary_opt: Option<&str>) -> Result<Option<usize>> { pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> {
let elfs = { let elfs = {
let mut elfs = BTreeMap::new(); let mut elfs = BTreeMap::new();
for (name, data) in self.objects.iter() { for (name, data) in self.objects.iter() {
...@@ -262,22 +268,41 @@ impl Linker { ...@@ -262,22 +268,41 @@ impl Linker {
// Allocate memory // Allocate memory
let mmap = unsafe { let mmap = unsafe {
let size = bounds.1 /* - bounds.0 */; let size = bounds.1 /* - bounds.0 */;
let ptr = sys_mman::mmap( let same_elf = if let Some(prog) = dso.as_ref() {
ptr::null_mut(), if prog.name == *elf_name {
size, true
//TODO: Make it possible to not specify PROT_EXEC on Redox } else {
sys_mman::PROT_READ | sys_mman::PROT_WRITE, false
sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE, }
-1, } else {
0, false
); };
if ptr as usize == !0 if same_elf {
/* MAP_FAILED */ let addr = dso.as_ref().unwrap().base_addr;
{ sys_mman::mprotect(
return Err(Error::Malformed(format!("failed to map {}", elf_name))); addr as *mut c_void,
size,
sys_mman::PROT_READ | sys_mman::PROT_WRITE,
);
slice::from_raw_parts_mut(addr as *mut u8, size)
} else {
let ptr = sys_mman::mmap(
ptr::null_mut(),
size,
//TODO: Make it possible to not specify PROT_EXEC on Redox
sys_mman::PROT_READ | sys_mman::PROT_WRITE,
sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE,
-1,
0,
);
if ptr as usize == !0
/* MAP_FAILED */
{
return Err(Error::Malformed(format!("failed to map {}", elf_name)));
}
ptr::write_bytes(ptr as *mut u8, 0, size);
slice::from_raw_parts_mut(ptr as *mut u8, size)
} }
ptr::write_bytes(ptr as *mut u8, 0, size);
slice::from_raw_parts_mut(ptr as *mut u8, size)
}; };
if self.verbose { if self.verbose {
println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len()); println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len());
...@@ -308,6 +333,18 @@ impl Linker { ...@@ -308,6 +333,18 @@ impl Linker {
}); });
let mut tls_ranges = BTreeMap::new(); let mut tls_ranges = BTreeMap::new();
for (elf_name, elf) in elfs.iter() { for (elf_name, elf) in elfs.iter() {
let same_elf = if let Some(prog) = dso.as_ref() {
if prog.name == *elf_name {
true
} else {
false
}
} else {
false
};
if same_elf {
continue;
}
let object = match self.objects.get(*elf_name) { let object = match self.objects.get(*elf_name) {
Some(some) => some, Some(some) => some,
None => continue, None => continue,
......
...@@ -6,8 +6,11 @@ use crate::{ ...@@ -6,8 +6,11 @@ use crate::{
c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex, c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex,
}; };
use super::{linker::Linker, tcb::Tcb}; use super::{
use crate::header::sys_auxv::AT_ENTRY; linker::{Linker, DSO},
tcb::Tcb,
};
use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR};
unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) { unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
//traverse the stack and collect argument vector //traverse the stack and collect argument vector
...@@ -149,7 +152,26 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> ...@@ -149,7 +152,26 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
} else { } else {
&argv[0] &argv[0]
}; };
// if we are not running in manual mode, then the main
// program is already loaded by the kernel and we want
// to use it.
let program = {
let mut pr = None;
if !is_manual {
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);
}
}
pr
};
let mut linker = Linker::new(library_path, false); let mut linker = Linker::new(library_path, false);
match linker.load(&path, &path) { match linker.load(&path, &path) {
Ok(()) => (), Ok(()) => (),
...@@ -160,7 +182,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> ...@@ -160,7 +182,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
} }
} }
let entry = match linker.link(Some(&path)) { let entry = match linker.link(Some(&path), program) {
Ok(ok) => match ok { Ok(ok) => match ok {
Some(some) => some, Some(some) => some,
None => { None => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment