diff --git a/Cargo.toml b/Cargo.toml index 40de92d..9773dd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" license = "MIT" authors = ["Nervos Core Dev "] edition = "2018" +build = "build.rs" [lib] crate-type = ["lib", "staticlib", "cdylib"] @@ -18,3 +19,6 @@ lazy_static = "1.4" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" + +[build-dependencies] +cc = "1.0" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..23d37c2 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + cc::Build::new().file("src/dlopen.c").compile("dlopen"); +} diff --git a/src/dlopen.c b/src/dlopen.c new file mode 100644 index 0000000..6b6aa35 --- /dev/null +++ b/src/dlopen.c @@ -0,0 +1,27 @@ +#include +#include + +#define ERROR_MEMORY_NOT_ENOUGH -23 +#define ERROR_DYNAMIC_LOADING -24 +#define RISCV_PGSIZE 4096 +#define ROUNDUP(a, b) ((((a)-1) / (b) + 1) * (b)) + +int simulator_internal_dlopen2(const char* native_library_path, + const uint8_t* code, size_t length, + uint8_t* aligned_addr, size_t aligned_size, + void** handle, size_t* consumed_size) { + /* TODO: parse ELF and consume proper pages */ + (void)code; + (void)aligned_addr; + size_t aligned_length = ROUNDUP(length, RISCV_PGSIZE); + if (aligned_size < aligned_length) { + return ERROR_MEMORY_NOT_ENOUGH; + } + *consumed_size = aligned_length; + *handle = dlopen(native_library_path, RTLD_NOW); + return -1; +} + +void* ckb_dlsym(void* handle, const char* symbol) { + return dlsym(handle, symbol); +} diff --git a/src/lib.rs b/src/lib.rs index 41fbce1..ebb99fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ use constants::{ SOURCE_GROUP_OUTPUT, SOURCE_HEADER_DEP, SOURCE_INPUT, SOURCE_OUTPUT, }; use serde_derive::{Deserialize, Serialize}; +use std::collections::HashMap; use std::ffi::CStr; use std::os::raw::{c_char, c_int, c_void}; @@ -27,6 +28,7 @@ pub struct RunningSetup { pub is_lock_script: bool, pub is_output: bool, pub script_index: u64, + pub native_binaries: HashMap, String>, } lazy_static! { @@ -279,6 +281,69 @@ pub extern "C" fn ckb_load_cell_data( CKB_SUCCESS } +extern "C" { + fn simulator_internal_dlopen2( + native_library_path: *const u8, + code: *const u8, + length: u64, + aligned_addr: *mut u8, + aligned_size: u64, + handle: *mut *mut c_void, + consumed_size: *mut u64, + ) -> c_int; +} + +#[no_mangle] +pub extern "C" fn ckb_dlopen2( + dep_cell_hash: *const u8, + hash_type: u8, + aligned_addr: *mut u8, + aligned_size: u64, + handle: *mut *mut c_void, + consumed_size: *mut u64, +) -> c_int { + let dep_cell_hash = unsafe { + let ptr = dep_cell_hash.as_ref().expect("casting pointer"); + std::slice::from_raw_parts(ptr, 32) + }; + let mut buffer = vec![]; + buffer.extend_from_slice(dep_cell_hash); + buffer.push(hash_type); + let filename = SETUP + .native_binaries + .get(&buffer) + .expect("cannot locate native binary!"); + let cell_dep = TRANSACTION + .mock_info + .cell_deps + .iter() + .find(|cell_dep| { + if hash_type == 1 { + cell_dep + .output + .type_() + .to_opt() + .map(|t| t.calc_script_hash().as_slice() == dep_cell_hash) + .unwrap_or(false) + } else { + CellOutput::calc_data_hash(&cell_dep.data).as_slice() == dep_cell_hash + } + }) + .expect("cannot locate cell dep"); + let cell_data = cell_dep.data.as_ref(); + unsafe { + simulator_internal_dlopen2( + filename.as_str().as_ptr(), + cell_data.as_ptr(), + cell_data.len() as u64, + aligned_addr, + aligned_size, + handle, + consumed_size, + ) + } +} + fn fetch_cell(index: u64, source: u64) -> Result<(CellOutput, Bytes), c_int> { match source { SOURCE_INPUT => TRANSACTION