feat(ld.so): switch to object crate
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Generated
+1
@@ -277,6 +277,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "git+https://gitlab.redox-os.org/andypython/object#7270e3f0d06e5ef4c2b80abc6166d31f4ddf4fea"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ generic-rt = { path = "generic-rt" }
|
||||
chrono-tz = {version = "0.10", default-features = false}
|
||||
chrono = {version = "0.4", default-features = false, features = ["alloc"]}
|
||||
libm = "0.2"
|
||||
object = { version = "0.36.7", path = "../object", default-features = false, features = ["elf", "read_core"] }
|
||||
object = { version = "0.36.7", git = "https://gitlab.redox-os.org/andypython/object", default-features = false, features = ["elf", "read_core"] }
|
||||
|
||||
[dependencies.dlmalloc]
|
||||
path = "dlmalloc-rs"
|
||||
|
||||
@@ -15,6 +15,8 @@ CARGOFLAGS+=--target=$(TARGET)
|
||||
TARGET_HEADERS?=$(BUILD)/include
|
||||
export CFLAGS=-I$(TARGET_HEADERS)
|
||||
|
||||
PROFILE?=release
|
||||
|
||||
HEADERS_UNPARSED=$(shell find src/header -mindepth 1 -maxdepth 1 -type d -not -name "_*" -printf "%f\n")
|
||||
HEADERS_DEPS=$(shell find src/header -type f \( -name "cbindgen.toml" -o -name "*.rs" \))
|
||||
#HEADERS=$(patsubst %,%.h,$(subst _,/,$(HEADERS_UNPARSED)))
|
||||
@@ -42,7 +44,7 @@ ifeq ($(TARGET),x86_64-unknown-linux-gnu)
|
||||
export LD=x86_64-linux-gnu-ld
|
||||
export AR=x86_64-linux-gnu-ar
|
||||
export NM=x86_64-linux-gnu-nm
|
||||
export OBJCOPY=x86_64-linux-gnu-objcopy
|
||||
export OBJCOPY=objcopy
|
||||
export CPPFLAGS=
|
||||
endif
|
||||
|
||||
@@ -118,23 +120,23 @@ install-headers: headers libs
|
||||
cp -rv "$(TARGET_HEADERS)"/* "$(DESTDIR)/include"
|
||||
|
||||
libs: \
|
||||
$(BUILD)/release/libc.a \
|
||||
$(BUILD)/release/libc.so \
|
||||
$(BUILD)/release/crt0.o \
|
||||
$(BUILD)/release/crti.o \
|
||||
$(BUILD)/release/crtn.o \
|
||||
$(BUILD)/release/ld_so
|
||||
$(BUILD)/$(PROFILE)/libc.a \
|
||||
$(BUILD)/$(PROFILE)/libc.so \
|
||||
$(BUILD)/$(PROFILE)/crt0.o \
|
||||
$(BUILD)/$(PROFILE)/crti.o \
|
||||
$(BUILD)/$(PROFILE)/crtn.o \
|
||||
$(BUILD)/$(PROFILE)/ld_so
|
||||
|
||||
install-libs: headers libs
|
||||
mkdir -pv "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/release/libc.a" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/release/libc.so" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/$(PROFILE)/libc.so" "$(DESTDIR)/lib"
|
||||
ln -vnfs libc.so "$(DESTDIR)/lib/libc.so.6"
|
||||
cp -v "$(BUILD)/release/crt0.o" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib"
|
||||
ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o"
|
||||
cp -v "$(BUILD)/release/crti.o" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/release/crtn.o" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/release/ld_so" "$(DESTDIR)/lib/ld64.so.1"
|
||||
cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/$(PROFILE)/crtn.o" "$(DESTDIR)/lib"
|
||||
cp -v "$(BUILD)/$(PROFILE)/ld_so" "$(DESTDIR)/lib/ld64.so.1"
|
||||
cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
|
||||
# Empty libraries for dl, pthread, and rt
|
||||
$(AR) -rcs "$(DESTDIR)/lib/libdl.a"
|
||||
@@ -181,7 +183,7 @@ $(BUILD)/debug/libc.so: $(BUILD)/debug/librelibc.a $(BUILD)/openlibm/libopenlibm
|
||||
$(CC) -nostdlib -shared -Wl,--allow-multiple-definition -Wl,--whole-archive $^ -Wl,--no-whole-archive -Wl,-soname,libc.so.6 -lgcc -o $@
|
||||
|
||||
$(BUILD)/debug/librelibc.a: $(SRC)
|
||||
$(CARGO) rustc $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
|
||||
$(CARGO) rustc $(CARGOFLAGS) -- --emit link=$@ -g -C debug-assertions=no $(RUSTCFLAGS)
|
||||
./renamesyms.sh "$@" "$(BUILD)/debug/deps/"
|
||||
touch $@
|
||||
|
||||
@@ -198,7 +200,7 @@ $(BUILD)/debug/crtn.o: $(SRC)
|
||||
touch $@
|
||||
|
||||
$(BUILD)/debug/ld_so.o: $(SRC)
|
||||
$(CARGO) rustc --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
|
||||
$(CARGO) rustc --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort -g -C debug-assertions=no $(RUSTCFLAGS)
|
||||
touch $@
|
||||
|
||||
$(BUILD)/debug/ld_so: $(BUILD)/debug/ld_so.o $(BUILD)/debug/crti.o $(BUILD)/debug/libc.a $(BUILD)/debug/crtn.o
|
||||
|
||||
+460
-188
@@ -3,18 +3,17 @@
|
||||
//! * <https://www.akkadia.org/drepper/dsohowto.pdf>
|
||||
|
||||
use object::{
|
||||
elf::{self, Dyn64, FileHeader64},
|
||||
elf::{self, Sym64},
|
||||
read::elf::{
|
||||
Dyn as _, ElfFile64, FileHeader, GnuHashTable, HashTable as SysVHashTable, ProgramHeader,
|
||||
Sym, SymbolTable, Version, VersionTable,
|
||||
Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _,
|
||||
Rela as _, Sym as _, Version, VersionTable,
|
||||
},
|
||||
Endianness, NativeEndian, Object, ObjectSection, ReadRef, SectionKind, StringTable,
|
||||
SymbolIndex,
|
||||
Endianness, NativeEndian, Object, StringTable, SymbolIndex,
|
||||
};
|
||||
|
||||
use super::{
|
||||
debug::_r_debug,
|
||||
linker::{Scope, Symbol},
|
||||
debug::{RTLDDebug, _r_debug},
|
||||
linker::{Resolve, Scope, Symbol, __plt_resolve_trampoline, GLOBAL_SCOPE},
|
||||
tcb::Master,
|
||||
};
|
||||
use crate::{
|
||||
@@ -27,69 +26,152 @@ use alloc::{
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{
|
||||
mem::transmute,
|
||||
mem::size_of,
|
||||
ptr::{self, NonNull},
|
||||
slice,
|
||||
};
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
use goblin::elf32::{
|
||||
header::ET_DYN,
|
||||
program_header,
|
||||
section_header::{SHT_FINI_ARRAY, SHT_INIT_ARRAY},
|
||||
};
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
use goblin::elf64::{
|
||||
header::ET_DYN,
|
||||
program_header,
|
||||
section_header::{SHT_FINI_ARRAY, SHT_INIT_ARRAY},
|
||||
};
|
||||
use goblin::error::{Error, Result};
|
||||
|
||||
type Dyn = Dyn64<NativeEndian>;
|
||||
|
||||
enum HashTable<'a, Elf: FileHeader> {
|
||||
Gnu(GnuHashTable<'a, Elf>),
|
||||
Sysv(SysVHashTable<'a, Elf>),
|
||||
mod shim {
|
||||
use object::{elf::*, read::elf::ElfFile64, NativeEndian};
|
||||
pub type Dyn = Dyn64<NativeEndian>;
|
||||
pub type Rel = Rel64<NativeEndian>;
|
||||
pub type Rela = Rela64<NativeEndian>;
|
||||
pub type Sym = Sym64<NativeEndian>;
|
||||
pub type FileHeader = FileHeader64<NativeEndian>;
|
||||
pub type ProgramHeader = ProgramHeader64<NativeEndian>;
|
||||
pub type ElfFile<'a> = ElfFile64<'a, NativeEndian>;
|
||||
}
|
||||
|
||||
impl<'a, Elf> HashTable<'a, Elf>
|
||||
where
|
||||
Elf: FileHeader,
|
||||
{
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub use shim::*;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
type Dyn = Dyn32<NativeEndian>;
|
||||
|
||||
enum HashTable<'a> {
|
||||
Gnu(GnuHashTable<'a, FileHeader>),
|
||||
Sysv(SysVHashTable<'a, FileHeader>),
|
||||
}
|
||||
|
||||
impl<'a> HashTable<'a> {
|
||||
/// Use the hash table to find the symbol table entry with the given name, hash, and version.
|
||||
#[inline]
|
||||
pub fn find<R: ReadRef<'a>>(
|
||||
pub fn find(
|
||||
&self,
|
||||
endian: Elf::Endian,
|
||||
name: &str,
|
||||
version: Option<&Version<'_>>,
|
||||
symbols: &SymbolTable<'a, Elf, R>,
|
||||
versions: &VersionTable<'a, Elf>,
|
||||
) -> Option<(SymbolIndex, &'a Elf::Sym)> {
|
||||
symbols: &'a [Sym],
|
||||
strings: StringTable<'a>,
|
||||
versions: &VersionTable<'a, FileHeader>,
|
||||
) -> Option<(SymbolIndex, &'a Sym)> {
|
||||
let name = name.as_bytes();
|
||||
|
||||
match self {
|
||||
Self::Gnu(hash_table) => {
|
||||
let hash = elf::gnu_hash(name);
|
||||
hash_table.find(endian, name, hash, version, symbols, versions)
|
||||
hash_table.find(
|
||||
NativeEndian,
|
||||
name,
|
||||
hash,
|
||||
version,
|
||||
symbols,
|
||||
strings,
|
||||
versions,
|
||||
)
|
||||
}
|
||||
|
||||
Self::Sysv(hash_table) => {
|
||||
let hash = elf::hash(name);
|
||||
hash_table.find(endian, name, hash, version, symbols, versions)
|
||||
hash_table.find(
|
||||
NativeEndian,
|
||||
name,
|
||||
hash,
|
||||
version,
|
||||
symbols,
|
||||
strings,
|
||||
versions,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_table_length(&self) -> usize {
|
||||
match self {
|
||||
Self::Gnu(hash_table) => hash_table
|
||||
.symbol_table_length(NativeEndian)
|
||||
.expect("empty GNU symbol hash table")
|
||||
as usize,
|
||||
Self::Sysv(hash_table) => hash_table.symbol_table_length() as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Dynamic<'a> {
|
||||
type InitFn = unsafe extern "C" fn();
|
||||
|
||||
pub(super) struct Dynamic<'data> {
|
||||
runpath: Option<String>,
|
||||
got: Option<NonNull<usize>>,
|
||||
needed: Vec<&'a str>,
|
||||
needed: Vec<&'data str>,
|
||||
pub(super) jmprel: usize,
|
||||
hash_table: HashTable<'a, FileHeader64<Endianness>>,
|
||||
pub(super) dynstrtab: StringTable<'a>,
|
||||
soname: Option<&'a str>,
|
||||
hash_table: HashTable<'data>,
|
||||
pub(super) dynstrtab: StringTable<'data>,
|
||||
soname: Option<&'data str>,
|
||||
init_array: &'data [unsafe extern "C" fn()],
|
||||
fini_array: &'data [unsafe extern "C" fn()],
|
||||
rela: &'data [Rela],
|
||||
rel: &'data [Rel],
|
||||
symbols: &'data [Sym],
|
||||
explicit_addend: bool,
|
||||
pltrelsz: usize,
|
||||
}
|
||||
|
||||
impl<'data> Dynamic<'data> {
|
||||
pub fn symbol(&self, index: SymbolIndex) -> Option<&'data Sym> {
|
||||
// Symbol table entry for index 0 is reserved.
|
||||
assert!(index != SymbolIndex(0));
|
||||
self.symbols.get(index.0)
|
||||
}
|
||||
|
||||
fn symbol_name(&self, index: SymbolIndex) -> Option<&'data str> {
|
||||
let sym = self.symbol(index)?;
|
||||
let name = sym.name(NativeEndian, self.dynstrtab).ok()?;
|
||||
Some(core::str::from_utf8(name).expect("non UTF-8 ELF symbol name"))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Dynamic<'_> {}
|
||||
unsafe impl Sync for Dynamic<'_> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Relocation {
|
||||
offset: usize,
|
||||
addend: usize,
|
||||
sym: SymbolIndex,
|
||||
kind: u32,
|
||||
}
|
||||
|
||||
impl From<&Rela> for Relocation {
|
||||
fn from(reloc: &Rela) -> Self {
|
||||
let is_mips64el = cfg!(all(target_arch = "mips64", target_endian = "little"));
|
||||
Self {
|
||||
offset: reloc.r_offset(NativeEndian) as usize,
|
||||
addend: reloc.r_addend(NativeEndian) as usize,
|
||||
sym: SymbolIndex(reloc.r_sym(NativeEndian, is_mips64el) as usize),
|
||||
kind: reloc.r_type(NativeEndian, is_mips64el),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Rel> for Relocation {
|
||||
fn from(reloc: &Rel) -> Self {
|
||||
Self {
|
||||
offset: reloc.r_offset(NativeEndian) as usize,
|
||||
addend: 0,
|
||||
sym: SymbolIndex(reloc.r_sym(NativeEndian) as usize),
|
||||
kind: reloc.r_type(NativeEndian),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -121,48 +203,30 @@ pub struct DSO {
|
||||
pub mmap: &'static [u8],
|
||||
pub global_syms: BTreeMap<String, Symbol>,
|
||||
pub weak_syms: BTreeMap<String, Symbol>,
|
||||
/// .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(super) dynamic: Dynamic<'static>,
|
||||
pub(super) symbols: SymbolTable<'static, FileHeader64<Endianness>>,
|
||||
|
||||
pub scope: Scope,
|
||||
/// Position Independent Executable.
|
||||
pub pie: bool,
|
||||
}
|
||||
|
||||
unsafe impl Send for DSO {}
|
||||
unsafe impl Sync for DSO {}
|
||||
|
||||
impl DSO {
|
||||
pub fn new(
|
||||
pub fn new<'a>(
|
||||
path: &str,
|
||||
data: &'static [u8],
|
||||
data: &'a [u8],
|
||||
base_addr: Option<usize>,
|
||||
dlopened: bool,
|
||||
id: usize,
|
||||
tls_module_id: usize,
|
||||
tls_offset: usize,
|
||||
) -> Result<(DSO, Option<Master>)> {
|
||||
let elf = ElfFile64::<object::Endianness>::parse(data).unwrap();
|
||||
) -> object::Result<(DSO, Option<Master>, Vec<ProgramHeader>)> {
|
||||
let elf = ElfFile::parse(data).unwrap();
|
||||
let (mmap, tcb_master, dynamic) =
|
||||
DSO::mmap_and_copy(path, &elf, data, base_addr, tls_offset).unwrap();
|
||||
|
||||
// dynamic.hash_table = HashTable::Gnu(
|
||||
// elf.elf_section_table()
|
||||
// .gnu_hash(Endianness::default(), data)
|
||||
// .unwrap()
|
||||
// .unwrap()
|
||||
// .0,
|
||||
// );
|
||||
|
||||
let (init_array, fini_array) = DSO::init_fini_arrays(&elf, mmap.as_ptr() as usize);
|
||||
|
||||
let name = match dynamic.soname {
|
||||
Some(soname) => soname.to_string(),
|
||||
_ => basename(path),
|
||||
@@ -176,9 +240,7 @@ impl DSO {
|
||||
} else {
|
||||
elf.entry() as usize
|
||||
};
|
||||
let endian = Endianness::default();
|
||||
let sections = elf.elf_header().sections(endian, data).unwrap();
|
||||
let symbols = sections.symbols(endian, data, elf::SHT_DYNSYM).unwrap();
|
||||
|
||||
let dso = DSO {
|
||||
name,
|
||||
id,
|
||||
@@ -187,8 +249,6 @@ impl DSO {
|
||||
mmap,
|
||||
global_syms: BTreeMap::new(),
|
||||
weak_syms: BTreeMap::new(),
|
||||
init_array,
|
||||
fini_array,
|
||||
tls_module_id: if tcb_master.is_some() {
|
||||
tls_module_id
|
||||
} else {
|
||||
@@ -197,12 +257,11 @@ impl DSO {
|
||||
tls_offset,
|
||||
|
||||
pie: is_pie_enabled(&elf),
|
||||
symbols,
|
||||
dynamic,
|
||||
scope: Scope::local(),
|
||||
};
|
||||
|
||||
Ok((dso, tcb_master))
|
||||
Ok((dso, tcb_master, elf.elf_program_headers().to_vec()))
|
||||
}
|
||||
|
||||
/// Global Offset Table
|
||||
@@ -222,15 +281,18 @@ impl DSO {
|
||||
}
|
||||
|
||||
pub fn get_sym(&self, name: &str) -> Option<(Symbol, SymbolBinding)> {
|
||||
let endian = Endianness::default();
|
||||
let (_index, sym) = self.dynamic.hash_table.find(
|
||||
endian,
|
||||
let (_, sym) = self.dynamic.hash_table.find(
|
||||
name,
|
||||
None,
|
||||
&self.symbols,
|
||||
&self.dynamic.symbols,
|
||||
self.dynamic.dynstrtab,
|
||||
&VersionTable::default(),
|
||||
)?;
|
||||
|
||||
if sym.st_shndx(NativeEndian) == elf::SHN_UNDEF {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((
|
||||
Symbol {
|
||||
base: if self.pie {
|
||||
@@ -238,8 +300,8 @@ impl DSO {
|
||||
} else {
|
||||
0
|
||||
},
|
||||
value: sym.st_value(endian) as usize,
|
||||
size: sym.st_size(endian) as usize,
|
||||
value: sym.st_value(NativeEndian) as usize,
|
||||
size: sym.st_size(NativeEndian) as usize,
|
||||
sym_type: sym.st_type(),
|
||||
},
|
||||
// TODO(andypython): move this into [`Symbol`]
|
||||
@@ -252,36 +314,24 @@ impl DSO {
|
||||
}
|
||||
|
||||
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);
|
||||
if let Some(f) = *func {
|
||||
f();
|
||||
}
|
||||
}
|
||||
for f in self.dynamic.init_array {
|
||||
unsafe { f() }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if let Some(f) = *func {
|
||||
f();
|
||||
}
|
||||
}
|
||||
for f in self.dynamic.fini_array.iter().rev() {
|
||||
unsafe { f() }
|
||||
}
|
||||
}
|
||||
|
||||
fn mmap_and_copy<'a>(
|
||||
path: &str,
|
||||
elf: &ElfFile64<'a>,
|
||||
elf: &ElfFile<'a>,
|
||||
data: &'a [u8],
|
||||
base_addr: Option<usize>,
|
||||
tls_offset: usize,
|
||||
) -> object::Result<(&'static [u8], Option<Master>, Dynamic<'a>)> {
|
||||
) -> object::Result<(&'static [u8], Option<Master>, Dynamic<'static>)> {
|
||||
let endian = elf.endian();
|
||||
trace!("# {}", path);
|
||||
// data for struct LinkMap
|
||||
@@ -296,10 +346,10 @@ impl DSO {
|
||||
.next_multiple_of(ph.p_align(endian) as usize);
|
||||
|
||||
match ph.p_type(endian) {
|
||||
program_header::PT_DYNAMIC => {
|
||||
elf::PT_DYNAMIC => {
|
||||
l_ld = ph.p_vaddr(endian);
|
||||
}
|
||||
program_header::PT_LOAD => {
|
||||
elf::PT_LOAD => {
|
||||
trace!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
|
||||
if let Some(ref mut bounds) = bounds_opt {
|
||||
if vaddr < bounds.0 {
|
||||
@@ -316,9 +366,7 @@ impl DSO {
|
||||
}
|
||||
}
|
||||
bounds_opt
|
||||
.ok_or(Error::Malformed(
|
||||
"Unable to find PT_LOAD section".to_string(),
|
||||
))
|
||||
.ok_or("Unable to find PT_LOAD section".to_string())
|
||||
.unwrap()
|
||||
};
|
||||
trace!(" bounds {:#x}, {:#x}", bounds.0, bounds.1);
|
||||
@@ -349,7 +397,7 @@ impl DSO {
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
.map_err(|e| Error::Malformed(format!("failed to map {}. errno: {}", path, e.0)))
|
||||
.map_err(|e| format!("failed to map {}. errno: {}", path, e.0))
|
||||
.unwrap();
|
||||
|
||||
if !(start as *mut c_void).is_null() {
|
||||
@@ -368,12 +416,6 @@ impl DSO {
|
||||
let skip_load_segment_copy = base_addr.is_some();
|
||||
let mut tcb_master = None;
|
||||
|
||||
let base = if is_pie_enabled(elf) {
|
||||
mmap.as_ptr() as usize
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// Copy data
|
||||
let mut dynamic = None;
|
||||
for ph in elf.elf_program_headers() {
|
||||
@@ -383,7 +425,7 @@ impl DSO {
|
||||
.next_multiple_of(ph.p_align(endian) as usize);
|
||||
|
||||
match ph.p_type(endian) {
|
||||
program_header::PT_LOAD => {
|
||||
elf::PT_LOAD => {
|
||||
if skip_load_segment_copy {
|
||||
continue;
|
||||
}
|
||||
@@ -393,13 +435,7 @@ impl DSO {
|
||||
let range = offset..(offset + size as usize);
|
||||
match data.get(range.clone()) {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
return Err(Error::Malformed(format!(
|
||||
"failed to read {:x?}",
|
||||
range
|
||||
)))
|
||||
.unwrap()
|
||||
}
|
||||
None => return Err(format!("failed to read {:x?}", range)).unwrap(),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -414,11 +450,7 @@ impl DSO {
|
||||
match mmap.get_mut(range.clone()) {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
return Err(Error::Malformed(format!(
|
||||
"failed to write {:x?}",
|
||||
range
|
||||
)))
|
||||
.unwrap();
|
||||
return Err(format!("failed to write {:x?}", range)).unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -431,7 +463,7 @@ impl DSO {
|
||||
);
|
||||
mmap_data.copy_from_slice(obj_data);
|
||||
}
|
||||
program_header::PT_TLS => {
|
||||
elf::PT_TLS => {
|
||||
let ptr = unsafe {
|
||||
if is_pie_enabled(elf) {
|
||||
mmap.as_ptr().add(ph.p_vaddr(endian) as usize)
|
||||
@@ -447,77 +479,131 @@ impl DSO {
|
||||
trace!(" tcb master {:x?}", tcb_master);
|
||||
}
|
||||
|
||||
program_header::PT_DYNAMIC => {
|
||||
dynamic = Some(ph.dynamic(endian, data).unwrap().unwrap())
|
||||
}
|
||||
elf::PT_DYNAMIC => dynamic = Some((ph, ph.dynamic(endian, data).unwrap().unwrap())),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
mmap,
|
||||
tcb_master,
|
||||
Self::parse_dynamic(path, base, endian, mmap, dynamic.unwrap())?,
|
||||
))
|
||||
let (parsed_dynamic, debug) =
|
||||
Self::parse_dynamic(path, mmap, is_pie_enabled(elf), dynamic.unwrap())?;
|
||||
|
||||
if let Some(i) = debug {
|
||||
// FIXME: cleanup
|
||||
let (ph, _) = dynamic.unwrap();
|
||||
let vaddr = ph.p_vaddr(endian) as usize;
|
||||
let bytes: [u8; size_of::<Dyn>() / 2] =
|
||||
unsafe { core::mem::transmute((&_r_debug) as *const RTLDDebug as usize) };
|
||||
let start = if is_pie_enabled(elf) {
|
||||
vaddr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
|
||||
} else {
|
||||
vaddr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
|
||||
- mmap.as_ptr().cast_mut() as usize
|
||||
};
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
bytes.as_ptr(),
|
||||
mmap.as_ptr().cast_mut().add(start),
|
||||
bytes.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((mmap, tcb_master, parsed_dynamic))
|
||||
}
|
||||
|
||||
fn parse_dynamic<'a>(
|
||||
path: &str,
|
||||
base: usize,
|
||||
endian: Endianness,
|
||||
mmap: &'static [u8],
|
||||
entries: &'a [Dyn64<Endianness>],
|
||||
) -> object::Result<Dynamic<'a>> {
|
||||
mmap: &'a [u8],
|
||||
is_pie: bool,
|
||||
(_, entries): (&ProgramHeader, &[Dyn]),
|
||||
) -> object::Result<(Dynamic<'a>, Option<usize>)> {
|
||||
let mut runpath = None;
|
||||
let mut got = None;
|
||||
let mut needed = vec![];
|
||||
let mut jmprel = None;
|
||||
let mut soname = None;
|
||||
let mut hash_table = None;
|
||||
let mut explicit_addend = None;
|
||||
let mut pltrelsz = None;
|
||||
let mut debug = None;
|
||||
let mut symtab_ptr = None;
|
||||
let (mut rel_ptr, mut rel_size) = (None, None);
|
||||
let (mut strtab_offset, mut strtab_size) = (None, None);
|
||||
let (mut init_array_ptr, mut init_array_len) = (None, None);
|
||||
let (mut fini_array_ptr, mut fini_array_len) = (None, None);
|
||||
let (mut rela_offset, mut rela_size) = (None, None);
|
||||
|
||||
for (i, entry) in entries.iter().enumerate() {
|
||||
let val = entry.d_val(endian);
|
||||
let tag = entry.d_tag(endian) as u32;
|
||||
let val = entry.d_val(NativeEndian);
|
||||
let relative_idx = val - if is_pie { 0 } else { mmap.as_ptr() as u64 };
|
||||
let ptr = (val + if is_pie { mmap.as_ptr() as u64 } else { 0 }) as *const u8;
|
||||
let tag = entry.d_tag(NativeEndian) as u32;
|
||||
|
||||
match tag {
|
||||
elf::DT_DEBUG => {
|
||||
// let vaddr = ph.p_vaddr(endian) as usize;
|
||||
// let bytes: [u8; size_of::<Dyn>() / 2] =
|
||||
// unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
|
||||
// let start = if is_pie_enabled(elf) {
|
||||
// vaddr + i * size_of::<Dyn>() + size_of::<Dyn>() / 2
|
||||
// } else {
|
||||
// vaddr + 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);
|
||||
}
|
||||
elf::DT_DEBUG => debug = Some(i),
|
||||
|
||||
// {Gnu,SysV}HashTable::parse()
|
||||
//
|
||||
// > The header does not contain a length field, and so all of
|
||||
// > `data` will be used as the hash table values. It does not
|
||||
// > matter if this is longer than needed...
|
||||
elf::DT_GNU_HASH => {
|
||||
let value = GnuHashTable::parse(endian, &mmap[val as usize..])?;
|
||||
let value = GnuHashTable::parse(NativeEndian, &mmap[relative_idx as usize..])?;
|
||||
hash_table = Some(HashTable::Gnu(value));
|
||||
}
|
||||
|
||||
// XXX: Both GNU_HASH and HASH may be present, we give priority
|
||||
// to GNU_HASH as it is significantly faster.
|
||||
elf::DT_HASH if hash_table.is_none() => {
|
||||
hash_table = Some(HashTable::Sysv(SysVHashTable::parse(
|
||||
endian,
|
||||
&mmap[val as usize..],
|
||||
)?));
|
||||
let value = SysVHashTable::parse(NativeEndian, &mmap[relative_idx as usize..])?;
|
||||
hash_table = Some(HashTable::Sysv(value));
|
||||
}
|
||||
|
||||
elf::DT_PLTGOT => {
|
||||
let ptr = NonNull::new(val as *mut usize).expect("DT_PLTGOT is NULL");
|
||||
got = Some(unsafe { ptr.byte_add(base) });
|
||||
got = Some(NonNull::new(ptr as *mut usize).expect("DT_PLTGOT is NULL"));
|
||||
}
|
||||
|
||||
elf::DT_NEEDED => needed.push(entry),
|
||||
elf::DT_JMPREL => jmprel = Some(val as usize),
|
||||
elf::DT_RUNPATH => runpath = Some(entry),
|
||||
elf::DT_STRTAB => strtab_offset = Some(val),
|
||||
elf::DT_JMPREL => jmprel = Some(ptr as usize),
|
||||
elf::DT_RUNPATH => runpath = Some(entry), // FIXME(andypython): rpath
|
||||
elf::DT_STRTAB => strtab_offset = Some(relative_idx),
|
||||
elf::DT_STRSZ => strtab_size = Some(val),
|
||||
elf::DT_SONAME => soname = Some(entry),
|
||||
|
||||
elf::DT_RELA => rela_offset = Some(ptr.cast::<Rela>()),
|
||||
elf::DT_RELASZ => rela_size = Some(val as usize / size_of::<Rela>()),
|
||||
elf::DT_RELAENT => {
|
||||
assert_eq!(val, size_of::<elf::Rela64<Endianness>>() as u64)
|
||||
}
|
||||
|
||||
elf::DT_REL => rel_ptr = Some(ptr.cast::<Rel>()),
|
||||
elf::DT_RELSZ => rel_size = Some(val as usize / size_of::<Rel>()),
|
||||
elf::DT_RELENT => {
|
||||
assert_eq!(val, size_of::<elf::Rel64<Endianness>>() as u64)
|
||||
}
|
||||
|
||||
elf::DT_PLTREL => {
|
||||
let val = val as u32;
|
||||
if val == elf::DT_RELA {
|
||||
explicit_addend = Some(true);
|
||||
} else {
|
||||
assert_eq!(val, elf::DT_REL);
|
||||
explicit_addend = Some(false);
|
||||
}
|
||||
}
|
||||
elf::DT_PLTRELSZ => pltrelsz = Some(val as usize),
|
||||
|
||||
elf::DT_INIT_ARRAY if val != 0 => init_array_ptr = Some(ptr.cast::<InitFn>()),
|
||||
elf::DT_INIT_ARRAYSZ => init_array_len = Some(val as usize / size_of::<InitFn>()),
|
||||
|
||||
elf::DT_FINI_ARRAY if val != 0 => fini_array_ptr = Some(ptr.cast::<InitFn>()),
|
||||
elf::DT_FINI_ARRAYSZ => fini_array_len = Some(val as usize / size_of::<InitFn>()),
|
||||
|
||||
elf::DT_SYMTAB => symtab_ptr = Some(ptr as *const Sym),
|
||||
elf::DT_SYMENT => {
|
||||
assert_eq!(val, size_of::<Sym64<NativeEndian>>() as u64);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -525,14 +611,24 @@ impl DSO {
|
||||
let strtab_offset = strtab_offset.expect("mandatory DT_STRTAB not present");
|
||||
let strtab_size = strtab_size.expect("mandatory DT_STRSZ not present");
|
||||
|
||||
let dynstrtab = StringTable::new(mmap, strtab_offset, strtab_offset + strtab_size);
|
||||
let dynstrtab = StringTable::new(&*mmap, strtab_offset, strtab_offset + strtab_size);
|
||||
|
||||
let get_str = |entry: &Dyn64<Endianness>| {
|
||||
let get_str = |entry: &Dyn| {
|
||||
entry
|
||||
.string(endian, dynstrtab)
|
||||
.string(NativeEndian, dynstrtab)
|
||||
.map(|bytes| core::str::from_utf8(bytes).expect("non utf-8 elf symbol name"))
|
||||
};
|
||||
|
||||
unsafe fn get_array<'a, T>(ptr: Option<*const T>, len: Option<usize>) -> &'a [T] {
|
||||
if let Some(ptr) = ptr {
|
||||
let len = len.expect("dynamic entry was present without it's corresponding size");
|
||||
core::slice::from_raw_parts(ptr, len)
|
||||
} else {
|
||||
assert!(len.is_none());
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
let needed = needed
|
||||
.into_iter()
|
||||
.map(get_str)
|
||||
@@ -550,39 +646,215 @@ impl DSO {
|
||||
let jmprel = jmprel.unwrap_or_default();
|
||||
let hash_table = hash_table.expect("either DT_GNU_HASH and/or DT_HASH mut be present");
|
||||
|
||||
Ok(Dynamic {
|
||||
runpath,
|
||||
got,
|
||||
needed,
|
||||
jmprel,
|
||||
soname,
|
||||
hash_table,
|
||||
dynstrtab,
|
||||
})
|
||||
let init_array = unsafe { get_array(init_array_ptr, init_array_len) };
|
||||
let fini_array = unsafe { get_array(fini_array_ptr, fini_array_len) };
|
||||
let rela = unsafe { get_array(rela_offset, rela_size) };
|
||||
let rel = unsafe { get_array(rel_ptr, rel_size) };
|
||||
|
||||
Ok((
|
||||
Dynamic {
|
||||
symbols: unsafe { get_array(symtab_ptr, Some(hash_table.symbol_table_length())) },
|
||||
runpath,
|
||||
got,
|
||||
needed,
|
||||
jmprel,
|
||||
soname,
|
||||
hash_table,
|
||||
dynstrtab,
|
||||
init_array,
|
||||
fini_array,
|
||||
rela,
|
||||
rel,
|
||||
explicit_addend: explicit_addend.unwrap_or_default(),
|
||||
pltrelsz: pltrelsz.unwrap_or_default(),
|
||||
},
|
||||
debug,
|
||||
))
|
||||
}
|
||||
|
||||
fn init_fini_arrays(elf: &ElfFile64, 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.sections().filter(|s| {
|
||||
matches!(
|
||||
s.kind(),
|
||||
SectionKind::Elf(SHT_INIT_ARRAY) | SectionKind::Elf(SHT_FINI_ARRAY)
|
||||
)
|
||||
}) {
|
||||
let addr = if is_pie_enabled(elf) {
|
||||
mmap_addr + section.address() as usize
|
||||
fn static_relocate(&self, reloc: Relocation) -> object::Result<()> {
|
||||
let b = self.mmap.as_ptr() as usize;
|
||||
|
||||
let sym = if reloc.sym.0 > 0 {
|
||||
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
|
||||
|
||||
GLOBAL_SCOPE
|
||||
.read()
|
||||
.get_sym(name)
|
||||
.or_else(|| self.scope.get_sym(name))
|
||||
.map(|(sym, _, obj)| (sym, obj.tls_offset))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (s, t) = sym
|
||||
.as_ref()
|
||||
.map(|(sym, t)| (sym.as_ptr() as usize, *t))
|
||||
.unwrap_or((0, 0));
|
||||
|
||||
let a = reloc.addend;
|
||||
let ptr = if self.pie {
|
||||
(b + reloc.offset) as *mut u8
|
||||
} else {
|
||||
reloc.offset as *mut u8
|
||||
};
|
||||
|
||||
let set_u64 = |value| unsafe {
|
||||
*(ptr as *mut u64) = value;
|
||||
};
|
||||
|
||||
match reloc.kind {
|
||||
elf::R_X86_64_64 => set_u64((s + a) as u64),
|
||||
elf::R_X86_64_DTPMOD64 => set_u64(self.tls_module_id as u64),
|
||||
elf::R_X86_64_DTPOFF64 => {
|
||||
if s != 0 {
|
||||
set_u64((s - b) as u64);
|
||||
} else {
|
||||
set_u64(s as u64);
|
||||
}
|
||||
}
|
||||
elf::R_X86_64_GLOB_DAT => set_u64(s as u64),
|
||||
elf::R_X86_64_RELATIVE => set_u64((b + a) as u64),
|
||||
elf::R_X86_64_TPOFF64 => {
|
||||
if reloc.sym.0 > 0 {
|
||||
let (sym, _) = sym
|
||||
.as_ref()
|
||||
.expect("R_X86_64_TPOFF64 called without valid symbol");
|
||||
set_u64((sym.value + a).wrapping_sub(t) as u64);
|
||||
} else {
|
||||
set_u64(a.wrapping_sub(t) as u64);
|
||||
}
|
||||
}
|
||||
elf::R_X86_64_IRELATIVE => unsafe {
|
||||
let f: unsafe extern "C" fn() -> u64 = core::mem::transmute(b + a);
|
||||
set_u64(f());
|
||||
},
|
||||
elf::R_X86_64_COPY => unsafe {
|
||||
let (sym, _) = sym
|
||||
.as_ref()
|
||||
.expect("R_X86_64_COPY called without valid symbol");
|
||||
ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size);
|
||||
},
|
||||
_ => unimplemented!("relocation type {:#x}", reloc.kind),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lazy_relocate(&self, resolve: Resolve) -> object::Result<()> {
|
||||
let Some(got) = self.got() else {
|
||||
assert_eq!(self.dynamic.jmprel, 0);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let object_base_addr = self.mmap.as_ptr() as usize;
|
||||
let jmprel = self.dynamic.jmprel;
|
||||
let pltrelsz = self.dynamic.pltrelsz;
|
||||
|
||||
unsafe {
|
||||
got.add(1).write(core::ptr::addr_of!(*self) as usize);
|
||||
got.add(2).write(__plt_resolve_trampoline as usize);
|
||||
}
|
||||
|
||||
let relsz = if self.dynamic.explicit_addend {
|
||||
size_of::<Rela>()
|
||||
} else {
|
||||
size_of::<Rel>()
|
||||
};
|
||||
|
||||
for addr in (jmprel..(jmprel + pltrelsz)).step_by(relsz) {
|
||||
let reloc: Relocation = if self.dynamic.explicit_addend {
|
||||
unsafe { &*(addr as *const Rela) }.into()
|
||||
} else {
|
||||
section.address() as usize
|
||||
unsafe { &*(addr as *const Rel) }.into()
|
||||
};
|
||||
if let SectionKind::Elf(SHT_INIT_ARRAY) = section.kind() {
|
||||
init_array = (addr, section.size() as usize);
|
||||
|
||||
let ptr = if self.pie {
|
||||
(object_base_addr + reloc.offset) as *mut usize
|
||||
} else {
|
||||
fini_array = (addr, section.size() as usize);
|
||||
reloc.offset as *mut usize
|
||||
};
|
||||
|
||||
match (reloc.kind, resolve) {
|
||||
(elf::R_X86_64_JUMP_SLOT, Resolve::Lazy) if self.pie => unsafe {
|
||||
*ptr += object_base_addr;
|
||||
},
|
||||
|
||||
(elf::R_X86_64_JUMP_SLOT, Resolve::Lazy) => {
|
||||
// NOP.
|
||||
}
|
||||
|
||||
(elf::R_X86_64_JUMP_SLOT, Resolve::Now) => {
|
||||
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
|
||||
|
||||
let resolved = GLOBAL_SCOPE
|
||||
.read()
|
||||
.get_sym(name)
|
||||
.or_else(|| self.scope.get_sym(name))
|
||||
.map(|(sym, _, _)| sym.as_ptr() as usize)
|
||||
.expect("unresolved symbol");
|
||||
|
||||
unsafe {
|
||||
*ptr = resolved + reloc.addend;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
unimplemented!("relocation type {:#x}", reloc.kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(init_array, fini_array)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn relocate(&self, ph: &[ProgramHeader], resolve: Resolve) -> object::Result<()> {
|
||||
self.dynamic
|
||||
.rela
|
||||
.iter()
|
||||
.try_for_each(|reloc| self.static_relocate(reloc.into()))?;
|
||||
|
||||
self.dynamic
|
||||
.rel
|
||||
.iter()
|
||||
.try_for_each(|reloc| self.static_relocate(reloc.into()))?;
|
||||
|
||||
self.lazy_relocate(resolve)?;
|
||||
|
||||
// Protect pages
|
||||
for ph in ph
|
||||
.iter()
|
||||
.filter(|ph| ph.p_type(NativeEndian) == elf::PT_LOAD)
|
||||
{
|
||||
let voff = ph.p_vaddr(NativeEndian) % ph.p_align(NativeEndian);
|
||||
let vaddr = (ph.p_vaddr(NativeEndian) - voff) as usize;
|
||||
let vsize = ((ph.p_memsz(NativeEndian) + voff) as usize)
|
||||
.next_multiple_of(ph.p_align(NativeEndian) as usize);
|
||||
|
||||
let mut prot = 0;
|
||||
if ph.p_flags(NativeEndian) & elf::PF_R == elf::PF_R {
|
||||
prot |= sys_mman::PROT_READ;
|
||||
}
|
||||
|
||||
// W ^ X. If it is executable, do not allow it to be writable, even if requested
|
||||
if ph.p_flags(NativeEndian) & elf::PF_X == elf::PF_X {
|
||||
prot |= sys_mman::PROT_EXEC;
|
||||
} else if ph.p_flags(NativeEndian) & elf::PF_W == elf::PF_W {
|
||||
prot |= sys_mman::PROT_WRITE;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = if self.pie {
|
||||
self.mmap.as_ptr().add(vaddr)
|
||||
} else {
|
||||
vaddr as *const u8
|
||||
};
|
||||
trace!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
Sys::mprotect(ptr as *mut c_void, vsize, prot).expect("[ld.so]: mprotect failed");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,8 +865,8 @@ impl Drop for DSO {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_pie_enabled(elf: &ElfFile64) -> bool {
|
||||
elf.elf_header().e_type.get(elf.endian()) == ET_DYN
|
||||
pub fn is_pie_enabled(elf: &ElfFile) -> bool {
|
||||
elf.elf_header().e_type.get(elf.endian()) == elf::ET_DYN
|
||||
}
|
||||
|
||||
fn basename(path: &str) -> String {
|
||||
|
||||
+76
-306
@@ -6,19 +6,16 @@ use alloc::{
|
||||
vec::Vec,
|
||||
};
|
||||
use object::{
|
||||
elf::Rela64,
|
||||
read::elf::{Rela, Sym},
|
||||
Endianness,
|
||||
elf,
|
||||
read::elf::{Rela as _, Sym},
|
||||
NativeEndian,
|
||||
};
|
||||
|
||||
use core::{
|
||||
cell::RefCell,
|
||||
mem::transmute,
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
|
||||
use goblin::elf::{program_header, reloc, sym::STT_TLS, Elf};
|
||||
|
||||
use crate::{
|
||||
c_str::{CStr, CString},
|
||||
error::Errno,
|
||||
@@ -27,7 +24,6 @@ use crate::{
|
||||
fcntl, sys_mman,
|
||||
unistd::F_OK,
|
||||
},
|
||||
io,
|
||||
ld_so::dso::SymbolBinding,
|
||||
platform::{
|
||||
types::{c_int, c_uint, c_void},
|
||||
@@ -40,7 +36,7 @@ use super::{
|
||||
access::accessible,
|
||||
callbacks::LinkerCallbacks,
|
||||
debug::{RTLDState, _dl_debug_state, _r_debug},
|
||||
dso::DSO,
|
||||
dso::{ProgramHeader, Rela, DSO},
|
||||
tcb::{Master, Tcb},
|
||||
PATH_SEP,
|
||||
};
|
||||
@@ -53,6 +49,8 @@ pub enum DlError {
|
||||
Malformed,
|
||||
/// Invalid DSO handle.
|
||||
InvalidHandle,
|
||||
/// Out of memory.
|
||||
Oom,
|
||||
}
|
||||
|
||||
impl DlError {
|
||||
@@ -70,31 +68,56 @@ impl DlError {
|
||||
DlError::InvalidHandle => {
|
||||
c_str!("Invalid DSO handle. Set `LD_DEBUG=all` for more information.")
|
||||
}
|
||||
|
||||
DlError::Oom => c_str!("Out of memory."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = core::result::Result<T, DlError>;
|
||||
|
||||
static GLOBAL_SCOPE: RwLock<Scope> = RwLock::new(Scope::global());
|
||||
pub(super) static GLOBAL_SCOPE: RwLock<Scope> = RwLock::new(Scope::global());
|
||||
|
||||
/// Same as [`crate::fs::File`], but does not touch [`crate::platform::ERRNO`] as the dynamic
|
||||
/// linker does not have thread-local storage.
|
||||
struct File {
|
||||
fd: c_int,
|
||||
struct MmapFile {
|
||||
fd: i32,
|
||||
ptr: *mut c_void,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn open(path: CStr, oflag: c_int) -> core::result::Result<Self, Errno> {
|
||||
Ok(Self {
|
||||
fd: Sys::open(path, oflag, 0)?,
|
||||
})
|
||||
impl MmapFile {
|
||||
fn open(path: CStr, oflag: c_int) -> core::result::Result<Self, Errno> {
|
||||
let fd = Sys::open(path, oflag, 0 /* mode */)?;
|
||||
let mut stat = crate::header::sys_stat::stat::default();
|
||||
unsafe {
|
||||
Sys::fstat(fd, &mut stat)?;
|
||||
}
|
||||
|
||||
let size = stat.st_size as usize;
|
||||
let ptr = unsafe {
|
||||
Sys::mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
sys_mman::PROT_READ,
|
||||
sys_mman::MAP_PRIVATE,
|
||||
fd,
|
||||
0,
|
||||
)
|
||||
}?;
|
||||
|
||||
Ok(Self { fd, ptr, size })
|
||||
}
|
||||
|
||||
fn data(&self) -> &[u8] {
|
||||
unsafe { core::slice::from_raw_parts(self.ptr.cast::<u8>(), self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Read for File {
|
||||
fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, io::Error> {
|
||||
Sys::read(self.fd, buf).map_err(|err| io::Error::from_raw_os_error(err.0))
|
||||
impl Drop for MmapFile {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
Sys::munmap(self.ptr, self.size).unwrap();
|
||||
Sys::close(self.fd).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +211,7 @@ impl Scope {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sym(&self, name: &str) -> Option<(Symbol, SymbolBinding, Arc<DSO>)> {
|
||||
pub(super) fn get_sym(&self, name: &str) -> Option<(Symbol, SymbolBinding, Arc<DSO>)> {
|
||||
let mut res = None;
|
||||
|
||||
let get_sym = |obj: Arc<DSO>| {
|
||||
@@ -452,7 +475,7 @@ impl Linker {
|
||||
}
|
||||
.get_sym(name)
|
||||
.map(|(symbol, _, obj)| {
|
||||
if symbol.sym_type != STT_TLS {
|
||||
if symbol.sym_type != elf::STT_TLS {
|
||||
symbol.as_ptr()
|
||||
} else {
|
||||
let mut tls_index = dl_tls_index {
|
||||
@@ -554,7 +577,7 @@ impl Linker {
|
||||
use redox_rt::signal::tmp_disable_signals;
|
||||
|
||||
let old_tcb = Tcb::current().expect("failed to get bootstrap TCB");
|
||||
let new_tcb = Tcb::new(self.tls_size).map_err(|_| DlError::Malformed)?; // This actually allocates TCB, TLS and ABI page.
|
||||
let new_tcb = Tcb::new(self.tls_size)?; // This actually allocates TCB, TLS and ABI page.
|
||||
|
||||
// Stash
|
||||
let new_tls_end = new_tcb.generic.tls_end;
|
||||
@@ -595,7 +618,7 @@ impl Linker {
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
let tcb = Tcb::new(self.tls_size).map_err(|_| DlError::Malformed)?;
|
||||
let tcb = Tcb::new(self.tls_size)?;
|
||||
|
||||
// We are now loading the main program or its dependencies. The TLS for all initially
|
||||
// loaded objects reside in the static TLS block. Depending on the architecture, the
|
||||
@@ -647,7 +670,7 @@ impl Linker {
|
||||
|
||||
// new_objects is already reversed.
|
||||
for (i, obj) in new_objects.into_iter().enumerate() {
|
||||
self.relocate(&obj, objects_data[i], resolve)?;
|
||||
obj.relocate(&objects_data[i], resolve).unwrap();
|
||||
self.run_init(&obj);
|
||||
self.register_object(obj);
|
||||
}
|
||||
@@ -663,14 +686,14 @@ impl Linker {
|
||||
self.objects.insert(obj.id, obj);
|
||||
}
|
||||
|
||||
fn load_objects_recursive(
|
||||
fn load_objects_recursive<'a>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
parent_runpath: &Option<String>,
|
||||
base_addr: Option<usize>,
|
||||
dlopened: bool,
|
||||
new_objects: &mut Vec<Arc<DSO>>,
|
||||
objects_data: &mut Vec<&[u8]>,
|
||||
objects_data: &mut Vec<Vec<ProgramHeader>>,
|
||||
tcb_masters: &mut Vec<Master>,
|
||||
// The object that caused this object to be loaded.
|
||||
dependent: Option<&mut DSO>,
|
||||
@@ -688,10 +711,11 @@ impl Linker {
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD);
|
||||
|
||||
let path = self.search_object(name, parent_runpath)?;
|
||||
let data = self.read_file(&path)?;
|
||||
let (mut obj, tcb_master) = DSO::new(
|
||||
let file = self.read_file(&path)?;
|
||||
let data = file.data();
|
||||
let (mut obj, tcb_master, elf) = DSO::new(
|
||||
&path,
|
||||
&data,
|
||||
data,
|
||||
base_addr,
|
||||
dlopened,
|
||||
self.next_object_id,
|
||||
@@ -760,7 +784,7 @@ impl Linker {
|
||||
GLOBAL_SCOPE.write().add(&obj);
|
||||
}
|
||||
|
||||
objects_data.push(data);
|
||||
objects_data.push(elf);
|
||||
new_objects.push(obj.clone());
|
||||
|
||||
Ok(obj)
|
||||
@@ -808,7 +832,7 @@ impl Linker {
|
||||
Err(DlError::NotFound)
|
||||
}
|
||||
|
||||
fn read_file(&self, path: &str) -> Result<&'static [u8]> {
|
||||
fn read_file(&self, path: &str) -> Result<MmapFile> {
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::SEARCH);
|
||||
|
||||
let path_c = CString::new(path).map_err(|err| {
|
||||
@@ -820,7 +844,7 @@ impl Linker {
|
||||
})?;
|
||||
|
||||
let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
|
||||
let file = File::open(CStr::borrow(&path_c), flags).map_err(|err| {
|
||||
let file = MmapFile::open(CStr::borrow(&path_c), flags).map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to open '{}': {}", path, err)
|
||||
}
|
||||
@@ -828,261 +852,7 @@ impl Linker {
|
||||
DlError::NotFound
|
||||
})?;
|
||||
|
||||
let mut stat = crate::header::sys_stat::stat::default();
|
||||
unsafe {
|
||||
Sys::fstat(file.fd, &mut stat).unwrap();
|
||||
}
|
||||
|
||||
let mmap_ptr = unsafe {
|
||||
Sys::mmap(
|
||||
ptr::null_mut(),
|
||||
stat.st_size as usize,
|
||||
sys_mman::PROT_READ,
|
||||
sys_mman::MAP_PRIVATE,
|
||||
file.fd,
|
||||
0,
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
Ok(unsafe { core::slice::from_raw_parts(mmap_ptr as *const u8, stat.st_size as usize) })
|
||||
}
|
||||
|
||||
/// Perform lazy relocations.
|
||||
fn lazy_relocate(&self, obj: &Arc<DSO>, elf: &Elf, resolve: Resolve) -> Result<()> {
|
||||
let Some(got) = obj.got() else { return Ok(()) };
|
||||
let object_base_addr = obj.mmap.as_ptr() as u64;
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD);
|
||||
|
||||
unsafe {
|
||||
got.add(1).write(Arc::as_ptr(obj) as usize);
|
||||
got.add(2).write(__plt_resolve_trampoline as usize);
|
||||
}
|
||||
|
||||
for rel in elf.pltrelocs.iter() {
|
||||
let ptr = if obj.pie {
|
||||
(object_base_addr + rel.r_offset) as *mut u64
|
||||
} else {
|
||||
rel.r_offset as *mut u64
|
||||
};
|
||||
|
||||
match (rel.r_type, resolve) {
|
||||
(reloc::R_X86_64_JUMP_SLOT, Resolve::Lazy) if obj.pie => unsafe {
|
||||
*ptr += object_base_addr;
|
||||
},
|
||||
|
||||
(reloc::R_X86_64_JUMP_SLOT, Resolve::Lazy) => {
|
||||
// NOP.
|
||||
}
|
||||
|
||||
(reloc::R_X86_64_JUMP_SLOT, Resolve::Now) => {
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("missing symbol for relocation {:?}", rel)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let name = elf.dynstrtab.get_at(sym.st_name).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("missing name for symbol {:?}", sym)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let resolved = GLOBAL_SCOPE
|
||||
.read()
|
||||
.get_sym(name)
|
||||
.or_else(|| obj.scope.get_sym(name))
|
||||
.map(|(sym, _, _)| sym.as_ptr())
|
||||
.expect("unresolved symbol");
|
||||
|
||||
let addend = rel.r_addend.unwrap_or(0) as u64;
|
||||
|
||||
unsafe {
|
||||
*ptr = resolved as u64 + addend;
|
||||
}
|
||||
}
|
||||
|
||||
_ => todo!("unsupported relocation type {:?}", rel.r_type),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn relocate(&self, obj: &Arc<DSO>, object_data: &[u8], resolve: Resolve) -> Result<()> {
|
||||
// Perform static relocations.
|
||||
let elf = Elf::parse(object_data).or(Err(DlError::Malformed))?;
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD); // FIXME
|
||||
|
||||
trace!("link {}", obj.name);
|
||||
|
||||
let mmap = &obj.mmap;
|
||||
let b = mmap.as_ptr() as usize;
|
||||
|
||||
// Relocate
|
||||
for rel in elf.dynrelas.iter().chain(elf.dynrels.iter()) {
|
||||
trace!(
|
||||
" rel {}: {:x?}",
|
||||
reloc::r_to_str(rel.r_type, elf.header.e_machine),
|
||||
rel
|
||||
);
|
||||
|
||||
let symbol = if rel.r_sym > 0 {
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: missing symbol for relocation {:?}", rel)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let name = elf.dynstrtab.get_at(sym.st_name).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: missing name for symbol {:?}", sym)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let symbol = GLOBAL_SCOPE
|
||||
.read()
|
||||
.get_sym(name)
|
||||
.or_else(|| obj.scope.get_sym(name))
|
||||
.map(|(sym, _, obj)| (sym, obj.tls_offset));
|
||||
|
||||
// TODO: below doesn't work because of missing __preinit_array_{start,end} and __init_array_{start,end} symbols in dynamic linked programs
|
||||
// TODO: found := symbol.is_some()
|
||||
/*
|
||||
if !found {
|
||||
return Err(Error::Malformed(format!("missing symbol for name {}", name)));
|
||||
}
|
||||
*/
|
||||
symbol
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (s, t) = symbol
|
||||
.as_ref()
|
||||
.map(|(sym, t)| (sym.as_ptr() as usize, *t))
|
||||
.unwrap_or((0, 0));
|
||||
|
||||
let a = rel.r_addend.unwrap_or(0) as usize;
|
||||
|
||||
let ptr = if obj.pie {
|
||||
(b + rel.r_offset as usize) as *mut u8
|
||||
} else {
|
||||
rel.r_offset as *mut u8
|
||||
};
|
||||
let set_u64 = |value| {
|
||||
trace!(
|
||||
" set_u64 r_type={} value={:#x} ptr={:p} base={:#x} mmap_len={:#x} a={:#x}",
|
||||
rel.r_type,
|
||||
value,
|
||||
ptr,
|
||||
b,
|
||||
mmap.len(),
|
||||
a
|
||||
);
|
||||
unsafe {
|
||||
*(ptr as *mut u64) = value;
|
||||
}
|
||||
};
|
||||
|
||||
match rel.r_type {
|
||||
reloc::R_X86_64_64 => {
|
||||
set_u64((s + a) as u64);
|
||||
}
|
||||
reloc::R_X86_64_DTPMOD64 => {
|
||||
set_u64(obj.tls_module_id as u64);
|
||||
}
|
||||
reloc::R_X86_64_DTPOFF64 => {
|
||||
if s != 0 {
|
||||
set_u64((s - b) as u64);
|
||||
} else {
|
||||
set_u64(s as u64);
|
||||
}
|
||||
}
|
||||
reloc::R_X86_64_GLOB_DAT | reloc::R_X86_64_JUMP_SLOT => {
|
||||
set_u64(s as u64);
|
||||
}
|
||||
reloc::R_X86_64_RELATIVE => {
|
||||
set_u64((b + a) as u64);
|
||||
}
|
||||
reloc::R_X86_64_TPOFF64 => {
|
||||
if rel.r_sym > 0 {
|
||||
let (sym, _) = symbol
|
||||
.as_ref()
|
||||
.expect("R_X86_64_TPOFF64 called without valid symbol");
|
||||
set_u64((sym.value + a).wrapping_sub(t) as u64);
|
||||
} else {
|
||||
set_u64(a.wrapping_sub(t) as u64);
|
||||
}
|
||||
}
|
||||
reloc::R_X86_64_IRELATIVE => unsafe {
|
||||
let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
|
||||
set_u64(f());
|
||||
},
|
||||
reloc::R_X86_64_COPY => unsafe {
|
||||
let (sym, _) = symbol
|
||||
.as_ref()
|
||||
.expect("R_X86_64_COPY called without valid symbol");
|
||||
ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size);
|
||||
},
|
||||
_ => {
|
||||
panic!(
|
||||
" {} unsupported",
|
||||
reloc::r_to_str(rel.r_type, elf.header.e_machine)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.lazy_relocate(obj, &elf, resolve)?;
|
||||
|
||||
// Protect pages
|
||||
for ph in elf
|
||||
.program_headers
|
||||
.iter()
|
||||
.filter(|ph| ph.p_type == program_header::PT_LOAD)
|
||||
{
|
||||
let voff = ph.p_vaddr % ph.p_align;
|
||||
let vaddr = (ph.p_vaddr - voff) as usize;
|
||||
let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize);
|
||||
let mut prot = 0;
|
||||
if ph.p_flags & program_header::PF_R == program_header::PF_R {
|
||||
prot |= sys_mman::PROT_READ;
|
||||
}
|
||||
|
||||
// W ^ X. If it is executable, do not allow it to be writable, even if requested
|
||||
if ph.p_flags & program_header::PF_X == program_header::PF_X {
|
||||
prot |= sys_mman::PROT_EXEC;
|
||||
} else if ph.p_flags & program_header::PF_W == program_header::PF_W {
|
||||
prot |= sys_mman::PROT_WRITE;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = if obj.pie {
|
||||
mmap.as_ptr().add(vaddr)
|
||||
} else {
|
||||
vaddr as *const u8
|
||||
};
|
||||
trace!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
Sys::mprotect(ptr as *mut c_void, vsize, prot).map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to mprotect: {}", err)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
fn run_init(&self, obj: &DSO) {
|
||||
@@ -1122,41 +892,41 @@ extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) ->
|
||||
let obj_base = obj.mmap.as_ptr() as usize;
|
||||
let jmprel = obj.dynamic.jmprel;
|
||||
|
||||
let rela = unsafe {
|
||||
&*((obj_base + jmprel) as *const Rela64<Endianness>).add(relocation_index as usize)
|
||||
};
|
||||
|
||||
let endian = Endianness::default();
|
||||
|
||||
assert_eq!(rela.r_type(endian, false), reloc::R_X86_64_JUMP_SLOT);
|
||||
let rela = unsafe { &*(jmprel as *const Rela).add(relocation_index as usize) };
|
||||
assert_eq!(rela.r_type(NativeEndian, false), elf::R_X86_64_JUMP_SLOT);
|
||||
|
||||
let sym = obj
|
||||
.symbols
|
||||
.symbol(rela.symbol(endian, false).unwrap())
|
||||
.dynamic
|
||||
.symbol(rela.symbol(NativeEndian, false).unwrap())
|
||||
.expect("symbol not found");
|
||||
assert_ne!(sym.st_name(endian), 0);
|
||||
assert_ne!(sym.st_name(NativeEndian), 0);
|
||||
|
||||
let name = core::str::from_utf8(obj.dynamic.dynstrtab.get(sym.st_name(endian)).unwrap())
|
||||
.expect("non utf8 symbol name");
|
||||
let name = core::str::from_utf8(
|
||||
obj.dynamic
|
||||
.dynstrtab
|
||||
.get(sym.st_name(NativeEndian))
|
||||
.unwrap(),
|
||||
)
|
||||
.expect("non utf8 symbol name");
|
||||
|
||||
let resolved = resolve_sym(name, &[&GLOBAL_SCOPE.read(), &obj.scope])
|
||||
.unwrap_or_else(|| panic!("symbol '{name}' not found"))
|
||||
.as_ptr();
|
||||
|
||||
trace!("@plt: {} -> *mut {:#x}", name, resolved as usize);
|
||||
|
||||
let ptr = if obj.pie {
|
||||
(obj_base as u64 + rela.r_offset(endian)) as *mut u64
|
||||
(obj_base as u64 + rela.r_offset(NativeEndian)) as *mut u64
|
||||
} else {
|
||||
rela.r_offset(endian) as *mut u64
|
||||
rela.r_offset(NativeEndian) as *mut u64
|
||||
};
|
||||
|
||||
trace!("@plt: {} -> *mut {:p}", name, ptr);
|
||||
|
||||
unsafe { *ptr = resolved as u64 }
|
||||
resolved
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __plt_resolve_trampoline() -> usize;
|
||||
pub(super) fn __plt_resolve_trampoline() -> usize;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
+40
-17
@@ -5,7 +5,11 @@
|
||||
#![warn(warnings, unused_variables)]
|
||||
|
||||
use core::{mem, ptr};
|
||||
use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};
|
||||
use object::{
|
||||
elf::{self, ProgramHeader32, ProgramHeader64},
|
||||
read::elf::ProgramHeader,
|
||||
Endianness,
|
||||
};
|
||||
|
||||
use self::tcb::{Master, Tcb};
|
||||
use crate::{
|
||||
@@ -38,6 +42,9 @@ static mut STATIC_TCB_MASTER: Master = Master {
|
||||
|
||||
#[inline(never)]
|
||||
pub fn static_init(sp: &'static Stack) {
|
||||
const SIZEOF_PHDR64: usize = mem::size_of::<ProgramHeader64<Endianness>>();
|
||||
const SIZEOF_PHDR32: usize = mem::size_of::<ProgramHeader32<Endianness>>();
|
||||
|
||||
let mut phdr_opt = None;
|
||||
let mut phent_opt = None;
|
||||
let mut phnum_opt = None;
|
||||
@@ -65,31 +72,47 @@ pub fn static_init(sp: &'static Stack) {
|
||||
|
||||
for i in 0..phnum {
|
||||
let ph_addr = phdr + phent * i;
|
||||
let ph: ProgramHeader = match phent {
|
||||
program_header32::SIZEOF_PHDR => {
|
||||
unsafe { *(ph_addr as *const program_header32::ProgramHeader) }.into()
|
||||
}
|
||||
program_header64::SIZEOF_PHDR => {
|
||||
unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into()
|
||||
}
|
||||
let endian = Endianness::default();
|
||||
let (p_align, p_filesz, p_memsz, p_type, p_vaddr) = match phent {
|
||||
SIZEOF_PHDR64 => unsafe {
|
||||
let ph = &*(ph_addr as *const ProgramHeader64<Endianness>);
|
||||
(
|
||||
ph.p_align(endian) as usize,
|
||||
ph.p_filesz(endian) as usize,
|
||||
ph.p_memsz(endian) as usize,
|
||||
ph.p_type(endian),
|
||||
ph.p_vaddr(endian) as usize,
|
||||
)
|
||||
},
|
||||
|
||||
SIZEOF_PHDR32 => unsafe {
|
||||
let ph = &*(ph_addr as *const ProgramHeader32<Endianness>);
|
||||
(
|
||||
ph.p_align(endian) as usize,
|
||||
ph.p_filesz(endian) as usize,
|
||||
ph.p_memsz(endian) as usize,
|
||||
ph.p_type(endian),
|
||||
ph.p_vaddr(endian) as usize,
|
||||
)
|
||||
},
|
||||
_ => panic_notls(format_args!("unknown AT_PHENT size {}", phent)),
|
||||
};
|
||||
|
||||
let page_size = Sys::getpagesize();
|
||||
let voff = ph.p_vaddr as usize % page_size;
|
||||
let voff = p_vaddr % page_size;
|
||||
// let vaddr = ph.p_vaddr as usize - voff;
|
||||
let vsize = ((ph.p_memsz as usize + voff + page_size - 1) / page_size) * page_size;
|
||||
let vsize = ((p_memsz + voff + page_size - 1) / page_size) * page_size;
|
||||
|
||||
if ph.p_type == program_header::PT_TLS {
|
||||
let valign = if ph.p_align > 0 {
|
||||
((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align
|
||||
if p_type == elf::PT_TLS {
|
||||
let valign = if p_align > 0 {
|
||||
((p_memsz + (p_align - 1)) / p_align) * p_align
|
||||
} else {
|
||||
ph.p_memsz
|
||||
} as usize;
|
||||
p_memsz
|
||||
};
|
||||
|
||||
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.ptr = p_vaddr as *const u8;
|
||||
STATIC_TCB_MASTER.len = p_filesz;
|
||||
STATIC_TCB_MASTER.offset = valign;
|
||||
|
||||
let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB");
|
||||
|
||||
+6
-1
@@ -26,7 +26,12 @@ use super::{
|
||||
PATH_SEP,
|
||||
};
|
||||
use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR};
|
||||
use goblin::elf::header::header64::SIZEOF_EHDR;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub const SIZEOF_EHDR: usize = 52;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub const SIZEOF_EHDR: usize = 64;
|
||||
|
||||
unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
|
||||
//traverse the stack and collect argument vector
|
||||
|
||||
+9
-8
@@ -1,4 +1,4 @@
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
mem,
|
||||
@@ -7,7 +7,6 @@ use core::{
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
use generic_rt::GenericTcb;
|
||||
use goblin::error::{Error, Result};
|
||||
|
||||
use crate::{
|
||||
header::sys_mman,
|
||||
@@ -17,6 +16,8 @@ use crate::{
|
||||
sync::{mutex::Mutex, waitval::Waitval},
|
||||
};
|
||||
|
||||
use super::linker::DlError;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Master {
|
||||
@@ -76,7 +77,7 @@ impl Tcb {
|
||||
/// Create a new TCB
|
||||
///
|
||||
/// `size` is the size of the TLS in bytes.
|
||||
pub unsafe fn new(size: usize) -> Result<&'static mut Self> {
|
||||
pub unsafe fn new(size: usize) -> Result<&'static mut Self, DlError> {
|
||||
let page_size = Sys::getpagesize();
|
||||
let (_abi_page, tls, tcb_page) = Self::os_new(size.next_multiple_of(page_size))?;
|
||||
|
||||
@@ -145,7 +146,7 @@ impl Tcb {
|
||||
}
|
||||
|
||||
/// Copy data from masters
|
||||
pub unsafe fn copy_masters(&mut self) -> Result<()> {
|
||||
pub unsafe fn copy_masters(&mut self) -> Result<(), DlError> {
|
||||
//TODO: Complain if masters or tls exist without the other
|
||||
if let Some(tls) = self.tls() {
|
||||
if let Some(masters) = self.masters() {
|
||||
@@ -175,7 +176,7 @@ impl Tcb {
|
||||
);
|
||||
tls_data.copy_from_slice(data);
|
||||
} else {
|
||||
return Err(Error::Malformed(format!("failed to copy tls master {}", i)));
|
||||
return Err(DlError::Malformed);
|
||||
}
|
||||
}
|
||||
self.num_copied_masters = masters.len();
|
||||
@@ -238,7 +239,7 @@ impl Tcb {
|
||||
}
|
||||
|
||||
/// Mapping with correct flags for TCB and TLS
|
||||
unsafe fn map(size: usize) -> Result<&'static mut [u8]> {
|
||||
unsafe fn map(size: usize) -> Result<&'static mut [u8], DlError> {
|
||||
let ptr = Sys::mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
@@ -247,7 +248,7 @@ impl Tcb {
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
.map_err(|_| Error::Malformed("failed to map tls".to_string()))?;
|
||||
.map_err(|_| DlError::Oom)?;
|
||||
|
||||
ptr::write_bytes(ptr as *mut u8, 0, size);
|
||||
Ok(slice::from_raw_parts_mut(ptr as *mut u8, size))
|
||||
@@ -257,7 +258,7 @@ impl Tcb {
|
||||
#[cfg(any(target_os = "linux", target_os = "redox"))]
|
||||
unsafe fn os_new(
|
||||
size: usize,
|
||||
) -> Result<(&'static mut [u8], &'static mut [u8], &'static mut [u8])> {
|
||||
) -> Result<(&'static mut [u8], &'static mut [u8], &'static mut [u8]), DlError> {
|
||||
let page_size = Sys::getpagesize();
|
||||
let abi_tls_tcb = Self::map(page_size + size + page_size)?;
|
||||
let (abi, tls_tcb) = abi_tls_tcb.split_at_mut(page_size);
|
||||
|
||||
+1
-1
@@ -23,6 +23,7 @@
|
||||
#![feature(lang_items)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(linkage)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(pointer_is_aligned_to)]
|
||||
#![feature(ptr_as_uninit)]
|
||||
#![feature(slice_as_chunks)]
|
||||
@@ -44,7 +45,6 @@
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
extern crate cbitset;
|
||||
extern crate goblin;
|
||||
extern crate memchr;
|
||||
extern crate posix_regex;
|
||||
extern crate rand;
|
||||
|
||||
Reference in New Issue
Block a user