diff --git a/Cargo.lock b/Cargo.lock index 37dccfd..beb901a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "clap" version = "2.33.3" @@ -126,6 +132,7 @@ name = "rsld" version = "0.1.0" dependencies = [ "anyhow", + "byteorder", "structopt", ] diff --git a/Cargo.toml b/Cargo.toml index 6fbe8d5..8589242 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ edition = "2018" [dependencies] anyhow = "1.0.41" +byteorder = "1.4.3" structopt = "0.3.21" diff --git a/ctest/.gitignore b/ctest/.gitignore new file mode 100644 index 0000000..c5e82d7 --- /dev/null +++ b/ctest/.gitignore @@ -0,0 +1 @@ +bin \ No newline at end of file diff --git a/ctest/Makefile b/ctest/Makefile index 2b2fb47..29ab30e 100644 --- a/ctest/Makefile +++ b/ctest/Makefile @@ -1,13 +1,13 @@ CC := clang SOURCES := $(shell find -type f -name "*.c") -OBJECTS := $(patsubst %.c, bin/%.bin, $(SOURCES)) +OBJECTS := $(patsubst %.c, bin/%, $(SOURCES)) CFLAGS := -v -static -fuse-ld=$(shell pwd)/../target/debug/rsld all: $(OBJECTS) -bin/%.bin: %.c bin +bin/%: %.c bin $(CC) $(CFLAGS) -o $@ $< bin: diff --git a/src/elf.rs b/src/elf.rs new file mode 100644 index 0000000..6fc68a1 --- /dev/null +++ b/src/elf.rs @@ -0,0 +1,47 @@ +use std::io::{Read, Write}; +use std::mem::MaybeUninit; + +use anyhow::Result; +use byteorder::{LittleEndian, ReadBytesExt}; + +#[derive(Debug, Default)] +pub struct Elf { + header: Header, + program_header: Option, +} + +#[derive(Debug)] +pub struct Header { + e_ident: [u8; 16], + e_type: u16, + e_machine: u16, + e_version: u32, +} + +impl Default for Header { + fn default() -> Self { + let mut header: Self = unsafe { MaybeUninit::zeroed().assume_init() }; + header.e_ident[0] = 0x7f; + header.e_ident[1] = b'E'; + header.e_ident[2] = b'L'; + header.e_ident[3] = b'F'; + header + } +} + +#[derive(Debug, Default)] +pub struct ProgramHeader {} + +impl Elf { + pub fn read(mut r: R) -> Result { + let mut elf = Elf::default(); + + // header + r.read_exact(&mut elf.header.e_ident)?; + elf.header.e_type = r.read_u16::()?; + + Ok(elf) + } + + pub fn write(&self, mut w: W) {} +} diff --git a/src/link.rs b/src/link.rs index 3e56362..d6d03d8 100644 --- a/src/link.rs +++ b/src/link.rs @@ -1,5 +1,34 @@ -use crate::Opt; +use std::fs::{File, OpenOptions}; +use std::os::unix::fs::OpenOptionsExt; -pub(crate) fn link(opt: &Opt) { +use anyhow::{Context, Result}; +use crate::elf::Elf; +use crate::{LinkUnit, Opt}; + +pub(crate) fn link(opt: &Opt) -> Result<()> { + for unit in &opt.units { + match unit { + LinkUnit::Path(path) => { + let file = File::open(path)?; + let elf = Elf::read(&file)?; + } + _ => {} + } + } + + let res = Elf::default(); + 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(()) } diff --git a/src/main.rs b/src/main.rs index 5b10747..13a4009 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ +mod elf; mod link; +mod utils; use std::env; use std::path::PathBuf; +use anyhow::Result; + #[derive(Debug, Default)] struct Opt { eh_frame_hdr: bool, @@ -20,7 +24,7 @@ enum LinkUnit { Group(Vec), } -fn main() { +fn main() -> Result<()> { let mut opt = Opt::default(); let mut it = env::args(); let mut curr_group = None; @@ -31,44 +35,28 @@ fn main() { while let Some(arg) = it.next() { if arg == "-static" { opt.is_static = true; - } - - else if arg == "--eh-frame-hdr" { + } else if arg == "--eh-frame-hdr" { opt.eh_frame_hdr = true; - } - - else if arg == "-m" { + } else if arg == "-m" { let next = it.next().unwrap(); opt.emulate = next; - } - - else if arg == "-o" { + } else if arg == "-o" { let next = it.next().unwrap(); opt.out = Some(PathBuf::from(next)); - } - - else if arg == "--start-group" { + } else if arg == "--start-group" { curr_group = Some(Vec::new()); - } - - else if arg == "--end-group" { + } else if arg == "--end-group" { if let Some(curr_group) = curr_group.take() { if !curr_group.is_empty() { opt.units.push(LinkUnit::Group(curr_group)); } } - } - - else if arg.starts_with("-L") { + } else if arg.starts_with("-L") { let path = PathBuf::from(arg.trim_start_matches("-L")); 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()); - } - - else { + } else { let path = PathBuf::from(&arg); if let Some(curr_group) = curr_group.as_mut() { curr_group.push(path); @@ -78,7 +66,7 @@ fn main() { } } - link::link(&opt); + link::link(&opt)?; - println!("opt: {:?}", opt); + Ok(()) } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..a24ad1d --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,28 @@ +use std::path::{Path, PathBuf, Component}; + +pub fn normalize_path(path: &Path) -> PathBuf { + let mut components = path.components().peekable(); + let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { + components.next(); + PathBuf::from(c.as_os_str()) + } else { + PathBuf::new() + }; + + for component in components { + match component { + Component::Prefix(..) => unreachable!(), + Component::RootDir => { + ret.push(component.as_os_str()); + } + Component::CurDir => {} + Component::ParentDir => { + ret.pop(); + } + Component::Normal(c) => { + ret.push(c); + } + } + } + ret +} \ No newline at end of file