Initial reorg.
This is largely the same as #305, but updated for the current tree.
This commit is contained in:
93
crates/obj/src/context.rs
Normal file
93
crates/obj/src/context.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
#![allow(clippy::cast_ptr_alignment)]
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::ptr;
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm::GlobalInit;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use wasmtime_environ::{Module, TargetSharedSignatureIndex, VMOffsets};
|
||||
|
||||
pub struct TableRelocation {
|
||||
pub index: usize,
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
pub fn layout_vmcontext(
|
||||
module: &Module,
|
||||
target_config: &TargetFrontendConfig,
|
||||
) -> (Box<[u8]>, Box<[TableRelocation]>) {
|
||||
let ofs = VMOffsets::new(target_config.pointer_bytes(), &module);
|
||||
let out_len = ofs.size_of_vmctx() as usize;
|
||||
let mut out = vec![0; out_len];
|
||||
|
||||
// Assign unique indicies to unique signatures.
|
||||
let mut signature_registry = HashMap::new();
|
||||
let mut signature_registry_len = signature_registry.len();
|
||||
for (index, sig) in module.signatures.iter() {
|
||||
let offset = ofs.vmctx_vmshared_signature_id(index) as usize;
|
||||
let target_index = match signature_registry.entry(sig) {
|
||||
Entry::Occupied(o) => *o.get(),
|
||||
Entry::Vacant(v) => {
|
||||
assert!(signature_registry_len <= ::core::u32::MAX as usize);
|
||||
let id = TargetSharedSignatureIndex::new(signature_registry_len as u32);
|
||||
signature_registry_len += 1;
|
||||
*v.insert(id)
|
||||
}
|
||||
};
|
||||
unsafe {
|
||||
let to = out.as_mut_ptr().add(offset) as *mut TargetSharedSignatureIndex;
|
||||
ptr::write(to, target_index);
|
||||
}
|
||||
}
|
||||
|
||||
let num_tables_imports = module.imported_tables.len();
|
||||
let mut table_relocs = Vec::with_capacity(module.table_plans.len() - num_tables_imports);
|
||||
for (index, table) in module.table_plans.iter().skip(num_tables_imports) {
|
||||
let def_index = module.defined_table_index(index).unwrap();
|
||||
let offset = ofs.vmctx_vmtable_definition(def_index) as usize;
|
||||
let current_elements = table.table.minimum;
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<u32>() as u8,
|
||||
ofs.size_of_vmtable_definition_current_elements(),
|
||||
"vmtable_definition_current_elements expected to be u32"
|
||||
);
|
||||
let to = out
|
||||
.as_mut_ptr()
|
||||
.add(offset)
|
||||
.add(ofs.vmtable_definition_current_elements() as usize);
|
||||
ptr::write(to as *mut u32, current_elements);
|
||||
}
|
||||
table_relocs.push(TableRelocation {
|
||||
index: def_index.index(),
|
||||
offset,
|
||||
});
|
||||
}
|
||||
|
||||
let num_globals_imports = module.imported_globals.len();
|
||||
for (index, global) in module.globals.iter().skip(num_globals_imports) {
|
||||
let def_index = module.defined_global_index(index).unwrap();
|
||||
let offset = ofs.vmctx_vmglobal_definition(def_index) as usize;
|
||||
let to = unsafe { out.as_mut_ptr().add(offset) };
|
||||
match global.initializer {
|
||||
GlobalInit::I32Const(x) => unsafe {
|
||||
ptr::write(to as *mut i32, x);
|
||||
},
|
||||
GlobalInit::I64Const(x) => unsafe {
|
||||
ptr::write(to as *mut i64, x);
|
||||
},
|
||||
GlobalInit::F32Const(x) => unsafe {
|
||||
ptr::write(to as *mut u32, x);
|
||||
},
|
||||
GlobalInit::F64Const(x) => unsafe {
|
||||
ptr::write(to as *mut u64, x);
|
||||
},
|
||||
_ => panic!("unsupported global type"),
|
||||
}
|
||||
}
|
||||
|
||||
(out.into_boxed_slice(), table_relocs.into_boxed_slice())
|
||||
}
|
||||
28
crates/obj/src/data_segment.rs
Normal file
28
crates/obj/src/data_segment.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use faerie::{Artifact, Decl};
|
||||
use wasmtime_environ::DataInitializer;
|
||||
|
||||
/// Declares data segment symbol
|
||||
pub fn declare_data_segment(
|
||||
obj: &mut Artifact,
|
||||
_data_initaliazer: &DataInitializer,
|
||||
index: usize,
|
||||
) -> Result<(), String> {
|
||||
let name = format!("_memory_{}", index);
|
||||
obj.declare(name, Decl::data())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emit segment data and initialization location
|
||||
pub fn emit_data_segment(
|
||||
obj: &mut Artifact,
|
||||
data_initaliazer: &DataInitializer,
|
||||
index: usize,
|
||||
) -> Result<(), String> {
|
||||
let name = format!("_memory_{}", index);
|
||||
obj.define(name, Vec::from(data_initaliazer.data))
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
Ok(())
|
||||
}
|
||||
109
crates/obj/src/function.rs
Normal file
109
crates/obj/src/function.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use alloc::string::String;
|
||||
use cranelift_codegen::settings;
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
use cranelift_entity::EntityRef;
|
||||
use faerie::{Artifact, Decl, Link};
|
||||
use wasmtime_environ::{Compilation, Module, RelocationTarget, Relocations};
|
||||
|
||||
fn get_reloc_target_special_import_name(target: RelocationTarget) -> Option<&'static str> {
|
||||
Some(match target {
|
||||
RelocationTarget::Memory32Grow => &"wasmtime_memory32_grow",
|
||||
RelocationTarget::ImportedMemory32Grow => &"wasmtime_memory32_grow",
|
||||
RelocationTarget::Memory32Size => &"wasmtime_memory32_size",
|
||||
RelocationTarget::ImportedMemory32Size => &"wasmtime_imported_memory32_size",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Defines module functions
|
||||
pub fn declare_functions(
|
||||
obj: &mut Artifact,
|
||||
module: &Module,
|
||||
relocations: &Relocations,
|
||||
) -> Result<(), String> {
|
||||
for i in 0..module.imported_funcs.len() {
|
||||
let string_name = format!("_wasm_function_{}", i);
|
||||
obj.declare(string_name, Decl::function_import())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
for (_, function_relocs) in relocations.iter() {
|
||||
for r in function_relocs {
|
||||
let special_import_name = get_reloc_target_special_import_name(r.reloc_target);
|
||||
if let Some(special_import_name) = special_import_name {
|
||||
obj.declare(special_import_name, Decl::function_import())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i, _function_relocs) in relocations.iter().rev() {
|
||||
let func_index = module.func_index(i);
|
||||
let string_name = format!("_wasm_function_{}", func_index.index());
|
||||
obj.declare(string_name, Decl::function().global())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits module functions
|
||||
pub fn emit_functions(
|
||||
obj: &mut Artifact,
|
||||
module: &Module,
|
||||
compilation: &Compilation,
|
||||
relocations: &Relocations,
|
||||
) -> Result<(), String> {
|
||||
debug_assert!(
|
||||
module.start_func.is_none()
|
||||
|| module.start_func.unwrap().index() >= module.imported_funcs.len(),
|
||||
"imported start functions not supported yet"
|
||||
);
|
||||
|
||||
let mut shared_builder = settings::builder();
|
||||
shared_builder
|
||||
.enable("enable_verifier")
|
||||
.expect("Missing enable_verifier setting");
|
||||
|
||||
for (i, _function_relocs) in relocations.iter() {
|
||||
let body = &compilation.get(i).body;
|
||||
let func_index = module.func_index(i);
|
||||
let string_name = format!("_wasm_function_{}", func_index.index());
|
||||
|
||||
obj.define(string_name, body.clone())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
|
||||
for (i, function_relocs) in relocations.iter() {
|
||||
let func_index = module.func_index(i);
|
||||
let string_name = format!("_wasm_function_{}", func_index.index());
|
||||
for r in function_relocs {
|
||||
debug_assert_eq!(r.addend, 0);
|
||||
match r.reloc_target {
|
||||
RelocationTarget::UserFunc(target_index) => {
|
||||
let target_name = format!("_wasm_function_{}", target_index.index());
|
||||
obj.link(Link {
|
||||
from: &string_name,
|
||||
to: &target_name,
|
||||
at: r.offset as u64,
|
||||
})
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
RelocationTarget::Memory32Grow
|
||||
| RelocationTarget::ImportedMemory32Grow
|
||||
| RelocationTarget::Memory32Size
|
||||
| RelocationTarget::ImportedMemory32Size => {
|
||||
obj.link(Link {
|
||||
from: &string_name,
|
||||
to: get_reloc_target_special_import_name(r.reloc_target).expect("name"),
|
||||
at: r.offset as u64,
|
||||
})
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
RelocationTarget::JumpTable(_, _) => {
|
||||
// ignore relocations for jump tables
|
||||
}
|
||||
_ => panic!("relocations target not supported yet: {:?}", r.reloc_target),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
40
crates/obj/src/lib.rs
Normal file
40
crates/obj/src/lib.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
//! Object-file writing library using the wasmtime environment.
|
||||
|
||||
#![deny(
|
||||
missing_docs,
|
||||
trivial_numeric_casts,
|
||||
unused_extern_crates,
|
||||
unstable_features
|
||||
)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(clippy::new_without_default, clippy::new_without_default_derive)
|
||||
)]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod context;
|
||||
mod data_segment;
|
||||
mod function;
|
||||
mod module;
|
||||
mod table;
|
||||
|
||||
pub use crate::module::emit_module;
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
63
crates/obj/src/module.rs
Normal file
63
crates/obj/src/module.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use crate::context::layout_vmcontext;
|
||||
use crate::data_segment::{declare_data_segment, emit_data_segment};
|
||||
use crate::function::{declare_functions, emit_functions};
|
||||
use crate::table::{declare_table, emit_table};
|
||||
use alloc::string::String;
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
use faerie::{Artifact, Decl, Link};
|
||||
use wasmtime_environ::{Compilation, DataInitializer, Module, Relocations};
|
||||
|
||||
fn emit_vmcontext_init(
|
||||
obj: &mut Artifact,
|
||||
module: &Module,
|
||||
target_config: &TargetFrontendConfig,
|
||||
) -> Result<(), String> {
|
||||
let (data, table_relocs) = layout_vmcontext(module, target_config);
|
||||
obj.declare_with("_vmcontext_init", Decl::data().global(), data.to_vec())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
for reloc in table_relocs.iter() {
|
||||
let target_name = format!("_table_{}", reloc.index);
|
||||
obj.link(Link {
|
||||
from: "_vmcontext_init",
|
||||
to: &target_name,
|
||||
at: reloc.offset as u64,
|
||||
})
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a module that has been emitted with the `wasmtime-environ` environment
|
||||
/// implementation to a native object file.
|
||||
pub fn emit_module(
|
||||
obj: &mut Artifact,
|
||||
module: &Module,
|
||||
compilation: &Compilation,
|
||||
relocations: &Relocations,
|
||||
data_initializers: &[DataInitializer],
|
||||
target_config: &TargetFrontendConfig,
|
||||
) -> Result<(), String> {
|
||||
declare_functions(obj, module, relocations)?;
|
||||
|
||||
for i in 0..data_initializers.len() {
|
||||
declare_data_segment(obj, &data_initializers[i], i)?;
|
||||
}
|
||||
|
||||
for i in 0..module.table_plans.len() {
|
||||
declare_table(obj, i)?;
|
||||
}
|
||||
|
||||
emit_functions(obj, module, compilation, relocations)?;
|
||||
|
||||
for i in 0..data_initializers.len() {
|
||||
emit_data_segment(obj, &data_initializers[i], i)?;
|
||||
}
|
||||
|
||||
for i in 0..module.table_plans.len() {
|
||||
emit_table(obj, i)?;
|
||||
}
|
||||
|
||||
emit_vmcontext_init(obj, module, target_config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
20
crates/obj/src/table.rs
Normal file
20
crates/obj/src/table.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use faerie::{Artifact, Decl};
|
||||
|
||||
/// Declares data segment symbol
|
||||
pub fn declare_table(obj: &mut Artifact, index: usize) -> Result<(), String> {
|
||||
let name = format!("_table_{}", index);
|
||||
obj.declare(name, Decl::data())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emit segment data and initialization location
|
||||
pub fn emit_table(obj: &mut Artifact, index: usize) -> Result<(), String> {
|
||||
let name = format!("_table_{}", index);
|
||||
// FIXME: We need to initialize table using function symbols
|
||||
obj.define(name, Vec::new())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user