This commit is contained in:
Michael Zhang 2021-06-29 23:44:18 -05:00
parent d60cd92a94
commit 138bbb39a9
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
11 changed files with 253 additions and 44 deletions

113
Cargo.lock generated
View file

@ -28,6 +28,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.2.1" version = "1.2.1"
@ -49,6 +55,12 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.3" version = "2.33.3"
@ -64,6 +76,56 @@ dependencies = [
"vec_map", "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]] [[package]]
name = "elf" name = "elf"
version = "0.1.0" version = "0.1.0"
@ -102,6 +164,25 @@ version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" 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]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "1.0.4" version = "1.0.4"
@ -144,15 +225,47 @@ dependencies = [
"proc-macro2", "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]] [[package]]
name = "rsld" name = "rsld"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"elf", "elf",
"rayon",
"structopt", "structopt",
] ]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"

View file

@ -10,3 +10,4 @@ members = ["elf"]
anyhow = "1.0.41" anyhow = "1.0.41"
structopt = "0.3.21" structopt = "0.3.21"
elf = { path = "elf" } elf = { path = "elf" }
rayon = "1.5.1"

View file

@ -1,13 +1,18 @@
CC := clang CC := clang
RUST_SOURCES := $(shell find .. -type f -name "*.rs")
SOURCES := $(shell find -type f -name "*.c") SOURCES := $(shell find -type f -name "*.c")
OBJECTS := $(patsubst %.c, bin/%, $(SOURCES)) 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) all: $(OBJECTS)
bin/%: %.c bin $(RSLD): $(RUST_SOURCES)
cargo build
bin/%: %.c bin $(RSLD)
$(CC) $(CFLAGS) -o $@ $< $(CC) $(CFLAGS) -o $@ $<
bin: bin:

1
elf/src/.ignore Normal file
View file

@ -0,0 +1 @@
constants.rs

View file

@ -1,25 +1,32 @@
use std::io::Read; use std::io::Read;
use std::mem::MaybeUninit;
use anyhow::Result; use anyhow::Result;
use crate::constants::*; use crate::constants::*;
use crate::header::E_IDENT; use crate::header::E_IDENT;
use crate::section::*;
macro_rules! elf { macro_rules! elf {
($size:ty) => { ($size:ty) => {
use std::io::Write;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Elf { pub struct Elf {
pub header: Header, pub header: Header,
pub sections: Vec<Section>,
} }
impl Elf { impl Elf {
pub(crate) fn continue_read<R: Read>(e_ident: E_IDENT, mut r: R) -> Result<Self> { pub(crate) fn continue_read<R: Read>(e_ident: E_IDENT, r: R) -> Result<Self> {
let mut elf: Self = unsafe { MaybeUninit::zeroed().assume_init() }; let mut elf: Self = Elf::default();
elf.header = Header::continue_read(e_ident, r)?; elf.header = Header::continue_read(e_ident, r)?;
Ok(elf) Ok(elf)
} }
pub fn write<W: Write>(&self, w: W) -> Result<()> {
Ok(())
}
} }
}; };
} }

View file

@ -6,6 +6,7 @@ use byteordered::{ByteOrdered, Endianness};
use crate::constants::*; use crate::constants::*;
#[allow(non_camel_case_types)]
pub type E_IDENT = [u8; EI_NIDENT]; pub type E_IDENT = [u8; EI_NIDENT];
macro_rules! elf_header { macro_rules! elf_header {
@ -40,7 +41,7 @@ macro_rules! elf_header {
} }
impl Header { impl Header {
pub(crate) fn continue_read<R: Read>(e_ident: E_IDENT, mut r: R) -> Result<Self> { pub(crate) fn continue_read<R: Read>(e_ident: E_IDENT, r: R) -> Result<Self> {
let mut header = Header::default(); let mut header = Header::default();
header.e_ident = e_ident; header.e_ident = e_ident;

View file

@ -5,9 +5,9 @@ extern crate anyhow;
pub mod constants; pub mod constants;
pub mod elf; pub mod elf;
pub mod header; pub mod header;
pub mod section;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::mem::MaybeUninit;
use anyhow::Result; use anyhow::Result;
@ -42,14 +42,17 @@ impl Default for Elf {
impl Elf { impl Elf {
pub fn read<R: Read>(mut r: R) -> Result<Self> { pub fn read<R: Read>(mut r: R) -> Result<Self> {
// 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]; 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] { let res = match e_ident[EI_CLASS] {
ELFCLASS32 => Elf::Elf32(elf32::Elf::continue_read(e_ident, r)?), ELFCLASS32 => Elf::Elf32(elf32::Elf::continue_read(e_ident, r)?),
ELFCLASS64 => Elf::Elf64(elf64::Elf::continue_read(e_ident, r)?), ELFCLASS64 => Elf::Elf64(elf64::Elf::continue_read(e_ident, r)?),
n => bail!("invalid class: {}", n), n => bail!("invalid class: {}", n),
}; };
Ok(res) Ok(res)
} }

2
elf/src/section.rs Normal file
View file

@ -0,0 +1,2 @@
#[derive(Debug)]
pub struct Section {}

View file

@ -1,36 +1,104 @@
use std::fs::{File, OpenOptions}; use std::fs::File;
use std::os::unix::fs::OpenOptionsExt;
use anyhow::{Context, Result}; use anyhow::Result;
use elf::Elf; use elf::{elf32::Elf as Elf32, elf64::Elf as Elf64, Elf};
use rayon::prelude::*;
use crate::{LinkUnit, Opt}; use crate::{LinkUnit, Opt};
pub(crate) fn link(opt: &Opt) -> Result<()> { pub(crate) fn link(opt: Opt) -> Result<()> {
let res = Elf::default(); let output = match opt.out {
Some(v) => v,
None => bail!("TODO: default output name"),
};
for unit in &opt.units { let accum = opt
match unit { .units
LinkUnit::Path(path) => { .into_par_iter()
let file = File::open(path)?; .try_fold(|| Accum::default(), sort_all_elfs_by_bitness)
let elf = Elf::read(&file)?; .try_reduce(|| Accum::default(), combine_accum)?;
println!("elf: {:?}", elf);
} // 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); #[derive(Default, Debug)]
let file = OpenOptions::new() struct Accum {
.create(true) elfs32: Vec<Elf32>,
.write(true) elfs64: Vec<Elf64>,
.mode(0o755) }
.open(&path)
.with_context(|| format!("could not create output file {:?}", path))?; fn sort_all_elfs_by_bitness(mut accum: Accum, unit: LinkUnit) -> Result<Accum> {
res.write(file); match unit {
println!("wrote to {:?}", path); LinkUnit::Path(path) => {
} let file = File::open(path)?;
let elf = Elf::read(&file)?;
Ok(()) // 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<Accum> {
// 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<Elf>) -> 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! {}
} }

View file

@ -1,3 +1,6 @@
#[macro_use]
extern crate anyhow;
mod link; mod link;
mod utils; mod utils;
@ -13,14 +16,14 @@ struct Opt {
emulate: String, emulate: String,
out: Option<PathBuf>, out: Option<PathBuf>,
link_includes: Vec<PathBuf>, link_includes: Vec<PathBuf>,
link_to: Vec<String>,
units: Vec<LinkUnit>, units: Vec<LinkUnit>,
} }
#[derive(Debug)] #[derive(Debug)]
enum LinkUnit { enum LinkUnit {
Lib(String),
Path(PathBuf), Path(PathBuf),
Group(Vec<PathBuf>), Group(Vec<LinkUnit>),
} }
fn main() -> Result<()> { fn main() -> Result<()> {
@ -54,18 +57,23 @@ fn main() -> Result<()> {
let path = PathBuf::from(arg.trim_start_matches("-L")); let path = PathBuf::from(arg.trim_start_matches("-L"));
opt.link_includes.push(path); opt.link_includes.push(path);
} else if arg.starts_with("-l") { } 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 { } else {
let path = PathBuf::from(&arg); let path = PathBuf::from(&arg);
if let Some(curr_group) = curr_group.as_mut() { if let Some(curr_group) = curr_group.as_mut() {
curr_group.push(path); curr_group.push(LinkUnit::Path(path));
} else { } else {
opt.units.push(LinkUnit::Path(path)); opt.units.push(LinkUnit::Path(path));
} }
} }
} }
link::link(&opt)?; link::link(opt)?;
Ok(()) Ok(())
} }

View file

@ -1,7 +1,7 @@
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
pub fn normalize_path(path: &Path) -> PathBuf { pub fn normalize_path(path: impl AsRef<Path>) -> PathBuf {
let mut components = path.components().peekable(); let mut components = path.as_ref().components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next(); components.next();
PathBuf::from(c.as_os_str()) PathBuf::from(c.as_os_str())