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",
]
[[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"

View file

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

View file

@ -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:

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::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<Section>,
}
impl Elf {
pub(crate) fn continue_read<R: Read>(e_ident: E_IDENT, mut r: R) -> Result<Self> {
let mut elf: Self = unsafe { MaybeUninit::zeroed().assume_init() };
pub(crate) fn continue_read<R: Read>(e_ident: E_IDENT, r: R) -> Result<Self> {
let mut elf: Self = Elf::default();
elf.header = Header::continue_read(e_ident, r)?;
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::*;
#[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<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();
header.e_ident = e_ident;

View file

@ -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<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];
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)
}

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::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<Elf32>,
elfs64: Vec<Elf64>,
}
fn sort_all_elfs_by_bitness(mut accum: Accum, unit: LinkUnit) -> Result<Accum> {
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<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 utils;
@ -13,14 +16,14 @@ struct Opt {
emulate: String,
out: Option<PathBuf>,
link_includes: Vec<PathBuf>,
link_to: Vec<String>,
units: Vec<LinkUnit>,
}
#[derive(Debug)]
enum LinkUnit {
Lib(String),
Path(PathBuf),
Group(Vec<PathBuf>),
Group(Vec<LinkUnit>),
}
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(())
}

View file

@ -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<Path>) -> 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())