Skip to content

Commit

Permalink
feat: add linker helper
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Apr 15, 2024
1 parent 6f43b14 commit 11350d5
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 18 additions & 7 deletions benches/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use clap::{Parser, ValueEnum};
use color_eyre::{eyre::eyre, Result};
use revm_jit::{
debug_time, eyre::Context, new_llvm_backend, EvmCompiler, EvmContext, OptimizationLevel,
debug_time,
eyre::{ensure, Context},
new_llvm_backend, EvmCompiler, EvmContext, OptimizationLevel,
};
use revm_jit_benches::Bench;
use revm_primitives::{hex, Bytes, Env, SpecId};
Expand Down Expand Up @@ -51,7 +53,7 @@ fn main() -> Result<()> {
let context = revm_jit::llvm::inkwell::context::Context::create();
let backend = new_llvm_backend(&context, cli.aot, opt_level)?;
let mut compiler = EvmCompiler::new(backend);
compiler.set_dump_to(Some(PathBuf::from("./tmp/revm-jit")));
compiler.set_dump_to(Some(PathBuf::from("tmp/revm-jit")));
compiler.set_module_name(&cli.bench_name);
compiler.set_disable_gas(cli.no_gas);
compiler.set_frame_pointers(true);
Expand Down Expand Up @@ -97,12 +99,21 @@ fn main() -> Result<()> {
let f_id = compiler.translate(Some(name), bytecode, spec_id)?;

if cli.aot {
let mut path = compiler.out_dir().unwrap().to_path_buf();
path.push(cli.bench_name);
path.push("a.o");
let mut file = std::fs::File::create(&path)?;
let mut out_dir = compiler.out_dir().unwrap().to_path_buf();
out_dir.push(cli.bench_name);

let obj = out_dir.join("a.o");
let mut file = std::fs::File::create(&obj)?;
compiler.write_object(&mut file)?;
eprintln!("Wrote object file to {}", path.display());
ensure!(obj.exists(), "Failed to write object file");
eprintln!("Compiled object file to {}", obj.display());

let so = out_dir.join("a.so");
let linker = revm_jit::Linker::new();
linker.link(&so, [obj.to_str().unwrap()])?;
ensure!(so.exists(), "Failed to link object file");
eprintln!("Linked shared object file to {}", so.display());

return Ok(());
}

Expand Down
2 changes: 1 addition & 1 deletion crates/revm-jit-llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl<'ctx> EvmLlvmBackend<'ctx> {
&cpu.to_string_lossy(),
&features.to_string_lossy(),
opt_level,
if aot { RelocMode::Default } else { RelocMode::PIC },
if aot { RelocMode::DynamicNoPic } else { RelocMode::PIC },
if aot { CodeModel::Default } else { CodeModel::JITDefault },
)
.ok_or_else(|| eyre::eyre!("failed to create target machine"))?;
Expand Down
1 change: 1 addition & 0 deletions crates/revm-jit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ tracing.workspace = true
[dev-dependencies]
revm-jit-context = { workspace = true, features = ["host-ext-any"] }
paste = "1.0"
tempfile = "3.10"

[features]
default = ["llvm"]
Expand Down
3 changes: 3 additions & 0 deletions crates/revm-jit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub use bytecode::*;
mod compiler;
pub use compiler::EvmCompiler;

mod linker;
pub use linker::Linker;

#[cfg(test)]
mod tests;

Expand Down
117 changes: 117 additions & 0 deletions crates/revm-jit/src/linker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use std::path::{Path, PathBuf};

/// EVM bytecode compiler linker.
#[derive(Debug)]
pub struct Linker {
cc: Option<PathBuf>,
}

impl Default for Linker {
fn default() -> Self {
Self::new()
}
}

impl Linker {
/// Creates a new linker.
pub fn new() -> Self {
Self { cc: None }
}

/// Sets the C compiler to use for linking.
pub fn with_cc(mut self, cc: impl Into<PathBuf>) -> Self {
self.cc = Some(cc.into());
self
}

/// Links the given object files into a shared library at the given path.
pub fn link(
&self,
out: &Path,
objects: impl IntoIterator<Item = impl AsRef<std::ffi::OsStr>>,
) -> std::io::Result<()> {
debug_time!("link", || self.link_inner(out, objects))
}

fn link_inner(
&self,
out: &Path,
objects: impl IntoIterator<Item = impl AsRef<std::ffi::OsStr>>,
) -> std::io::Result<()> {
let storage;
let cc = match &self.cc {
Some(cc) => cc,
None => {
let str = match std::env::var_os("CC") {
Some(cc) => {
storage = cc;
storage.as_os_str()
}
None => "cc".as_ref(),
};
Path::new(str)
}
};

let mut cmd = std::process::Command::new(cc);
cmd.arg("-o").arg(out);
cmd.arg("-shared");
cmd.arg("-O3");
if !cfg!(debug_assertions) {
cmd.arg("-Wl,--gc-sections");
cmd.arg("-Wl,--strip-all");
}
// Link libc and the builtins.
cmd.arg("-lc");
// TODO
// cmd.arg("-Ltarget/release/").arg("-lrevm_jit_builtins");
cmd.args(objects);
debug!(?cmd, "linking");
let output = cmd.output()?;
if !output.status.success() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("cc failed with {output:#?}"),
));
}
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use revm_primitives::SpecId;
use std::fs::File;

#[test]
fn basic() {
let tmp = tempfile::tempdir().expect("could not create temp dir");
let obj = tmp.path().join("out.o");
let so = tmp.path().join("out.so");

// Compile and build object file.
let cx = crate::llvm::inkwell::context::Context::create();
let opt_level = revm_jit_backend::OptimizationLevel::Aggressive;
let backend = crate::new_llvm_backend(&cx, true, opt_level).unwrap();
let mut compiler = crate::EvmCompiler::new(backend);
if let Err(e) = compiler.translate(Some("link_test_basic"), &[], SpecId::CANCUN) {
panic!("failed to compile: {e}");
}

{
let mut f = File::create(&obj).unwrap();
if let Err(e) = compiler.write_object(&mut f) {
panic!("failed to write object: {e}");
}
}
assert!(obj.exists());

// Link object to shared library.
let linker = Linker::new();
if let Err(e) = linker.link(&so, [&obj]) {
panic!("failed to link: {e}");
}
assert!(so.exists());
}
}

0 comments on commit 11350d5

Please sign in to comment.