Merge branch 'patch5' into 'master'
feat(ld.so): lazy binding and scopes See merge request redox-os/relibc!586
This commit is contained in:
@@ -29,14 +29,14 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
|
||||
tcb.dtv_mut().unwrap().len()
|
||||
);
|
||||
|
||||
if tcb.dtv_mut().unwrap_or_default().len() < masters.len() {
|
||||
if tcb.dtv_mut().len() < masters.len() {
|
||||
// Reallocate DTV.
|
||||
tcb.setup_dtv(masters.len());
|
||||
}
|
||||
|
||||
let dtv_index = ti.ti_module as usize - 1;
|
||||
|
||||
if tcb.dtv_mut().unwrap()[dtv_index].is_null() {
|
||||
if tcb.dtv_mut()[dtv_index].is_null() {
|
||||
// Allocate TLS for module.
|
||||
let master = &masters[dtv_index];
|
||||
|
||||
@@ -50,10 +50,10 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
|
||||
unsafe { core::ptr::copy_nonoverlapping(master.ptr, module_tls, master.len) };
|
||||
|
||||
// Set the DTV entry.
|
||||
tcb.dtv_mut().unwrap()[dtv_index] = module_tls;
|
||||
tcb.dtv_mut()[dtv_index] = module_tls;
|
||||
}
|
||||
|
||||
let mut ptr = tcb.dtv_mut().unwrap()[dtv_index];
|
||||
let mut ptr = tcb.dtv_mut()[dtv_index];
|
||||
|
||||
if ptr.is_null() {
|
||||
panic!(
|
||||
|
||||
+49
-14
@@ -3,17 +3,30 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use core::{
|
||||
ptr, str,
|
||||
ptr::{self, NonNull},
|
||||
str,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use crate::{c_str::CStr, ld_so::tcb::Tcb, platform::types::*};
|
||||
use alloc::sync::Arc;
|
||||
|
||||
pub const RTLD_LAZY: c_int = 0x0001;
|
||||
pub const RTLD_NOW: c_int = 0x0002;
|
||||
pub const RTLD_GLOBAL: c_int = 0x0100;
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
ld_so::{
|
||||
linker::{ObjectHandle, ObjectScope, Resolve},
|
||||
tcb::Tcb,
|
||||
},
|
||||
platform::types::*,
|
||||
};
|
||||
|
||||
pub const RTLD_LAZY: c_int = 1 << 0;
|
||||
pub const RTLD_NOW: c_int = 1 << 1;
|
||||
pub const RTLD_NOLOAD: c_int = 1 << 2;
|
||||
pub const RTLD_GLOBAL: c_int = 1 << 8;
|
||||
pub const RTLD_LOCAL: c_int = 0x0000;
|
||||
|
||||
pub const RTLD_DEFAULT: *mut c_void = 0 as *mut c_void; // XXX: cbindgen doesn't like ptr::null_mut()
|
||||
|
||||
static ERROR_NOT_SUPPORTED: CStr = c_str!("dlfcn not supported");
|
||||
|
||||
#[thread_local]
|
||||
@@ -42,6 +55,19 @@ pub unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut c_void {
|
||||
//TODO support all sort of flags
|
||||
let resolve = if flags & RTLD_NOW == RTLD_NOW {
|
||||
Resolve::Now
|
||||
} else {
|
||||
Resolve::Lazy
|
||||
};
|
||||
|
||||
let scope = if flags & RTLD_GLOBAL == RTLD_GLOBAL {
|
||||
ObjectScope::Global
|
||||
} else {
|
||||
ObjectScope::Local
|
||||
};
|
||||
|
||||
let noload = flags & RTLD_NOLOAD == RTLD_NOLOAD;
|
||||
|
||||
let filename = if cfilename.is_null() {
|
||||
None
|
||||
@@ -69,19 +95,19 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
|
||||
let id = match (cbs.load_library)(&mut linker, filename) {
|
||||
Err(err) => {
|
||||
match (cbs.load_library)(&mut linker, filename, resolve, scope, noload) {
|
||||
Ok(handle) => handle.as_ptr().cast_mut(),
|
||||
Err(error) => {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
return ptr::null_mut();
|
||||
ptr::null_mut()
|
||||
}
|
||||
Ok(id) => id,
|
||||
};
|
||||
|
||||
id as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void {
|
||||
let handle = ObjectHandle::from_ptr(handle);
|
||||
|
||||
if symbol.is_null() {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
return ptr::null_mut();
|
||||
@@ -89,6 +115,9 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
|
||||
|
||||
let symbol_str = unsafe { str::from_utf8_unchecked(CStr::from_ptr(symbol).to_bytes()) };
|
||||
|
||||
// FIXME(andypython): just call obj.scope.get_sym() directly or search the
|
||||
// global scope. The rest is unnecessary as Linker::get_sym() does not
|
||||
// depend on the Linker state.
|
||||
let tcb = match unsafe { Tcb::current() } {
|
||||
Some(tcb) => tcb,
|
||||
None => {
|
||||
@@ -105,7 +134,7 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
|
||||
let linker = unsafe { (&*tcb.linker_ptr).lock() };
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
match (cbs.get_sym)(&linker, handle as usize, symbol_str) {
|
||||
match (cbs.get_sym)(&linker, handle, symbol_str) {
|
||||
Some(sym) => sym,
|
||||
_ => {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
@@ -128,10 +157,16 @@ pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
return -1;
|
||||
};
|
||||
|
||||
let Some(handle) = ObjectHandle::from_ptr(handle) else {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
return -1;
|
||||
};
|
||||
|
||||
let mut linker = unsafe { (&*tcb.linker_ptr).lock() };
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
(cbs.unload)(&mut linker, handle as usize);
|
||||
(cbs.unload)(&mut linker, handle);
|
||||
0
|
||||
}
|
||||
|
||||
|
||||
+17
-10
@@ -1,12 +1,13 @@
|
||||
use super::linker::Linker;
|
||||
use super::linker::{Linker, ObjectHandle, ObjectScope, Resolve};
|
||||
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 get_sym: Box<dyn Fn(&Linker, usize, &str) -> Option<*mut c_void>>,
|
||||
pub unload: Box<dyn Fn(&mut Linker, ObjectHandle)>,
|
||||
pub load_library:
|
||||
Box<dyn Fn(&mut Linker, Option<&str>, Resolve, ObjectScope, bool) -> Result<ObjectHandle>>,
|
||||
pub get_sym: Box<dyn Fn(&Linker, Option<ObjectHandle>, &str) -> Option<*mut c_void>>,
|
||||
}
|
||||
|
||||
impl LinkerCallbacks {
|
||||
@@ -19,14 +20,20 @@ impl LinkerCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
fn unload(linker: &mut Linker, lib_id: usize) {
|
||||
linker.unload(lib_id)
|
||||
fn unload(linker: &mut Linker, handle: ObjectHandle) {
|
||||
linker.unload(handle)
|
||||
}
|
||||
|
||||
fn load_library(linker: &mut Linker, name: Option<&str>) -> Result<usize> {
|
||||
linker.load_library(name)
|
||||
fn load_library(
|
||||
linker: &mut Linker,
|
||||
name: Option<&str>,
|
||||
resolve: Resolve,
|
||||
scope: ObjectScope,
|
||||
noload: bool,
|
||||
) -> Result<ObjectHandle> {
|
||||
linker.load_library(name, resolve, scope, noload)
|
||||
}
|
||||
|
||||
fn get_sym(linker: &Linker, lib_id: usize, name: &str) -> Option<*mut c_void> {
|
||||
linker.get_sym(lib_id, name)
|
||||
fn get_sym(linker: &Linker, handle: Option<ObjectHandle>, name: &str) -> Option<*mut c_void> {
|
||||
linker.get_sym(handle, name)
|
||||
}
|
||||
|
||||
+94
-29
@@ -1,11 +1,13 @@
|
||||
//! See <https://refspecs.linuxfoundation.org/elf/elf.pdf>.
|
||||
|
||||
use super::{
|
||||
debug::{RTLDDebug, _r_debug},
|
||||
linker::Symbol,
|
||||
linker::{Scope, Symbol},
|
||||
tcb::Master,
|
||||
};
|
||||
use crate::{
|
||||
header::{errno::STR_ERROR, sys_mman},
|
||||
platform::{types::c_void, Pal, Sys, ERRNO},
|
||||
header::sys_mman,
|
||||
platform::{types::c_void, Pal, Sys},
|
||||
};
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
@@ -14,7 +16,8 @@ use alloc::{
|
||||
};
|
||||
use core::{
|
||||
mem::{size_of, transmute},
|
||||
ptr, slice,
|
||||
ptr::{self, NonNull},
|
||||
slice,
|
||||
};
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
use goblin::elf32::{
|
||||
@@ -33,12 +36,34 @@ use goblin::elf64::{
|
||||
sym,
|
||||
};
|
||||
use goblin::{
|
||||
elf::Elf,
|
||||
elf::{
|
||||
dynamic::DT_PLTGOT,
|
||||
sym::{STB_GLOBAL, STB_WEAK},
|
||||
Dynamic, Elf,
|
||||
},
|
||||
error::{Error, Result},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum SymbolBinding {
|
||||
/// Global symbols are visible to all object files being combined. One
|
||||
/// file's definition of a global symbol will satisfy another file's
|
||||
/// undefined reference to the same global symbol.
|
||||
Global = STB_GLOBAL,
|
||||
/// Weak symbols resemble global symbols, but their definitions have lower
|
||||
/// precedence.
|
||||
Weak = STB_WEAK,
|
||||
}
|
||||
|
||||
impl SymbolBinding {
|
||||
#[inline]
|
||||
pub fn is_global(&self) -> bool {
|
||||
matches!(self, Self::Global)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
@@ -56,7 +81,13 @@ pub struct DSO {
|
||||
pub fini_array: (usize, usize),
|
||||
pub tls_module_id: usize,
|
||||
pub tls_offset: usize,
|
||||
pub use_count: usize,
|
||||
|
||||
pub dynamic: Option<Dynamic>,
|
||||
pub dynsyms: Vec<goblin::elf::sym::Sym>,
|
||||
|
||||
pub scope: Scope,
|
||||
/// Position Independent Executable.
|
||||
pub pie: bool,
|
||||
}
|
||||
|
||||
impl DSO {
|
||||
@@ -88,33 +119,67 @@ impl DSO {
|
||||
elf.header.e_entry as usize
|
||||
};
|
||||
let dso = DSO {
|
||||
name: name,
|
||||
id: id,
|
||||
use_count: 1,
|
||||
dlopened: dlopened,
|
||||
entry_point: entry_point,
|
||||
name,
|
||||
id,
|
||||
dlopened,
|
||||
entry_point,
|
||||
runpath: DSO::get_runpath(&path, &elf)?,
|
||||
mmap: mmap,
|
||||
global_syms: global_syms,
|
||||
weak_syms: weak_syms,
|
||||
mmap,
|
||||
global_syms,
|
||||
weak_syms,
|
||||
dependencies: elf.libraries.iter().map(|s| s.to_string()).collect(),
|
||||
init_array: init_array,
|
||||
fini_array: fini_array,
|
||||
init_array,
|
||||
fini_array,
|
||||
tls_module_id: if tcb_master.is_some() {
|
||||
tls_module_id
|
||||
} else {
|
||||
0
|
||||
},
|
||||
tls_offset: tls_offset,
|
||||
tls_offset,
|
||||
|
||||
pie: is_pie_enabled(&elf),
|
||||
dynamic: elf.dynamic.map(|dynamic| dynamic),
|
||||
dynsyms: elf.dynsyms.iter().collect(),
|
||||
|
||||
scope: Scope::local(),
|
||||
};
|
||||
return Ok((dso, tcb_master));
|
||||
|
||||
Ok((dso, tcb_master))
|
||||
}
|
||||
|
||||
pub fn get_sym(&self, name: &str) -> Option<(Symbol, bool)> {
|
||||
/// Global Offset Table
|
||||
pub(super) fn got(&self) -> Option<NonNull<usize>> {
|
||||
let Some(dynamic) = self.dynamic.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let object_base_addr = self.mmap.as_ptr() as u64;
|
||||
|
||||
let got = if let Some(ptr) = {
|
||||
dynamic
|
||||
.dyns
|
||||
.iter()
|
||||
.find(|r#dyn| r#dyn.d_tag == DT_PLTGOT)
|
||||
.map(|r#dyn| r#dyn.d_val)
|
||||
} {
|
||||
if self.pie {
|
||||
(object_base_addr + ptr) as *mut usize
|
||||
} else {
|
||||
ptr as *mut usize
|
||||
}
|
||||
} else {
|
||||
assert_eq!(dynamic.info.jmprel, 0);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(NonNull::new(got).expect("global offset table"))
|
||||
}
|
||||
|
||||
pub fn get_sym(&self, name: &str) -> Option<(Symbol, SymbolBinding)> {
|
||||
if let Some(value) = self.global_syms.get(name) {
|
||||
Some((*value, true))
|
||||
Some((*value, SymbolBinding::Global))
|
||||
} else if let Some(value) = self.weak_syms.get(name) {
|
||||
Some((*value, false))
|
||||
Some((*value, SymbolBinding::Weak))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -147,8 +212,8 @@ impl DSO {
|
||||
Some(entry) => {
|
||||
let runpath = elf
|
||||
.dynstrtab
|
||||
.get(entry.d_val as usize)
|
||||
.ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??;
|
||||
.get_at(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)));
|
||||
}
|
||||
@@ -249,7 +314,7 @@ impl DSO {
|
||||
// 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 vaddr = (ph.p_vaddr - voff) as usize;
|
||||
let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize);
|
||||
|
||||
match ph.p_type {
|
||||
@@ -361,8 +426,8 @@ impl DSO {
|
||||
}
|
||||
let name: String;
|
||||
let value: Symbol;
|
||||
if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
|
||||
name = name_res?.to_string();
|
||||
if let Some(name_res) = elf.dynstrtab.get_at(sym.st_name) {
|
||||
name = name_res.to_string();
|
||||
value = if is_pie_enabled(elf) {
|
||||
Symbol {
|
||||
base: mmap.as_ptr() as usize,
|
||||
@@ -404,7 +469,7 @@ impl DSO {
|
||||
.iter()
|
||||
.filter(|s| s.sh_type == SHT_INIT_ARRAY || s.sh_type == SHT_FINI_ARRAY)
|
||||
{
|
||||
let addr = if is_pie_enabled(&elf) {
|
||||
let addr = if is_pie_enabled(elf) {
|
||||
mmap_addr + section.vm_range().start
|
||||
} else {
|
||||
section.vm_range().start
|
||||
@@ -422,7 +487,7 @@ impl DSO {
|
||||
impl Drop for DSO {
|
||||
fn drop(&mut self) {
|
||||
self.run_fini();
|
||||
unsafe { Sys::munmap(self.mmap.as_mut_ptr() as *mut c_void, self.mmap.len()) };
|
||||
unsafe { Sys::munmap(self.mmap.as_mut_ptr() as *mut c_void, self.mmap.len()).unwrap() };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+773
-256
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -1,5 +1,9 @@
|
||||
//! Dynamic loading and linking.
|
||||
|
||||
// FIXME(andypython): remove this when #![allow(warnings, unused_variables)] is
|
||||
// dropped from src/lib.rs.
|
||||
#![warn(warnings, unused_variables)]
|
||||
|
||||
use core::{mem, ptr};
|
||||
use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};
|
||||
|
||||
@@ -73,7 +77,7 @@ pub fn static_init(sp: &'static Stack) {
|
||||
|
||||
let page_size = Sys::getpagesize();
|
||||
let voff = ph.p_vaddr as usize % page_size;
|
||||
let vaddr = ph.p_vaddr as usize - voff;
|
||||
// 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 {
|
||||
@@ -170,7 +174,7 @@ pub unsafe fn init(sp: &'static Stack) {
|
||||
|
||||
pub unsafe fn fini() {
|
||||
if let Some(tcb) = Tcb::current() {
|
||||
if tcb.linker_ptr != ptr::null_mut() {
|
||||
if !tcb.linker_ptr.is_null() {
|
||||
let linker = (&*tcb.linker_ptr).lock();
|
||||
linker.fini();
|
||||
}
|
||||
|
||||
+2
-25
@@ -12,7 +12,6 @@ use generic_rt::ExpectTlsFree;
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
header::unistd,
|
||||
ld_so::tcb::Master,
|
||||
platform::{get_auxv, get_auxvs, types::c_char},
|
||||
start::Stack,
|
||||
sync::mutex::Mutex,
|
||||
@@ -39,7 +38,6 @@ unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
|
||||
_ => {
|
||||
eprintln!("ld.so: failed to parse argv[{}]", argv.len());
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
ptr = ptr.add(1);
|
||||
@@ -88,16 +86,6 @@ unsafe fn adjust_stack(sp: &'static mut Stack) {
|
||||
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
|
||||
@@ -152,12 +140,7 @@ fn resolve_path_name(
|
||||
|
||||
// TODO: Make unsafe
|
||||
#[no_mangle]
|
||||
pub extern "C" fn relibc_ld_so_start(
|
||||
sp: &'static mut Stack,
|
||||
ld_entry: usize,
|
||||
self_tls_start: usize,
|
||||
self_tls_end: usize,
|
||||
) -> usize {
|
||||
pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize {
|
||||
// Setup TCB for ourselves.
|
||||
unsafe {
|
||||
let tcb = Tcb::new(0).expect_notls("ld.so: failed to allocate bootstrap TCB");
|
||||
@@ -212,9 +195,6 @@ pub extern "C" fn relibc_ld_so_start(
|
||||
crate::platform::init(auxv.clone());
|
||||
}
|
||||
|
||||
// Some variables that will be overridden by environment and auxiliary vectors
|
||||
let ld_library_path = envs.get("LD_LIBRARY_PATH").map(|s| s.to_owned());
|
||||
|
||||
let name_or_path = if is_manual {
|
||||
// ld.so is run directly by user and not via execve() or similar systemcall
|
||||
println!("argv: {:#?}", argv);
|
||||
@@ -224,7 +204,6 @@ pub extern "C" fn relibc_ld_so_start(
|
||||
if sp.argc < 2 {
|
||||
eprintln!("ld.so [executable] [arguments...]");
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
}
|
||||
unsafe { adjust_stack(sp) };
|
||||
argv[1].to_string()
|
||||
@@ -232,12 +211,11 @@ pub extern "C" fn relibc_ld_so_start(
|
||||
argv[0].to_string()
|
||||
};
|
||||
|
||||
let (path, name) = match resolve_path_name(&name_or_path, &envs) {
|
||||
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 {}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -260,7 +238,6 @@ pub extern "C" fn relibc_ld_so_start(
|
||||
Err(err) => {
|
||||
eprintln!("ld.so: failed to link '{}': {}", path, err);
|
||||
unistd::_exit(1);
|
||||
loop {}
|
||||
}
|
||||
};
|
||||
if let Some(tcb) = unsafe { Tcb::current() } {
|
||||
|
||||
+9
-11
@@ -1,6 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
arch::asm,
|
||||
cell::UnsafeCell,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
@@ -10,7 +9,6 @@ use core::{
|
||||
use generic_rt::GenericTcb;
|
||||
use goblin::error::{Error, Result};
|
||||
|
||||
use super::ExpectTlsFree;
|
||||
use crate::{
|
||||
header::sys_mman,
|
||||
ld_so::linker::Linker,
|
||||
@@ -80,7 +78,7 @@ impl Tcb {
|
||||
/// `size` is the size of the TLS in bytes.
|
||||
pub unsafe fn new(size: usize) -> Result<&'static mut Self> {
|
||||
let page_size = Sys::getpagesize();
|
||||
let (abi_page, tls, tcb_page) = Self::os_new(size.next_multiple_of(page_size))?;
|
||||
let (_abi_page, tls, tcb_page) = Self::os_new(size.next_multiple_of(page_size))?;
|
||||
|
||||
let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self;
|
||||
trace!("New TCB: {:p}", tcb_ptr);
|
||||
@@ -197,7 +195,7 @@ impl Tcb {
|
||||
// XXX: [`Vec::from_raw_parts`] cannot be used here as the masters were originally
|
||||
// allocated by the ld.so allocator and that would violate that function's invariants.
|
||||
let mut masters = self.masters().unwrap().to_vec();
|
||||
masters.extend(new_masters.into_iter());
|
||||
masters.extend(new_masters);
|
||||
|
||||
self.masters_ptr = masters.as_mut_ptr();
|
||||
self.masters_len = masters.len() * mem::size_of::<Master>();
|
||||
@@ -212,8 +210,8 @@ impl Tcb {
|
||||
|
||||
pub fn setup_dtv(&mut self, n: usize) {
|
||||
if self.dtv_ptr.is_null() {
|
||||
let mut dtv = vec![ptr::null_mut(); n];
|
||||
let (ptr, len, cap) = dtv.into_raw_parts();
|
||||
let dtv = vec![ptr::null_mut(); n];
|
||||
let (ptr, len, _) = dtv.into_raw_parts();
|
||||
|
||||
self.dtv_ptr = ptr;
|
||||
self.dtv_len = len;
|
||||
@@ -222,7 +220,7 @@ impl Tcb {
|
||||
//
|
||||
// XXX: [`Vec::from_raw_parts`] cannot be used here as the DTV was originally allocated
|
||||
// by the ld.so allocator and that would violate that function's invariants.
|
||||
let mut dtv = self.dtv_mut().unwrap().to_vec();
|
||||
let mut dtv = self.dtv_mut().to_vec();
|
||||
dtv.resize(n, ptr::null_mut());
|
||||
|
||||
let (ptr, len, _) = dtv.into_raw_parts();
|
||||
@@ -231,11 +229,11 @@ impl Tcb {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dtv_mut(&mut self) -> Option<&'static mut [*mut u8]> {
|
||||
pub fn dtv_mut(&mut self) -> &'static mut [*mut u8] {
|
||||
if self.dtv_len != 0 {
|
||||
Some(unsafe { slice::from_raw_parts_mut(self.dtv_ptr, self.dtv_len) })
|
||||
unsafe { slice::from_raw_parts_mut(self.dtv_ptr, self.dtv_len) }
|
||||
} else {
|
||||
None
|
||||
&mut []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +267,7 @@ impl Tcb {
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Linux x86_64
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
unsafe fn os_arch_activate(os: &(), tls_end: usize, _tls_len: usize) {
|
||||
unsafe fn os_arch_activate(_os: &(), tls_end: usize, _tls_len: usize) {
|
||||
const ARCH_SET_FS: usize = 0x1002;
|
||||
syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end);
|
||||
}
|
||||
|
||||
+1
-1
@@ -348,4 +348,4 @@ pub unsafe fn init(auxvs: Box<[[usize; 2]]>) {
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn init(auxvs: Box<[[usize; 2]]>) {}
|
||||
pub unsafe fn init(auxvs: Box<[[usize; 2]]>) {}
|
||||
|
||||
+11
-1
@@ -159,7 +159,8 @@ EXPECT_NAMES=\
|
||||
BUILD?=.
|
||||
|
||||
DYNAMIC_ONLY_NAMES=\
|
||||
dlfcn
|
||||
dlfcn \
|
||||
dlopen_scopes
|
||||
|
||||
# Binaries that may generate varied output
|
||||
NAMES=\
|
||||
@@ -323,10 +324,19 @@ $(BUILD)/bins_dynamic/%.so: %.c $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" -shared -fpic $(FLAGS) $(DYNAMIC_FLAGS)
|
||||
|
||||
# foobar depends on foo
|
||||
$(BUILD)/bins_dynamic/libfoobar.so: libfoobar.c $(BUILD)/bins_dynamic/libfoo.so $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" -shared -fpic $(FLAGS) $(DYNAMIC_FLAGS) -L $(BUILD)/bins_dynamic -lfoo
|
||||
|
||||
$(BUILD)/bins_dynamic/dlfcn: dlfcn.c $(BUILD)/bins_dynamic/sharedlib.so $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
|
||||
|
||||
$(BUILD)/bins_dynamic/dlopen_scopes: dlopen_scopes.c $(BUILD)/bins_dynamic/libfoobar.so $(BUILD)/bins_dynamic/libfoo.so $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
|
||||
|
||||
$(BUILD)/bins_dynamic/%: %.c $(DEPS)
|
||||
mkdir -p "$$(dirname "$@")"
|
||||
$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
|
||||
|
||||
+41
-30
@@ -1,18 +1,16 @@
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define SHARED_LIB "sharedlib.so"
|
||||
|
||||
int add(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
int add(int a, int b) { return a + b; }
|
||||
|
||||
void test_dlopen_null()
|
||||
{
|
||||
void* handle = dlopen(NULL, RTLD_LAZY);
|
||||
void test_dlopen_null() {
|
||||
void *handle = dlopen(NULL, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
printf("dlopen(NULL) failed\n");
|
||||
printf("dlopen(NULL) failed: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -20,7 +18,7 @@ void test_dlopen_null()
|
||||
*(void **)(&f) = dlsym(handle, "add");
|
||||
|
||||
if (!f) {
|
||||
printf("dlsym(handle, add) failed\n");
|
||||
printf("dlsym(handle, add) failed: %s\n", dlerror());
|
||||
exit(2);
|
||||
}
|
||||
int a = 22;
|
||||
@@ -29,15 +27,14 @@ void test_dlopen_null()
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
void test_dlopen_libc()
|
||||
{
|
||||
void* handle = dlopen("libc.so.6", RTLD_LAZY);
|
||||
void test_dlopen_libc() {
|
||||
void *handle = dlopen("libc.so.6", RTLD_LAZY);
|
||||
if (!handle) {
|
||||
printf("dlopen(libc.so.6) failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int (*f)(const char*);
|
||||
|
||||
int (*f)(const char *);
|
||||
*(void **)(&f) = dlsym(handle, "puts");
|
||||
|
||||
if (!f) {
|
||||
@@ -48,10 +45,8 @@ void test_dlopen_libc()
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
|
||||
void test_dlsym_function()
|
||||
{
|
||||
void* handle = dlopen("sharedlib.so", RTLD_LAZY);
|
||||
void test_dlsym_function() {
|
||||
void *handle = dlopen(SHARED_LIB, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
printf("dlopen(sharedlib.so) failed\n");
|
||||
exit(1);
|
||||
@@ -68,14 +63,13 @@ void test_dlsym_function()
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
void test_dlsym_global_var()
|
||||
{
|
||||
void* handle = dlopen("sharedlib.so", RTLD_LAZY);
|
||||
void test_dlsym_global_var() {
|
||||
void *handle = dlopen(SHARED_LIB, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
printf("dlopen(sharedlib.so) failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int* global_var = dlsym(handle, "global_var");
|
||||
int *global_var = dlsym(handle, "global_var");
|
||||
if (!global_var) {
|
||||
printf("dlsym(handle, global_var) failed\n");
|
||||
exit(2);
|
||||
@@ -84,14 +78,13 @@ void test_dlsym_global_var()
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
void test_dlsym_tls_var()
|
||||
{
|
||||
void* handle = dlopen("sharedlib.so", RTLD_LAZY);
|
||||
void test_dlsym_tls_var() {
|
||||
void *handle = dlopen(SHARED_LIB, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
printf("dlopen(sharedlib.so) failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int* tls_var = dlsym(handle, "tls_var");
|
||||
int *tls_var = dlsym(handle, "tls_var");
|
||||
if (!tls_var) {
|
||||
printf("dlsym(handle, tls_var) failed\n");
|
||||
exit(2);
|
||||
@@ -100,12 +93,30 @@ void test_dlsym_tls_var()
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
void test_dlunload(void) {
|
||||
void *handle = dlopen(SHARED_LIB, RTLD_LAZY | RTLD_LOCAL);
|
||||
void *handle2 = dlopen(SHARED_LIB, RTLD_LAZY | RTLD_LOCAL);
|
||||
assert(handle == handle2 && handle);
|
||||
assert(!dlclose(handle));
|
||||
void *handle3 = dlopen(SHARED_LIB, RTLD_LAZY | RTLD_NOLOAD);
|
||||
assert(handle3 == handle2);
|
||||
assert(!dlclose(handle3));
|
||||
assert(!dlclose(handle2));
|
||||
void *handle4 = dlopen(SHARED_LIB, RTLD_LAZY | RTLD_NOLOAD);
|
||||
assert(handle4 == NULL);
|
||||
|
||||
void *handle5 = dlopen(SHARED_LIB, RTLD_LAZY | RTLD_GLOBAL);
|
||||
assert(handle5);
|
||||
assert(!dlclose(handle5));
|
||||
void *handle6 = dlopen(SHARED_LIB, RTLD_LAZY | RTLD_NOLOAD);
|
||||
assert(handle6 == NULL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_dlopen_null();
|
||||
test_dlopen_libc();
|
||||
test_dlsym_function();
|
||||
test_dlsym_global_var();
|
||||
test_dlsym_tls_var();
|
||||
test_dlunload();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void) {
|
||||
void *handle = dlopen("libfoobar.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
printf("dlopen(libfoobar.so): %s\n", dlerror());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
assert(dlsym(handle, "BAR") != NULL);
|
||||
assert(dlsym(handle, "FOO") != NULL);
|
||||
// not in the global scope
|
||||
assert(dlsym(RTLD_DEFAULT, "BAR") == NULL);
|
||||
assert(dlsym(RTLD_DEFAULT, "FOO") == NULL);
|
||||
|
||||
void *self = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!self) {
|
||||
printf("dlopen(NULL): %s\n", dlerror());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
assert(dlsym(self, "FOO") == NULL);
|
||||
assert(dlsym(self, "BAR") == NULL);
|
||||
|
||||
assert(dlclose(self) == 0);
|
||||
|
||||
// Promote the library to the global scope.
|
||||
assert(dlopen("libfoobar.so", /* RTLD_NOLOAD |*/ RTLD_NOW | RTLD_GLOBAL));
|
||||
|
||||
assert(dlsym(RTLD_DEFAULT, "FOO") != NULL);
|
||||
assert(dlsym(RTLD_DEFAULT, "BAR") != NULL);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
char *FOO = "foo";
|
||||
|
||||
void a() {}
|
||||
@@ -0,0 +1,4 @@
|
||||
char *BAR = "bar";
|
||||
|
||||
void a();
|
||||
void b() { a(); }
|
||||
Reference in New Issue
Block a user