-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
141 additions
and
8 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} |