diff --git a/Cargo.lock b/Cargo.lock index 9531ce6..b9796fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bitflags" version = "1.2.1" @@ -49,6 +55,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" version = "2.33.3" @@ -64,6 +76,56 @@ dependencies = [ "vec_map", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "elf" version = "0.1.0" @@ -102,6 +164,25 @@ version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -144,15 +225,47 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + [[package]] name = "rsld" version = "0.1.0" dependencies = [ "anyhow", "elf", + "rayon", "structopt", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "strsim" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index d13077e..370fe1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ members = ["elf"] anyhow = "1.0.41" structopt = "0.3.21" elf = { path = "elf" } +rayon = "1.5.1" diff --git a/ctest/Makefile b/ctest/Makefile index 29ab30e..48fdaa5 100644 --- a/ctest/Makefile +++ b/ctest/Makefile @@ -1,13 +1,18 @@ CC := clang +RUST_SOURCES := $(shell find .. -type f -name "*.rs") SOURCES := $(shell find -type f -name "*.c") OBJECTS := $(patsubst %.c, bin/%, $(SOURCES)) +RSLD := $(shell pwd)/../target/debug/rsld -CFLAGS := -v -static -fuse-ld=$(shell pwd)/../target/debug/rsld +CFLAGS := -v -static -fuse-ld=$(RSLD) all: $(OBJECTS) -bin/%: %.c bin +$(RSLD): $(RUST_SOURCES) + cargo build + +bin/%: %.c bin $(RSLD) $(CC) $(CFLAGS) -o $@ $< bin: diff --git a/elf/src/.ignore b/elf/src/.ignore new file mode 100644 index 0000000..51a9f54 --- /dev/null +++ b/elf/src/.ignore @@ -0,0 +1 @@ +constants.rs \ No newline at end of file diff --git a/elf/src/elf.rs b/elf/src/elf.rs index 012aa6a..7899996 100644 --- a/elf/src/elf.rs +++ b/elf/src/elf.rs @@ -1,25 +1,32 @@ use std::io::Read; -use std::mem::MaybeUninit; use anyhow::Result; use crate::constants::*; use crate::header::E_IDENT; +use crate::section::*; macro_rules! elf { ($size:ty) => { + use std::io::Write; + #[derive(Debug, Default)] pub struct Elf { pub header: Header, + pub sections: Vec
, } impl Elf { - pub(crate) fn continue_read(e_ident: E_IDENT, mut r: R) -> Result { - let mut elf: Self = unsafe { MaybeUninit::zeroed().assume_init() }; + pub(crate) fn continue_read(e_ident: E_IDENT, r: R) -> Result { + let mut elf: Self = Elf::default(); elf.header = Header::continue_read(e_ident, r)?; Ok(elf) } + + pub fn write(&self, w: W) -> Result<()> { + Ok(()) + } } }; } diff --git a/elf/src/header.rs b/elf/src/header.rs index fb7105a..f1c3c7e 100644 --- a/elf/src/header.rs +++ b/elf/src/header.rs @@ -6,6 +6,7 @@ use byteordered::{ByteOrdered, Endianness}; use crate::constants::*; +#[allow(non_camel_case_types)] pub type E_IDENT = [u8; EI_NIDENT]; macro_rules! elf_header { @@ -40,7 +41,7 @@ macro_rules! elf_header { } impl Header { - pub(crate) fn continue_read(e_ident: E_IDENT, mut r: R) -> Result { + pub(crate) fn continue_read(e_ident: E_IDENT, r: R) -> Result { let mut header = Header::default(); header.e_ident = e_ident; diff --git a/elf/src/lib.rs b/elf/src/lib.rs index 55c8d4e..d00c537 100644 --- a/elf/src/lib.rs +++ b/elf/src/lib.rs @@ -5,9 +5,9 @@ extern crate anyhow; pub mod constants; pub mod elf; pub mod header; +pub mod section; use std::io::{Read, Write}; -use std::mem::MaybeUninit; use anyhow::Result; @@ -42,14 +42,17 @@ impl Default for Elf { impl Elf { pub fn read(mut r: R) -> Result { + // read the first 16-bytes of the header to see if it's 32-bit or 64-bit let mut e_ident: E_IDENT = [0u8; EI_NIDENT]; - r.read_exact(&mut e_ident); + r.read_exact(&mut e_ident)?; + // continue reading, passing the array we already read let res = match e_ident[EI_CLASS] { ELFCLASS32 => Elf::Elf32(elf32::Elf::continue_read(e_ident, r)?), ELFCLASS64 => Elf::Elf64(elf64::Elf::continue_read(e_ident, r)?), n => bail!("invalid class: {}", n), }; + Ok(res) } diff --git a/elf/src/section.rs b/elf/src/section.rs new file mode 100644 index 0000000..4ba0e5b --- /dev/null +++ b/elf/src/section.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct Section {} diff --git a/src/link.rs b/src/link.rs index 402b552..a2879dc 100644 --- a/src/link.rs +++ b/src/link.rs @@ -1,36 +1,104 @@ -use std::fs::{File, OpenOptions}; -use std::os::unix::fs::OpenOptionsExt; +use std::fs::File; -use anyhow::{Context, Result}; -use elf::Elf; +use anyhow::Result; +use elf::{elf32::Elf as Elf32, elf64::Elf as Elf64, Elf}; +use rayon::prelude::*; use crate::{LinkUnit, Opt}; -pub(crate) fn link(opt: &Opt) -> Result<()> { - let res = Elf::default(); +pub(crate) fn link(opt: Opt) -> Result<()> { + let output = match opt.out { + Some(v) => v, + None => bail!("TODO: default output name"), + }; - for unit in &opt.units { - match unit { - LinkUnit::Path(path) => { - let file = File::open(path)?; - let elf = Elf::read(&file)?; - println!("elf: {:?}", elf); - } - _ => {} - } + let accum = opt + .units + .into_par_iter() + .try_fold(|| Accum::default(), sort_all_elfs_by_bitness) + .try_reduce(|| Accum::default(), combine_accum)?; + + // call out to the appropriately specialized function + if accum.elfs32.is_empty() { + bits_64::link(output, accum.elfs64) + } else if accum.elfs64.is_empty() { + bits_32::link(output, accum.elfs32) + } else { + // not all ELFs are either 32-bit or 64-bit + bail!("not all elfs have the same bitness") } - - if let Some(path) = &opt.out { - let path = crate::utils::normalize_path(path); - let file = OpenOptions::new() - .create(true) - .write(true) - .mode(0o755) - .open(&path) - .with_context(|| format!("could not create output file {:?}", path))?; - res.write(file); - println!("wrote to {:?}", path); - } - - Ok(()) +} + +#[derive(Default, Debug)] +struct Accum { + elfs32: Vec, + elfs64: Vec, +} + +fn sort_all_elfs_by_bitness(mut accum: Accum, unit: LinkUnit) -> Result { + match unit { + LinkUnit::Path(path) => { + let file = File::open(path)?; + let elf = Elf::read(&file)?; + // println!("elf: {:?}", elf); + match elf { + Elf::Elf32(v) => accum.elfs32.push(v), + Elf::Elf64(v) => accum.elfs64.push(v), + } + + Ok(accum) + } + + _ => bail!("lol"), + } +} + +fn combine_accum(mut a: Accum, b: Accum) -> Result { + // TODO: early check to make sure at least one of these are 0 + Ok(Accum { + elfs32: { + a.elfs32.extend(b.elfs32); + a.elfs32 + }, + elfs64: { + a.elfs64.extend(b.elfs64); + a.elfs64 + }, + }) +} + +macro_rules! link { + () => { + use std::fs::OpenOptions; + use std::os::unix::fs::OpenOptionsExt; + use std::path::PathBuf; + + use anyhow::{Context, Result}; + + pub fn link(output: PathBuf, elfs: Vec) -> Result<()> { + let res = Elf::default(); + println!("Hellosu {:?}", elfs); + + let path = crate::utils::normalize_path(&output); + let file = OpenOptions::new() + .create(true) + .write(true) + .mode(0o755) + .open(&path) + .with_context(|| format!("could not create output file {:?}", path))?; + + res.write(file)?; + Ok(()) + } + }; +} + +mod bits_32 { + pub type Elf = elf::elf32::Elf; + link! {} +} + +mod bits_64 { + pub type Elf = elf::elf64::Elf; + link! {} } diff --git a/src/main.rs b/src/main.rs index bb3f507..3450165 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate anyhow; + mod link; mod utils; @@ -13,14 +16,14 @@ struct Opt { emulate: String, out: Option, link_includes: Vec, - link_to: Vec, units: Vec, } #[derive(Debug)] enum LinkUnit { + Lib(String), Path(PathBuf), - Group(Vec), + Group(Vec), } fn main() -> Result<()> { @@ -54,18 +57,23 @@ fn main() -> Result<()> { let path = PathBuf::from(arg.trim_start_matches("-L")); opt.link_includes.push(path); } else if arg.starts_with("-l") { - opt.link_to.push(arg.trim_start_matches("-l").to_owned()); + let name = arg.trim_start_matches("-l").to_owned(); + if let Some(curr_group) = curr_group.as_mut() { + curr_group.push(LinkUnit::Lib(name)); + } else { + opt.units.push(LinkUnit::Lib(name)); + } } else { let path = PathBuf::from(&arg); if let Some(curr_group) = curr_group.as_mut() { - curr_group.push(path); + curr_group.push(LinkUnit::Path(path)); } else { opt.units.push(LinkUnit::Path(path)); } } } - link::link(&opt)?; + link::link(opt)?; Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index 3d8d4a8..cdb530b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use std::path::{Component, Path, PathBuf}; -pub fn normalize_path(path: &Path) -> PathBuf { - let mut components = path.components().peekable(); +pub fn normalize_path(path: impl AsRef) -> PathBuf { + let mut components = path.as_ref().components().peekable(); let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { components.next(); PathBuf::from(c.as_os_str())