1use crate::engine::{NativeEngine, NativeEngineInner};
5use crate::serialize::ModuleMetadata;
6use libloading::{Library, Symbol as LibrarySymbol};
7use std::error::Error;
8use std::fs::File;
9use std::io::{Read, Write};
10use std::path::{Path, PathBuf};
11#[cfg(feature = "compiler")]
12use std::process::Command;
13use std::sync::Arc;
14use tempfile::NamedTempFile;
15#[cfg(feature = "compiler")]
16use tracing::trace;
17use wasmer_compiler::{CompileError, Features, OperatingSystem, Symbol, SymbolRegistry, Triple};
18#[cfg(feature = "compiler")]
19use wasmer_compiler::{
20 CompileModuleInfo, FunctionBodyData, ModuleEnvironment, ModuleTranslationState,
21};
22use wasmer_engine::{Artifact, DeserializeError, InstantiationError, SerializeError};
23#[cfg(feature = "compiler")]
24use wasmer_engine::{Engine, Tunables};
25#[cfg(feature = "compiler")]
26use wasmer_object::{emit_compilation, emit_data, get_object_for_target};
27use wasmer_types::entity::{BoxedSlice, PrimaryMap};
28#[cfg(feature = "compiler")]
29use wasmer_types::DataInitializer;
30use wasmer_types::{
31 FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
32 TableIndex,
33};
34use wasmer_vm::{
35 FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody, VMSharedSignatureIndex,
36 VMTrampoline,
37};
38
39pub struct NativeArtifact {
41 sharedobject_path: PathBuf,
42 metadata: ModuleMetadata,
43 finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
44 finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
45 finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
46 signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
47}
48
49fn to_compile_error(err: impl Error) -> CompileError {
50 CompileError::Codegen(format!("{}", err))
51}
52
53const WASMER_METADATA_SYMBOL: &[u8] = b"WASMER_METADATA";
54
55impl NativeArtifact {
56 #[allow(dead_code)]
58 const MAGIC_HEADER_MH_CIGAM_64: &'static [u8] = &[207, 250, 237, 254];
59
60 #[allow(dead_code)]
62 const MAGIC_HEADER_ELF_32: &'static [u8] = &[0x7f, b'E', b'L', b'F', 1];
63
64 #[allow(dead_code)]
66 const MAGIC_HEADER_ELF_64: &'static [u8] = &[0x7f, b'E', b'L', b'F', 2];
67
68 #[allow(dead_code)]
70 const MAGIC_HEADER_COFF_64: &'static [u8] = &[b'M', b'Z'];
71
72 pub fn is_deserializable(bytes: &[u8]) -> bool {
77 cfg_if::cfg_if! {
78 if #[cfg(all(target_pointer_width = "64", target_os="macos"))] {
79 bytes.starts_with(Self::MAGIC_HEADER_MH_CIGAM_64)
80 }
81 else if #[cfg(all(target_pointer_width = "64", target_os="linux"))] {
82 bytes.starts_with(Self::MAGIC_HEADER_ELF_64)
83 }
84 else if #[cfg(all(target_pointer_width = "32", target_os="linux"))] {
85 bytes.starts_with(Self::MAGIC_HEADER_ELF_32)
86 }
87 else if #[cfg(all(target_pointer_width = "64", target_os="windows"))] {
88 bytes.starts_with(Self::MAGIC_HEADER_COFF_64)
89 }
90 else {
91 false
92 }
93 }
94 }
95
96 #[cfg(feature = "compiler")]
97 fn generate_metadata<'data>(
99 data: &'data [u8],
100 features: &Features,
101 tunables: &dyn Tunables,
102 ) -> Result<
103 (
104 CompileModuleInfo,
105 PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
106 Vec<DataInitializer<'data>>,
107 Option<ModuleTranslationState>,
108 ),
109 CompileError,
110 > {
111 let environ = ModuleEnvironment::new();
112 let translation = environ.translate(data).map_err(CompileError::Wasm)?;
113 let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = translation
114 .module
115 .memories
116 .values()
117 .map(|memory_type| tunables.memory_style(memory_type))
118 .collect();
119 let table_styles: PrimaryMap<TableIndex, TableStyle> = translation
120 .module
121 .tables
122 .values()
123 .map(|table_type| tunables.table_style(table_type))
124 .collect();
125
126 let compile_info = CompileModuleInfo {
127 module: Arc::new(translation.module),
128 features: features.clone(),
129 memory_styles,
130 table_styles,
131 };
132 Ok((
133 compile_info,
134 translation.function_body_inputs,
135 translation.data_initializers,
136 translation.module_translation_state,
137 ))
138 }
139
140 #[cfg(feature = "compiler")]
142 pub fn new(
143 engine: &NativeEngine,
144 data: &[u8],
145 tunables: &dyn Tunables,
146 ) -> Result<Self, CompileError> {
147 let mut engine_inner = engine.inner_mut();
148 let target = engine.target();
149 let compiler = engine_inner.compiler()?;
150 let (compile_info, function_body_inputs, data_initializers, module_translation) =
151 Self::generate_metadata(data, engine_inner.features(), tunables)?;
152
153 let data_initializers = data_initializers
154 .iter()
155 .map(OwnedDataInitializer::new)
156 .collect::<Vec<_>>()
157 .into_boxed_slice();
158
159 let target_triple = target.triple();
160
161 let function_body_lengths = function_body_inputs
175 .keys()
176 .map(|_function_body| 0u64)
177 .collect::<PrimaryMap<LocalFunctionIndex, u64>>();
178
179 let mut metadata = ModuleMetadata {
180 compile_info,
181 prefix: engine_inner.get_prefix(&data),
182 data_initializers,
183 function_body_lengths,
184 };
185
186 let serialized_data = bincode::serialize(&metadata).map_err(to_compile_error)?;
187 let mut metadata_binary = vec![0; 10];
188 let mut writable = &mut metadata_binary[..];
189 leb128::write::unsigned(&mut writable, serialized_data.len() as u64)
190 .expect("Should write number");
191 metadata_binary.extend(serialized_data);
192
193 let (mut compile_info, symbol_registry) = metadata.split();
194 let maybe_obj_bytes = compiler.experimental_native_compile_module(
195 &target,
196 &mut compile_info,
197 module_translation.as_ref().unwrap(),
198 &function_body_inputs,
199 &symbol_registry,
200 &metadata_binary,
201 );
202
203 let filepath = match maybe_obj_bytes {
204 Some(obj_bytes) => {
205 let obj_bytes = obj_bytes?;
206 let file = tempfile::Builder::new()
207 .prefix("wasmer_native")
208 .suffix(".o")
209 .tempfile()
210 .map_err(to_compile_error)?;
211
212 let (mut file, filepath) = file.keep().map_err(to_compile_error)?;
214 file.write(&obj_bytes).map_err(to_compile_error)?;
215 filepath
216 }
217 None => {
218 let compilation = compiler.compile_module(
219 &target,
220 &mut compile_info,
221 module_translation.as_ref().unwrap(),
222 function_body_inputs,
223 )?;
224 let mut obj = get_object_for_target(&target_triple).map_err(to_compile_error)?;
225 emit_data(&mut obj, WASMER_METADATA_SYMBOL, &metadata_binary)
226 .map_err(to_compile_error)?;
227 emit_compilation(&mut obj, compilation, &symbol_registry, &target_triple)
228 .map_err(to_compile_error)?;
229 let file = tempfile::Builder::new()
230 .prefix("wasmer_native")
231 .suffix(".o")
232 .tempfile()
233 .map_err(to_compile_error)?;
234
235 let (mut file, filepath) = file.keep().map_err(to_compile_error)?;
237 let obj_bytes = obj.write().map_err(to_compile_error)?;
238
239 file.write(&obj_bytes).map_err(to_compile_error)?;
240 filepath
241 }
242 };
243
244 let shared_filepath = {
245 let suffix = format!(".{}", Self::get_default_extension(&target_triple));
246 let shared_file = tempfile::Builder::new()
247 .prefix("wasmer_native")
248 .suffix(&suffix)
249 .tempfile()
250 .map_err(to_compile_error)?;
251 shared_file
252 .into_temp_path()
253 .keep()
254 .map_err(to_compile_error)?
255 };
256
257 let is_cross_compiling = engine_inner.is_cross_compiling();
258 let target_triple_str = {
259 let into_str = target_triple.to_string();
260 if into_str == "aarch64-apple-darwin" {
263 "arm64-apple-darwin".to_string()
264 } else {
265 into_str
266 }
267 };
268
269 let cross_compiling_args: Vec<String> = if is_cross_compiling {
270 vec![
271 format!("--target={}", target_triple_str),
272 "-fuse-ld=lld".to_string(),
273 "-nodefaultlibs".to_string(),
274 "-nostdlib".to_string(),
275 ]
276 } else {
277 if target_triple_str == "arm64-apple-darwin" {
280 vec![format!("--target={}", target_triple_str)]
281 } else {
282 vec![]
283 }
284 };
285 let target_args = match (target_triple.operating_system, is_cross_compiling) {
286 (OperatingSystem::Windows, true) => vec!["-Wl,/force:unresolved,/noentry"],
287 (OperatingSystem::Windows, false) => vec!["-Wl,-undefined,dynamic_lookup"],
288 _ => vec!["-nostartfiles", "-Wl,-undefined,dynamic_lookup"],
289 };
290 trace!(
291 "Compiling for target {} from host {}",
292 target_triple_str,
293 Triple::host().to_string(),
294 );
295
296 let linker: &'static str = engine_inner.linker().into();
297 let output = Command::new(linker)
298 .arg(&filepath)
299 .arg("-o")
300 .arg(&shared_filepath)
301 .args(&target_args)
302 .arg("-shared")
304 .args(&cross_compiling_args)
305 .arg("-v")
306 .output()
307 .map_err(to_compile_error)?;
308
309 if !output.status.success() {
310 return Err(CompileError::Codegen(format!(
311 "Shared object file generator failed with:\nstderr:{}\nstdout:{}",
312 String::from_utf8_lossy(&output.stderr).trim_end(),
313 String::from_utf8_lossy(&output.stdout).trim_end()
314 )));
315 }
316 trace!("gcc command result {:?}", output);
317 if is_cross_compiling {
318 Self::from_parts_crosscompiled(metadata, shared_filepath)
319 } else {
320 let lib = Library::new(&shared_filepath).map_err(to_compile_error)?;
321 Self::from_parts(&mut engine_inner, metadata, shared_filepath, lib)
322 }
323 }
324
325 pub fn get_default_extension(triple: &Triple) -> &'static str {
327 match triple.operating_system {
328 OperatingSystem::Windows => "dll",
329 OperatingSystem::Darwin | OperatingSystem::Ios | OperatingSystem::MacOSX { .. } => {
330 "dylib"
331 }
332 _ => "so",
333 }
334 }
335
336 pub fn from_parts_crosscompiled(
338 metadata: ModuleMetadata,
339 sharedobject_path: PathBuf,
340 ) -> Result<Self, CompileError> {
341 let finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> = PrimaryMap::new();
342 let finished_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
343 PrimaryMap::new();
344 let finished_dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBodyPtr> =
345 PrimaryMap::new();
346 let signatures: PrimaryMap<SignatureIndex, VMSharedSignatureIndex> = PrimaryMap::new();
347 Ok(Self {
348 sharedobject_path,
349 metadata,
350 finished_functions: finished_functions.into_boxed_slice(),
351 finished_function_call_trampolines: finished_function_call_trampolines
352 .into_boxed_slice(),
353 finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
354 .into_boxed_slice(),
355 signatures: signatures.into_boxed_slice(),
356 })
357 }
358
359 pub fn from_parts(
361 engine_inner: &mut NativeEngineInner,
362 metadata: ModuleMetadata,
363 sharedobject_path: PathBuf,
364 lib: Library,
365 ) -> Result<Self, CompileError> {
366 let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
367 PrimaryMap::new();
368 for (function_local_index, _function_len) in metadata.function_body_lengths.iter() {
369 let function_name = metadata
370 .get_symbol_registry()
371 .symbol_to_name(Symbol::LocalFunction(function_local_index));
372 unsafe {
373 let func: LibrarySymbol<unsafe extern "C" fn()> = lib
376 .get(function_name.as_bytes())
377 .map_err(to_compile_error)?;
378 finished_functions.push(FunctionBodyPtr(
379 func.into_raw().into_raw() as *const VMFunctionBody
380 ));
381 }
382 }
383
384 let mut finished_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
386 PrimaryMap::with_capacity(metadata.compile_info.module.signatures.len());
387 for sig_index in metadata.compile_info.module.signatures.keys() {
388 let function_name = metadata
389 .get_symbol_registry()
390 .symbol_to_name(Symbol::FunctionCallTrampoline(sig_index));
391 unsafe {
392 let trampoline: LibrarySymbol<VMTrampoline> = lib
393 .get(function_name.as_bytes())
394 .map_err(to_compile_error)?;
395 let raw = *trampoline.into_raw();
396 finished_function_call_trampolines.push(raw);
397 }
398 }
399
400 let mut finished_dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBodyPtr> =
402 PrimaryMap::with_capacity(metadata.compile_info.module.num_imported_functions);
403 for func_index in metadata
404 .compile_info
405 .module
406 .functions
407 .keys()
408 .take(metadata.compile_info.module.num_imported_functions)
409 {
410 let function_name = metadata
411 .get_symbol_registry()
412 .symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
413 unsafe {
414 let trampoline: LibrarySymbol<unsafe extern "C" fn()> = lib
415 .get(function_name.as_bytes())
416 .map_err(to_compile_error)?;
417 finished_dynamic_function_trampolines.push(FunctionBodyPtr(
418 trampoline.into_raw().into_raw() as *const VMFunctionBody,
419 ));
420 }
421 }
422
423 let signatures = {
439 metadata
440 .compile_info
441 .module
442 .signatures
443 .values()
444 .map(|sig| engine_inner.signatures().register(sig))
445 .collect::<PrimaryMap<_, _>>()
446 };
447
448 engine_inner.add_library(lib);
449
450 Ok(Self {
451 sharedobject_path,
452 metadata,
453 finished_functions: finished_functions.into_boxed_slice(),
454 finished_function_call_trampolines: finished_function_call_trampolines
455 .into_boxed_slice(),
456 finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
457 .into_boxed_slice(),
458 signatures: signatures.into_boxed_slice(),
459 })
460 }
461
462 #[cfg(not(feature = "compiler"))]
464 pub fn new(_engine: &NativeEngine, _data: &[u8]) -> Result<Self, CompileError> {
465 Err(CompileError::Codegen(
466 "Compilation is not enabled in the engine".to_string(),
467 ))
468 }
469
470 pub unsafe fn deserialize(
476 engine: &NativeEngine,
477 bytes: &[u8],
478 ) -> Result<Self, DeserializeError> {
479 if !Self::is_deserializable(&bytes) {
480 return Err(DeserializeError::Incompatible(
481 "The provided bytes are not in any native format Wasmer can understand".to_string(),
482 ));
483 }
484 let named_file = NamedTempFile::new()?;
486 let (mut file, path) = named_file.keep().map_err(|e| e.error)?;
487 file.write_all(&bytes)?;
488 Self::deserialize_from_file_unchecked(&engine, &path)
491 }
492
493 pub unsafe fn deserialize_from_file(
499 engine: &NativeEngine,
500 path: &Path,
501 ) -> Result<Self, DeserializeError> {
502 let mut file = File::open(&path)?;
503 let mut buffer = [0; 5];
504 file.read_exact(&mut buffer)?;
506 if !Self::is_deserializable(&buffer) {
507 return Err(DeserializeError::Incompatible(
508 "The provided bytes are not in any native format Wasmer can understand".to_string(),
509 ));
510 }
511 Self::deserialize_from_file_unchecked(&engine, &path)
512 }
513
514 pub unsafe fn deserialize_from_file_unchecked(
520 engine: &NativeEngine,
521 path: &Path,
522 ) -> Result<Self, DeserializeError> {
523 let lib = Library::new(&path).map_err(|e| {
524 DeserializeError::CorruptedBinary(format!("Library loading failed: {}", e))
525 })?;
526 let shared_path: PathBuf = PathBuf::from(path);
527 let symbol: LibrarySymbol<*mut [u8; 10 + 1]> =
532 lib.get(WASMER_METADATA_SYMBOL).map_err(|e| {
533 DeserializeError::CorruptedBinary(format!(
534 "The provided object file doesn't seem to be generated by Wasmer: {}",
535 e
536 ))
537 })?;
538 use std::ops::Deref;
539 use std::slice;
540
541 let size = &mut **symbol.deref();
542 let mut readable = &size[..];
543 let metadata_len = leb128::read::unsigned(&mut readable).map_err(|_e| {
544 DeserializeError::CorruptedBinary("Can't read metadata size".to_string())
545 })?;
546 let metadata_slice: &'static [u8] =
547 slice::from_raw_parts(&size[10] as *const u8, metadata_len as usize);
548 let metadata: ModuleMetadata = bincode::deserialize(metadata_slice)
549 .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?;
550 let mut engine_inner = engine.inner_mut();
551
552 Self::from_parts(&mut engine_inner, metadata, shared_path, lib)
553 .map_err(DeserializeError::Compiler)
554 }
555}
556
557impl Artifact for NativeArtifact {
558 fn module(&self) -> Arc<ModuleInfo> {
559 self.metadata.compile_info.module.clone()
560 }
561
562 fn module_ref(&self) -> &ModuleInfo {
563 &self.metadata.compile_info.module
564 }
565
566 fn module_mut(&mut self) -> Option<&mut ModuleInfo> {
567 Arc::get_mut(&mut self.metadata.compile_info.module)
568 }
569
570 fn register_frame_info(&self) {
571 }
573
574 fn features(&self) -> &Features {
575 &self.metadata.compile_info.features
576 }
577
578 fn data_initializers(&self) -> &[OwnedDataInitializer] {
579 &*self.metadata.data_initializers
580 }
581
582 fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
583 &self.metadata.compile_info.memory_styles
584 }
585
586 fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
587 &self.metadata.compile_info.table_styles
588 }
589
590 fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
591 &self.finished_functions
592 }
593
594 fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
595 &self.finished_function_call_trampolines
596 }
597
598 fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
599 &self.finished_dynamic_function_trampolines
600 }
601
602 fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex> {
603 &self.signatures
604 }
605
606 fn preinstantiate(&self) -> Result<(), InstantiationError> {
607 Ok(())
608 }
609
610 fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
612 Ok(std::fs::read(&self.sharedobject_path)?)
613 }
614}