From c6217ebfdbf3beea8f6012ad0455aa42427a9d33 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 16 Aug 2021 20:06:44 -0700 Subject: [PATCH] Roc linker library base setup --- Cargo.lock | 19 +++++++++++++++++++ Cargo.toml | 1 + linker/Cargo.toml | 24 ++++++++++++++++++++++++ linker/README.md | 31 +++++++++++++++++++++++++++++++ linker/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ linker/src/main.rs | 17 +++++++++++++++++ linker/tests/.gitignore | 1 + linker/tests/Makefile | 12 ++++++++++++ linker/tests/app.c | 3 +++ linker/tests/platform.c | 9 +++++++++ 10 files changed, 151 insertions(+) create mode 100644 linker/Cargo.toml create mode 100644 linker/README.md create mode 100644 linker/src/lib.rs create mode 100644 linker/src/main.rs create mode 100644 linker/tests/.gitignore create mode 100644 linker/tests/Makefile create mode 100644 linker/tests/app.c create mode 100644 linker/tests/platform.c diff --git a/Cargo.lock b/Cargo.lock index 4c7a553e59..770afa7bae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2219,6 +2219,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" +dependencies = [ + "flate2", + "memchr", +] + [[package]] name = "once_cell" version = "1.7.2" @@ -3296,6 +3306,15 @@ dependencies = [ name = "roc_ident" version = "0.1.0" +[[package]] +name = "roc_linker" +version = "0.1.0" +dependencies = [ + "bumpalo", + "clap 3.0.0-beta.1", + "object 0.26.0", +] + [[package]] name = "roc_load" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 01b160bf9a..196832420a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ members = [ "cli/cli_utils", "roc_std", "docs", + "linker", ] exclude = [ "ci/bench-runner" ] # Needed to be able to run `cargo run -p roc_cli --no-default-features` - diff --git a/linker/Cargo.toml b/linker/Cargo.toml new file mode 100644 index 0000000000..40444f77ec --- /dev/null +++ b/linker/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "roc_linker" +version = "0.1.0" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +repository = "https://github.com/rtfeldman/roc" +edition = "2018" +description = "A surgical linker for Roc" + +[lib] +name = "roc_linker" +path = "src/lib.rs" + +[[bin]] +name = "link" +path = "src/main.rs" +test = false +bench = false + +[dependencies] +# TODO switch to clap 3.0.0 once it's out. Tried adding clap = "~3.0.0-beta.1" and cargo wouldn't accept it +clap = { git = "https://github.com/rtfeldman/clap", branch = "master" } +object = { version = "0.26", features = ["read"] } +bumpalo = { version = "3.6.1", features = ["collections"] } \ No newline at end of file diff --git a/linker/README.md b/linker/README.md new file mode 100644 index 0000000000..047dc09480 --- /dev/null +++ b/linker/README.md @@ -0,0 +1,31 @@ +# The Roc Surgical Linker + +This linker has the goal of being extremely slim lined and fast. +It is focused on the scope of only linking platforms to Roc applications. +This restriction enables ignoring most of linking. + +## General Overview + +This linker is run in 2 phases: preprocessing and surigical linking. + +### Platform Preprocessor + +1. Dynamically link the platform to a dummy Roc application dynamic library +1. Create metadata related to Roc dynamically linked functions + - Symbols that need to be redefined + - Call locations that need to be modified for each symbol + - Locations of special roc functions (roc_alloc, roc_dealloc, builtins, etc) +1. Modify the main executable to no longer be dynamically link + - Delete dependency on dynamic library + - Remove symbols from the dynamic table (maybe add them to the regular table?) + - Delete GOT and PLT entries + - Remove relocations from the dynamic table + - Add extra header information about new text and data section at end of file + +### Surgical Linker + +1. Copy over preprocessed platform as base +1. Append text and data of application, noting offset + - This could potentially have extra complication around section locations and updating the header +1. Surgically update all call locations in the platform +1. Surgically update call information in the application (also dealing with other relocations for builtins) diff --git a/linker/src/lib.rs b/linker/src/lib.rs new file mode 100644 index 0000000000..05313d0ae1 --- /dev/null +++ b/linker/src/lib.rs @@ -0,0 +1,34 @@ +use clap::{App, AppSettings, Arg}; +use std::io; + +pub const CMD_PREPROCESS: &str = "preprocess"; +pub const CMD_SURGERY: &str = "surgery"; +pub const EXEC: &str = "EXEC"; +pub const SHARED_LIB: &str = "SHARED_LIB"; + +pub fn build_app<'a>() -> App<'a> { + App::new("link") + .about("Preprocesses a platform and surgically links it to an application.") + .setting(AppSettings::SubcommandRequiredElseHelp) + .subcommand( + App::new(CMD_PREPROCESS) + .about("Preprocesses a dynamically linked platform to prepare for linking.") + .arg( + Arg::with_name(EXEC) + .help("The dynamically link platform executable") + .required(true), + ) + .arg( + Arg::with_name(SHARED_LIB) + .help("The dummy shared library representing the Roc application") + .required(true), + ), + ) + .subcommand( + App::new(CMD_SURGERY).about("Links a preprocessed platform with a Roc application."), + ) +} + +pub fn preprocess() -> io::Result<()> { + panic!("sad"); +} diff --git a/linker/src/main.rs b/linker/src/main.rs new file mode 100644 index 0000000000..494d46c39b --- /dev/null +++ b/linker/src/main.rs @@ -0,0 +1,17 @@ +use roc_linker::{build_app, preprocess, CMD_PREPROCESS, CMD_SURGERY}; +use std::io; + +fn main() -> io::Result<()> { + let matches = build_app().get_matches(); + + let exit_code = match matches.subcommand_name() { + None => Ok::(-1), + Some(CMD_PREPROCESS) => { + preprocess()?; + Ok(0) + } + Some(CMD_SURGERY) => Ok(0), + _ => unreachable!(), + }?; + std::process::exit(exit_code); +} diff --git a/linker/tests/.gitignore b/linker/tests/.gitignore new file mode 100644 index 0000000000..f1fe8d1efb --- /dev/null +++ b/linker/tests/.gitignore @@ -0,0 +1 @@ +*.so \ No newline at end of file diff --git a/linker/tests/Makefile b/linker/tests/Makefile new file mode 100644 index 0000000000..5933ce15f2 --- /dev/null +++ b/linker/tests/Makefile @@ -0,0 +1,12 @@ +SHLIB_LDFLAGS = -shared -Wl,--allow-shlib-undefined + +all: platform + +platform: platform.c libapp.so + $(CC) -O2 -fPIC -o $@ $^ + +libapp.so: app.c + $(CC) -O2 -fPIC -shared -o $@ $^ + +clean: + rm -f platform libapp.so \ No newline at end of file diff --git a/linker/tests/app.c b/linker/tests/app.c new file mode 100644 index 0000000000..1d3311dd93 --- /dev/null +++ b/linker/tests/app.c @@ -0,0 +1,3 @@ +#include + +void app() { printf("Hello World from the application"); } diff --git a/linker/tests/platform.c b/linker/tests/platform.c new file mode 100644 index 0000000000..41d36b1bcb --- /dev/null +++ b/linker/tests/platform.c @@ -0,0 +1,9 @@ +#include + +void app(); + +int main() { + printf("Hello World from the platform"); + app(); + return 0; +}