Add ld_so executable

This commit is contained in:
Jeremy Soller
2019-04-13 12:17:38 -06:00
parent d5eb1e2732
commit 084b69b361
11 changed files with 640 additions and 6 deletions
Generated
+96
View File
@@ -93,6 +93,16 @@ name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "goblin"
version = "0.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.3"
@@ -106,6 +116,10 @@ dependencies = [
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ld_so"
version = "0.1.0"
[[package]]
name = "libc"
version = "0.2.51"
@@ -132,6 +146,11 @@ name = "num-traits"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "posix-regex"
version = "0.1.0"
@@ -144,11 +163,27 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ralloc"
version = "1.0.0"
@@ -226,6 +261,7 @@ dependencies = [
"cbitset 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"core_io 0.1.20181107",
"goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"posix-regex 0.1.0",
"ralloc 1.0.0",
@@ -252,6 +288,14 @@ dependencies = [
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "0.2.7"
@@ -262,11 +306,43 @@ name = "sc"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scroll"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scroll_derive"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.90"
@@ -342,6 +418,16 @@ dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
@@ -452,14 +538,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6a4013e9182f2345c6b7829b9ef6e670bce0dfca12c6f974457ed2160c2c7fe9"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
@@ -469,9 +559,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum sc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ebbb026ba4a707c25caec2db5ef59ad8b41f7ad77cad06257e06229c891f376"
"checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383"
"checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
"checksum serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "652bc323d694dc925829725ec6c890156d8e70ae5202919869cb00fe2eff3788"
"checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab"
@@ -481,6 +576,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum standalone-syn 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "115808f5187c07c23cb93eee49d542fae54c6e8285d3a24c6ff683fcde9243db"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
+6 -1
View File
@@ -8,7 +8,7 @@ name = "relibc"
crate-type = ["staticlib"]
[workspace]
members = ["src/crt0", "src/crti", "src/crtn", "cbindgen"]
members = ["src/crt0", "src/crti", "src/crtn", "src/ld_so", "cbindgen"]
exclude = ["core_io", "ralloc"]
[build-dependencies]
@@ -22,6 +22,11 @@ posix-regex = { path = "posix-regex", features = ["no_std"] }
rand = { version = "0.5.5", default-features = false }
va_list = { path = "va_list", features = ["no_std"] }
[dependencies.goblin]
version = "0.0.21"
default-features = false
features = ["elf32", "elf64", "endian_fd"]
[dependencies.ralloc]
path = "ralloc"
default-features = false
+39 -2
View File
@@ -79,7 +79,9 @@ sysroot: all
test: sysroot
$(MAKE) -C tests run
$(BUILD)/release/libc.a: $(BUILD)/release/librelibc.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
# Debug targets
$(BUILD)/debug/libc.a: $(BUILD)/debug/librelibc.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
echo "create $@" > "$@.mri"
for lib in $^; do\
echo "addlib $$lib" >> "$@.mri"; \
@@ -88,13 +90,18 @@ $(BUILD)/release/libc.a: $(BUILD)/release/librelibc.a $(BUILD)/pthreads-emb/libp
echo "end" >> "$@.mri"
ar -M < "$@.mri"
$(BUILD)/release/libc.so: $(BUILD)/release/librelibc.patched.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
$(BUILD)/debug/libc.so: $(BUILD)/debug/librelibc.patched.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
$(CC) -nostdlib -shared -Wl,--whole-archive $^ -Wl,--no-whole-archive -o $@
$(BUILD)/debug/librelibc.a: $(SRC)
$(CARGO) rustc $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
touch $@
$(BUILD)/debug/librelibc.patched.a: $(BUILD)/debug/librelibc.a
# Patch out clzsi2.o from libgcc
cp $< $@
ar d $@ clzsi2.o
$(BUILD)/debug/crt0.o: $(SRC)
CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
@@ -107,6 +114,27 @@ $(BUILD)/debug/crtn.o: $(SRC)
CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/debug/ld_so.o: $(SRC)
CARGO_INCREMENTAL=0 $(CARGO) rustc --manifest-path src/ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/debug/ld_so: $(BUILD)/debug/ld_so.o $(BUILD)/debug/crti.o $(BUILD)/debug/libc.a $(BUILD)/debug/crtn.o
$(LD) $^ -o $@
# Release targets
$(BUILD)/release/libc.a: $(BUILD)/release/librelibc.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
echo "create $@" > "$@.mri"
for lib in $^; do\
echo "addlib $$lib" >> "$@.mri"; \
done
echo "save" >> "$@.mri"
echo "end" >> "$@.mri"
ar -M < "$@.mri"
$(BUILD)/release/libc.so: $(BUILD)/release/librelibc.patched.a $(BUILD)/pthreads-emb/libpthread.a $(BUILD)/openlibm/libopenlibm.a
$(CC) -nostdlib -shared -Wl,--whole-archive $^ -Wl,--no-whole-archive -o $@
$(BUILD)/release/librelibc.a: $(SRC)
$(CARGO) rustc --release $(CARGOFLAGS) -- --emit link=$@ $(RUSTCFLAGS)
touch $@
@@ -128,6 +156,15 @@ $(BUILD)/release/crtn.o: $(SRC)
CARGO_INCREMENTAL=0 $(CARGO) rustc --release --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/ld_so.o: $(SRC)
CARGO_INCREMENTAL=0 $(CARGO) rustc --release --manifest-path src/ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/ld_so: $(BUILD)/release/ld_so.o $(BUILD)/release/crti.o $(BUILD)/release/libc.a $(BUILD)/release/crtn.o
$(LD) $^ -o $@
# Other targets
$(BUILD)/include: $(SRC)
rm -rf $@ $@.partial
mkdir -p $@.partial
-1
View File
@@ -1,7 +1,6 @@
//! sys/auxv.h implementation
use platform::types::*;
use platform::{Pal, Sys};
pub const AT_HWCAP: usize = 16;
-2
View File
@@ -679,8 +679,6 @@ pub extern "C" fn vfork() -> pid_t {
#[no_mangle]
pub extern "C" fn write(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t {
use core::slice;
let buf = unsafe { slice::from_raw_parts(buf as *const u8, nbyte as usize) };
Sys::write(fildes, buf)
}
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "ld_so"
version = "0.1.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
[lib]
name = "ld_so"
crate-type = ["staticlib"]
+355
View File
@@ -0,0 +1,355 @@
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::{ptr, slice};
use goblin::elf::{Elf, program_header, reloc, sym};
use goblin::error::{Error, Result};
use c_str::CString;
use fs::File;
use header::{fcntl, sys_mman, unistd};
use io::Read;
use platform::types::c_void;
const PAGE_SIZE: usize = 4096;
#[cfg(target_os = "redox")]
const PATH_SEP: char = ';';
#[cfg(target_os = "linux")]
const PATH_SEP: char = ':';
pub struct Linker {
library_path: String,
objects: BTreeMap<String, Box<[u8]>>
}
impl Linker {
pub fn new(library_path: &str) -> Self {
Self {
library_path: library_path.to_string(),
objects: BTreeMap::new(),
}
}
pub fn load(&mut self, name: &str, path: &str) -> Result<()> {
println!("load {}: {}", name, path);
let mut data = Vec::new();
let path_c = CString::new(path).map_err(|err| Error::Malformed(
format!("invalid path '{}': {}", path, err)
))?;
{
let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
let mut file = File::open(&path_c, flags).map_err(|err| Error::Malformed(
format!("failed to open '{}': {}", path, err)
))?;
file.read_to_end(&mut data).map_err(|err| Error::Malformed(
format!("failed to read '{}': {}", path, err)
))?;
}
self.load_data(name, data.into_boxed_slice())
}
pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result<()> {
//TODO: Prevent failures due to recursion
{
let elf = Elf::parse(&data)?;
//println!("{:#?}", elf);
for library in elf.libraries.iter() {
if ! self.objects.contains_key(&library.to_string()) {
self.load_library(library)?;
}
}
}
self.objects.insert(name.to_string(), data);
Ok(())
}
pub fn load_library(&mut self, name: &str) -> Result<()> {
if name.contains('/') {
self.load(name, name)
} else {
let library_path = self.library_path.clone();
for part in library_path.split(PATH_SEP) {
let path = if part.is_empty() {
format!("./{}", name)
} else {
format!("{}/{}", part, name)
};
println!("check {}", path);
let access = unsafe {
let path_c = CString::new(path.as_bytes()).map_err(|err| Error::Malformed(
format!("invalid path '{}': {}", path, err)
))?;
// TODO: Use R_OK | X_OK
unistd::access(path_c.as_ptr(), unistd::F_OK) == 0
};
if access {
self.load(name, &path)?;
return Ok(());
}
}
Err(Error::Malformed(
format!("failed to locate '{}'", name)
))
}
}
pub fn link(&mut self, primary: &str) -> Result<usize> {
let elfs = {
let mut elfs = BTreeMap::new();
for (name, data) in self.objects.iter() {
elfs.insert(name.as_str(), Elf::parse(&data)?);
}
elfs
};
// Load all ELF files into memory and find all globals
let mut mmaps = BTreeMap::new();
let mut globals = BTreeMap::new();
for (elf_name, elf) in elfs.iter() {
println!("load {}", elf_name);
let object = match self.objects.get(*elf_name) {
Some(some) => some,
None => continue,
};
// Calculate virtual memory bounds
let bounds = {
let mut bounds_opt: Option<(usize, usize)> = None;
for ph in elf.program_headers.iter() {
match ph.p_type {
program_header::PT_LOAD => {
let voff = ph.p_vaddr as usize % 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;
println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
if let Some(ref mut bounds) = bounds_opt {
if vaddr < bounds.0 {
bounds.0 = vaddr;
}
if vaddr + vsize > bounds.1 {
bounds.1 = vaddr + vsize;
}
} else {
bounds_opt = Some((vaddr, vaddr + vsize));
}
},
_ => ()
}
}
match bounds_opt {
Some(some) => some,
None => continue,
}
};
println!(" bounds {:#x}, {:#x}", bounds.0, bounds.1);
// Allocate memory
let mmap = unsafe {
let size = bounds.1 /* - bounds.0 */;
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)
));
}
slice::from_raw_parts_mut(ptr as *mut u8, size)
};
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 {
if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
let name = name_res?;
let value = mmap.as_ptr() as usize + sym.st_value as usize;
println!(" global {}: {:x?} = {:#x}", name, sym, value);
globals.insert(name, value);
}
}
}
// Copy data
for ph in elf.program_headers.iter() {
match ph.p_type {
program_header::PT_LOAD => {
let voff = ph.p_vaddr as usize % 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;
// Copy data
let obj_data = {
let range = ph.file_range();
match object.get(range.clone()) {
Some(some) => some,
None => return Err(Error::Malformed(
format!("failed to read {:?}", range)
)),
}
};
let mmap_data = {
let range = ph.p_vaddr as usize..ph.p_vaddr as usize + obj_data.len();
match mmap.get_mut(range.clone()) {
Some(some) => some,
None => return Err(Error::Malformed(
format!("failed to write {:?}", range)
)),
}
};
println!(" copy {:#x}, {:#x}: {:#x}, {:#x}", vaddr, vsize, voff, obj_data.len());
mmap_data.copy_from_slice(obj_data);
},
_ => ()
}
}
mmaps.insert(elf_name, mmap);
}
// Perform relocations and protect pages
let mut entry_opt = None;
for (elf_name, elf) in elfs.iter() {
let mmap = match mmaps.get_mut(elf_name) {
Some(some) => some,
None => continue
};
println!("link {}", elf_name);
if *elf_name == primary {
entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize);
}
// Relocate
for rel in elf.dynrelas.iter().chain(elf.dynrels.iter()).chain(elf.pltrelocs.iter()) {
println!(" rel {}: {:x?}",
reloc::r_to_str(rel.r_type, elf.header.e_machine),
rel
);
let a = rel.r_addend.unwrap_or(0) as usize;
let b = mmap.as_ptr() as usize;
let s = if rel.r_sym > 0 {
let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(
format!("missing symbol for relocation {:?}", rel)
))?;
let name = elf.dynstrtab.get(sym.st_name).ok_or(Error::Malformed(
format!("missing name for symbol {:?}", sym)
))??;
if let Some(value) = globals.get(name) {
println!(" sym {}: {:x?} = {:#x}", name, sym, value);
*value
} else {
println!(" sym {}: {:x?} = undefined", name, sym);
0
}
} else {
0
};
let ptr = unsafe {
mmap.as_mut_ptr().add(rel.r_offset as usize)
};
let set_u64 = |value| {
println!(" set_u64 {:#x}", value);
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_GLOB_DAT | reloc::R_X86_64_JUMP_SLOT => {
set_u64(s as u64);
},
reloc::R_X86_64_RELATIVE => {
set_u64((b + a) as u64);
},
_ => {
println!(" unsupported");
}
}
}
// Protect pages
for ph in elf.program_headers.iter() {
match ph.p_type {
program_header::PT_LOAD => {
let voff = ph.p_vaddr as usize % 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 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;
}
let res = unsafe {
let ptr = mmap.as_mut_ptr().add(vaddr);
println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
sys_mman::mprotect(
ptr as *mut c_void,
vsize,
prot
)
};
if res < 0 {
return Err(Error::Malformed(
format!("failed to mprotect {}", elf_name)
));
}
},
_ => ()
}
}
}
entry_opt.ok_or(Error::Malformed(
format!("missing entry for {}", primary)
))
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod linker;
pub mod start;
+64
View File
@@ -0,0 +1,64 @@
#![no_std]
#![feature(asm)]
#![feature(linkage)]
#![feature(naked_functions)]
#[naked]
#[no_mangle]
pub unsafe extern "C" fn _start() {
#[cfg(target_arch = "x86_64")]
asm!("
# Save original stack and align stack to 16 bytes
mov rbp, rsp
and rsp, 0xFFFFFFFFFFFFFFF0
# Call ld_so_start(stack)
mov rdi, rbp
call relibc_ld_so_start
# Restore original stack, clear registers, and jump to new start function
mov rsp, rbp
xor rcx, rcx
xor rdx, rdx
xor rdi, rdi
xor rsi, rsi
xor r8, r8
xor r9, r9
xor r10, r10
xor r11, r11
jmp rax
"
:
:
:
: "intel", "volatile"
);
#[cfg(target_arch = "aarch64")]
asm!("
mov x0, sp
bl ld_so_start
TODO
"
:
:
:
: "volatile"
);
}
#[naked]
#[no_mangle]
pub unsafe extern "C" fn main(argc: isize, argv: *const *const i8) -> usize {
// LD
0x1D
}
#[panic_handler]
#[linkage = "weak"]
#[no_mangle]
pub unsafe extern "C" fn rust_begin_unwind(pi: &::core::panic::PanicInfo) -> ! {
extern "C" {
fn relibc_panic(pi: &::core::panic::PanicInfo) -> !;
}
relibc_panic(pi)
}
+68
View File
@@ -0,0 +1,68 @@
// Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs
use c_str::CStr;
use header::unistd;
use platform::types::c_char;
use super::linker::Linker;
#[repr(C)]
pub struct Stack {
argc: isize,
argv0: *const c_char,
}
#[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 {}
}
// Pop the first argument (path to ld_so), and get the path of the program
// TODO: Also retrieve LD_LIBRARY_PATH this way
let path_c = unsafe {
let mut argv = &mut sp.argv0 as *mut *const c_char;
loop {
let next_argv = argv.add(1);
let arg = *next_argv;
*argv = arg;
argv = next_argv;
if arg.is_null() {
break;
}
}
sp.argc -= 1;
CStr::from_ptr(sp.argv0)
};
let path = match path_c.to_str() {
Ok(ok) => ok,
Err(err) => {
eprintln!("ld.so: failed to parse path: {}", err);
unistd::_exit(1);
loop {}
}
};
let mut linker = Linker::new("/usr/local/lib:/lib/x86_64-linux-gnu");
match linker.load(&path, &path) {
Ok(()) => (),
Err(err) => {
eprintln!("ld.so: failed to load '{}': {}", path, err);
unistd::_exit(1);
loop {}
}
}
match linker.link(&path) {
Ok(entry) => entry,
Err(err) => {
eprintln!("ld.so: failed to link '{}': {}", path, err);
unistd::_exit(1);
loop {}
}
}
}
+2
View File
@@ -26,6 +26,7 @@
extern crate alloc;
extern crate cbitset;
extern crate core_io;
extern crate goblin;
#[macro_use]
extern crate lazy_static;
extern crate posix_regex;
@@ -50,6 +51,7 @@ pub mod db;
pub mod fs;
pub mod header;
pub mod io;
pub mod ld_so;
pub mod mutex;
pub mod platform;
pub mod start;