mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-29 00:47:58 +00:00
89 lines
2.8 KiB
Rust
89 lines
2.8 KiB
Rust
use std::{env, ffi::CString, fs};
|
|
|
|
use lld_sys::LLDELFLink;
|
|
use revive_builtins::COMPILER_RT;
|
|
|
|
const LINKER_SCRIPT: &str = r#"
|
|
SECTIONS {
|
|
.text : { KEEP(*(.text.polkavm_export)) *(.text .text.*) }
|
|
}"#;
|
|
|
|
#[cfg(not(feature = "riscv-64"))]
|
|
const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv32.a";
|
|
#[cfg(feature = "riscv-64")]
|
|
const BUILTINS_ARCHIVE_FILE: &str = "libclang_rt.builtins-riscv64.a";
|
|
|
|
#[cfg(not(feature = "riscv-64"))]
|
|
const BUILTINS_LIB_NAME: &str = "clang_rt.builtins-riscv32";
|
|
#[cfg(feature = "riscv-64")]
|
|
const BUILTINS_LIB_NAME: &str = "clang_rt.builtins-riscv64";
|
|
|
|
fn invoke_lld(cmd_args: &[&str]) -> bool {
|
|
let c_strings = cmd_args
|
|
.iter()
|
|
.map(|arg| CString::new(*arg).expect("ld.lld args should not contain null bytes"))
|
|
.collect::<Vec<_>>();
|
|
|
|
let args: Vec<*const libc::c_char> = c_strings.iter().map(|arg| arg.as_ptr()).collect();
|
|
|
|
unsafe { LLDELFLink(args.as_ptr(), args.len()) == 0 }
|
|
}
|
|
|
|
fn polkavm_linker<T: AsRef<[u8]>>(code: T) -> anyhow::Result<Vec<u8>> {
|
|
let mut config = polkavm_linker::Config::default();
|
|
config.set_strip(true);
|
|
config.set_optimize(true);
|
|
|
|
polkavm_linker::program_from_elf(config, code.as_ref())
|
|
.map_err(|reason| anyhow::anyhow!("polkavm linker failed: {}", reason))
|
|
}
|
|
|
|
pub fn link<T: AsRef<[u8]>>(input: T) -> anyhow::Result<Vec<u8>> {
|
|
let dir = tempfile::tempdir().expect("failed to create temp directory for linking");
|
|
let output_path = dir.path().join("out.so");
|
|
let object_path = dir.path().join("out.o");
|
|
let linker_script_path = dir.path().join("linker.ld");
|
|
let compiler_rt_path = dir.path().join(BUILTINS_ARCHIVE_FILE);
|
|
|
|
fs::write(&object_path, input).map_err(|msg| anyhow::anyhow!("{msg} {object_path:?}"))?;
|
|
|
|
if env::var("PVM_LINKER_DUMP_OBJ").is_ok() {
|
|
fs::copy(&object_path, "/tmp/out.o")?;
|
|
}
|
|
|
|
fs::write(&linker_script_path, LINKER_SCRIPT)
|
|
.map_err(|msg| anyhow::anyhow!("{msg} {linker_script_path:?}"))?;
|
|
|
|
fs::write(&compiler_rt_path, COMPILER_RT)
|
|
.map_err(|msg| anyhow::anyhow!("{msg} {compiler_rt_path:?}"))?;
|
|
|
|
let ld_args = [
|
|
"ld.lld",
|
|
"--lto=full",
|
|
"--error-limit=0",
|
|
"--relocatable",
|
|
"--emit-relocs",
|
|
"--no-relax",
|
|
"--gc-sections",
|
|
"--library-path",
|
|
dir.path().to_str().expect("should be utf8"),
|
|
"--library",
|
|
BUILTINS_LIB_NAME,
|
|
linker_script_path.to_str().expect("should be utf8"),
|
|
object_path.to_str().expect("should be utf8"),
|
|
"-o",
|
|
output_path.to_str().expect("should be utf8"),
|
|
];
|
|
|
|
if invoke_lld(&ld_args) {
|
|
return Err(anyhow::anyhow!("ld.lld failed"));
|
|
}
|
|
|
|
if env::var("PVM_LINKER_DUMP_SO").is_ok() {
|
|
fs::copy(&output_path, "/tmp/out.so")?;
|
|
};
|
|
|
|
let blob = fs::read(&output_path)?;
|
|
polkavm_linker(blob)
|
|
}
|