Roc linker library base setup

This commit is contained in:
Brendan Hansknecht 2021-08-16 20:06:44 -07:00
parent d5058041b0
commit c6217ebfdb
10 changed files with 151 additions and 0 deletions

19
Cargo.lock generated
View file

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

View file

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

24
linker/Cargo.toml Normal file
View file

@ -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"] }

31
linker/README.md Normal file
View file

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

34
linker/src/lib.rs Normal file
View file

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

17
linker/src/main.rs Normal file
View file

@ -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::<i32, io::Error>(-1),
Some(CMD_PREPROCESS) => {
preprocess()?;
Ok(0)
}
Some(CMD_SURGERY) => Ok(0),
_ => unreachable!(),
}?;
std::process::exit(exit_code);
}

1
linker/tests/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.so

12
linker/tests/Makefile Normal file
View file

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

3
linker/tests/app.c Normal file
View file

@ -0,0 +1,3 @@
#include <stdio.h>
void app() { printf("Hello World from the application"); }

9
linker/tests/platform.c Normal file
View file

@ -0,0 +1,9 @@
#include <stdio.h>
void app();
int main() {
printf("Hello World from the platform");
app();
return 0;
}