diff --git a/Cargo.lock b/Cargo.lock index 198a02c..892470a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.40" @@ -50,6 +59,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -92,6 +116,7 @@ dependencies = [ "env_logger", "log", "object", + "structopt", "tempfile", ] @@ -106,6 +131,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.18" @@ -121,6 +155,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.91" @@ -168,6 +208,48 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.8.3" @@ -243,6 +325,47 @@ dependencies = [ "winapi", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.2.0" @@ -266,6 +389,45 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index bd080bb..ec33206 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,5 @@ anyhow = "1.0.32" env_logger = "0.8.3" log = "0.4.11" object = "0.23.0" +structopt = "0.3.21" tempfile = "3.1.0" diff --git a/src/main.rs b/src/main.rs index f606415..8cbfff1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ use std::{ - borrow::Cow, env, fs::{self, File}, io::Write, @@ -10,6 +9,7 @@ use std::{ use anyhow::anyhow; use object::{elf, Object as _, ObjectSection, SectionFlags}; +use structopt::StructOpt; const EXIT_CODE_FAILURE: i32 = 1; // TODO make this configurable (via command-line flag or similar) @@ -17,12 +17,28 @@ const LINKER: &str = "rust-lld"; /// Stack Pointer alignment required by the ARM architecture const SP_ALIGN: u64 = 8; +#[derive(Debug, StructOpt)] +struct Opt { + /// Add `` to library search path + #[structopt(short = "-L", long, parse(from_os_str))] + library_path: Vec, + + /// Set output file name + #[structopt(short, long, parse(from_os_str))] + output: PathBuf, + + /// Read linker script + #[structopt(short = "T", long)] + script: Vec, +} + fn main() -> anyhow::Result<()> { notmain().map(|code| process::exit(code)) } fn notmain() -> anyhow::Result { env_logger::init(); + let opt: Opt = Opt::from_args(); // NOTE `skip` the name/path of the binary (first argument) let args = env::args().skip(1).collect::>(); @@ -35,12 +51,13 @@ fn notmain() -> anyhow::Result { if !status.success() { return Ok(status.code().unwrap_or(EXIT_CODE_FAILURE)); } - // if linking succeeds then linker scripts are well-formed; we'll rely on that in the parser + let current_dir = env::current_dir()?; - let linker_scripts = get_linker_scripts(&args, ¤t_dir)?; - let output_path = - get_output_path(&args).ok_or_else(|| anyhow!("(BUG?) `-o` flag not found"))?; + + let mut search_paths = opt.library_path; + search_paths.push(current_dir.clone()); + let linker_scripts = get_linker_scripts(opt.script, search_paths)?; // here we assume that we'll end with the same linker script as LLD // I'm unsure about how LLD picks a linker script when there are multiple candidates in the @@ -57,7 +74,7 @@ fn notmain() -> anyhow::Result { let (ram_linker_script, ram_entry) = ram_path_entry .ok_or_else(|| anyhow!("MEMORY.RAM not found after scanning linker scripts"))?; - let elf = fs::read(output_path)?; + let elf = fs::read(opt.output)?; let object = object::File::parse(&elf)?; // TODO assert that `_stack_start == ORIGIN(RAM) + LENGTH(RAM)` @@ -194,38 +211,14 @@ impl LinkerScript { } } -fn get_linker_scripts(args: &[String], current_dir: &Path) -> anyhow::Result> { - // search paths are the current dir and args passed by `-L` - let mut search_paths = args - .windows(2) - .filter_map(|x| { - if x[0] == "-L" { - log::trace!("new search path: {}", x[1]); - return Some(Path::new(&x[1])); - } - None - }) - .collect::>(); - search_paths.push(current_dir); - - // get names of linker scripts, passed via `-T` - // FIXME this doesn't handle "-T memory.x" (as two separate CLI arguments) - let mut search_list = args - .iter() - .filter_map(|arg| { - const FLAG: &str = "-T"; - if arg.starts_with(FLAG) { - let filename = &arg[FLAG.len()..]; - return Some(Cow::Borrowed(filename)); - } - None - }) - .collect::>(); - - // try to find all linker scripts from `search_list` in the `search_paths` +/// Try to find all [`LinkerScript`]s from `search_list` in the `search_paths` +fn get_linker_scripts( + mut search_list: Vec, + search_paths: Vec, +) -> anyhow::Result> { let mut linker_scripts = vec![]; while let Some(filename) = search_list.pop() { - for dir in &search_paths { + for dir in search_paths.iter() { let full_path = dir.join(&*filename); if full_path.exists() { @@ -235,34 +228,20 @@ fn get_linker_scripts(args: &[String], current_dir: &Path) -> anyhow::Result Option<&str> { - let mut next_is_output = false; - for arg in args { - if arg == "-o" { - next_is_output = true; - } else if next_is_output { - return Some(arg); - } - } - - None -} - /// Entry under the `MEMORY` section in a linker script #[derive(Clone, Copy, Debug, PartialEq)] struct MemoryEntry {