1#![allow(clippy::result_large_err)]
260
261use std::{
262 borrow::Cow,
263 collections::{BTreeMap, HashMap},
264 ffi::OsStr,
265 ops::{Deref, DerefMut},
266 path::{Path, PathBuf},
267 sync::{
268 Arc, Barrier, Mutex, MutexGuard, RwLock, RwLockWriteGuard, TryLockError,
269 atomic::{AtomicBool, Ordering},
270 },
271};
272
273use bus::Bus;
274use derive_more::Debug;
275use shared_buffer::OwnedBuffer;
276use tracing::trace;
277use virtual_fs::{AsyncReadExt, FileSystem, FsError};
278use virtual_mio::InlineWaker;
279use wasmer::{
280 AsStoreMut, AsStoreRef, Engine, ExportError, Exportable, Extern, ExternType, Function,
281 FunctionEnv, FunctionEnvMut, FunctionType, Global, GlobalType, ImportType, Imports, Instance,
282 InstantiationError, Memory, MemoryError, Module, RuntimeError, StoreMut, Table, Tag, Type,
283 Value, WASM_PAGE_SIZE, WasmTypeList,
284};
285use wasmer_wasix_types::wasix::WasiMemoryLayout;
286
287use crate::{
288 Runtime, SpawnError, WasiEnv, WasiError, WasiFs, WasiFunctionEnv, WasiModuleTreeHandles,
289 WasiProcess, WasiThreadId, fs::WasiFsRoot, import_object_for_all_wasi_versions,
290 runtime::module_cache::HashedModuleData,
291};
292
293use super::{WasiModuleInstanceHandles, WasiState};
294
295pub static MAIN_MODULE_HANDLE: ModuleHandle = ModuleHandle(1);
297static INVALID_MODULE_HANDLE: ModuleHandle = ModuleHandle(u32::MAX);
298
299static MAIN_MODULE_MEMORY_BASE: u64 = 0;
300static MAIN_MODULE_TABLE_BASE: u64 = 1;
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
304pub struct ModuleHandle(u32);
305
306impl From<ModuleHandle> for u32 {
307 fn from(handle: ModuleHandle) -> Self {
308 handle.0
309 }
310}
311
312impl From<u32> for ModuleHandle {
313 fn from(handle: u32) -> Self {
314 ModuleHandle(handle)
315 }
316}
317
318const DEFAULT_RUNTIME_PATH: [&str; 3] = ["/lib", "/usr/lib", "/usr/local/lib"];
319
320struct AllocatedPage {
321 base_ptr: u32,
323
324 remaining: u32,
327}
328
329struct MemoryAllocator {
334 allocated_pages: Vec<AllocatedPage>,
335}
336
337impl MemoryAllocator {
338 pub fn new() -> Self {
339 Self {
340 allocated_pages: vec![],
341 }
342 }
343
344 pub fn allocate(
345 &mut self,
346 memory: &Memory,
347 store: &mut impl AsStoreMut,
348 size: u32,
349 alignment: u32,
350 ) -> Result<u32, MemoryError> {
351 match self.allocate_in_existing_pages(size, alignment) {
352 Some(base_ptr) => Ok(base_ptr),
353 None => self.allocate_new_page(memory, store, size),
354 }
355 }
356
357 fn allocate_in_existing_pages(&mut self, size: u32, alignment: u32) -> Option<u32> {
360 struct CandidatePage {
364 index: usize,
365 base_ptr: u32,
366 to_add: u32,
367 remaining_free: u32,
368 }
369
370 impl PartialEq for CandidatePage {
371 fn eq(&self, other: &Self) -> bool {
372 self.remaining_free == other.remaining_free
373 }
374 }
375
376 impl Eq for CandidatePage {}
377
378 impl PartialOrd for CandidatePage {
379 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
380 Some(self.cmp(other))
381 }
382 }
383
384 impl Ord for CandidatePage {
385 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
386 self.remaining_free.cmp(&other.remaining_free)
387 }
388 }
389
390 let mut candidates = std::collections::BinaryHeap::new();
391
392 for (index, page) in self.allocated_pages.iter().enumerate() {
393 let offset = if page.base_ptr % alignment == 0 {
395 0
396 } else {
397 alignment - (page.base_ptr % alignment)
398 };
399
400 if page.remaining >= offset + size {
401 candidates.push(std::cmp::Reverse(CandidatePage {
402 index,
403 base_ptr: page.base_ptr + offset,
404 to_add: offset + size,
405 remaining_free: page.remaining - offset - size,
406 }));
407 }
408 }
409
410 candidates.pop().map(|elected| {
411 let page = &mut self.allocated_pages[elected.0.index];
412
413 trace!(
414 free = page.remaining,
415 base_ptr = elected.0.base_ptr,
416 "Found existing memory page with sufficient space"
417 );
418
419 page.base_ptr += elected.0.to_add;
420 page.remaining -= elected.0.to_add;
421 elected.0.base_ptr
422 })
423 }
424
425 fn allocate_new_page(
426 &mut self,
427 memory: &Memory,
428 store: &mut impl AsStoreMut,
429 size: u32,
430 ) -> Result<u32, MemoryError> {
431 let to_grow = size.div_ceil(WASM_PAGE_SIZE as u32);
433 let pages = memory.grow(store, to_grow)?;
434
435 let base_ptr = pages.0 * WASM_PAGE_SIZE as u32;
436 let total_allocated = to_grow * WASM_PAGE_SIZE as u32;
437
438 if total_allocated > size {
440 self.allocated_pages.push(AllocatedPage {
441 base_ptr: base_ptr + size,
442 remaining: total_allocated - size,
443 });
444 }
445
446 trace!(
447 page_count = to_grow,
448 size, base_ptr, "Allocated new memory page(s) to accommodate requested memory"
449 );
450
451 Ok(base_ptr)
452 }
453}
454
455#[derive(thiserror::Error, Debug)]
456pub enum LinkError {
457 #[error("Cannot access linker through a dead instance group")]
458 InstanceGroupIsDead,
459
460 #[error("Main module is missing a required import: {0}")]
461 MissingMainModuleImport(String),
462
463 #[error("Failed to spawn module: {0}")]
464 SpawnError(#[from] SpawnError),
465
466 #[error("Failed to instantiate module: {0}")]
467 InstantiationError(#[from] InstantiationError),
468
469 #[error("Memory allocation error: {0}")]
470 MemoryAllocationError(#[from] MemoryError),
471
472 #[error("Failed to allocate function table indices: {0}")]
473 TableAllocationError(RuntimeError),
474
475 #[error("Failed to find shared library {0}: {1}")]
476 SharedLibraryMissing(String, LocateModuleError),
477
478 #[error("Module is not a dynamic library")]
479 NotDynamicLibrary,
480
481 #[error("Failed to parse dylink.0 section: {0}")]
482 Dylink0SectionParseError(#[from] wasmparser::BinaryReaderError),
483
484 #[error("Unresolved global '{0}'.{1} due to: {2}")]
485 UnresolvedGlobal(String, String, Box<ResolveError>),
486
487 #[error("Failed to update global {0} due to: {1}")]
488 GlobalUpdateFailed(String, RuntimeError),
489
490 #[error("Expected global to be of type I32 or I64: '{0}'.{1}")]
491 NonIntegerGlobal(String, String),
492
493 #[error("Bad known import: '{0}'.{1} of type {2:?}")]
494 BadImport(String, String, ExternType),
495
496 #[error(
497 "Import could not be satisfied because of type mismatch: '{0}'.{1}, expected {2:?}, found {3:?}"
498 )]
499 ImportTypeMismatch(String, String, ExternType, ExternType),
500
501 #[error("Expected import to be a function: '{0}'.{1}")]
502 ImportMustBeFunction(&'static str, String),
503
504 #[error("Expected export {0} to be a function, found: {1:?}")]
505 ExportMustBeFunction(String, ExternType),
506
507 #[error("Failed to initialize instance: {0}")]
508 InitializationError(anyhow::Error),
509
510 #[error("Initialization function has invalid signature: {0}")]
511 InitFuncWithInvalidSignature(String),
512
513 #[error("Initialization function {0} failed to run: {1}")]
514 InitFunctionFailed(String, RuntimeError),
515
516 #[error("Failed to initialize WASI(X) module handles: {0}")]
517 MainModuleHandleInitFailed(ExportError),
518
519 #[error("Dynamic function index {0} was not allocated via `allocate_function`")]
520 DynamicFunctionIndexNotAllocated(u32),
521}
522
523#[derive(Debug)]
524pub enum LocateModuleError {
525 Single(FsError),
526 Multiple(Vec<(PathBuf, FsError)>),
527}
528
529impl std::fmt::Display for LocateModuleError {
530 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
531 match self {
532 LocateModuleError::Single(e) => std::fmt::Display::fmt(&e, f),
533 LocateModuleError::Multiple(errors) => {
534 for (path, error) in errors {
535 write!(f, "\n {}: {}", path.display(), error)?;
536 }
537 Ok(())
538 }
539 }
540 }
541}
542
543#[derive(Debug)]
544enum PartiallyResolvedExport {
545 Function(Function),
546 Global(u64),
547 Tls {
548 offset: u64,
551 final_addr: u64,
553 },
554}
555
556pub enum ResolvedExport {
557 Function { func_ptr: u64 },
558
559 Global { data_ptr: u64 },
562}
563
564#[derive(thiserror::Error, Debug)]
565pub enum ResolveError {
566 #[error("Linker not initialized")]
567 NotInitialized,
568
569 #[error("Invalid module handle")]
570 InvalidModuleHandle,
571
572 #[error("Missing export")]
573 MissingExport,
574
575 #[error("Invalid export type: {0:?}")]
576 InvalidExportType(ExternType),
577
578 #[error("Failed to allocate function table indices: {0}")]
579 TableAllocationError(RuntimeError),
580
581 #[error("Cannot access linker through a dead instance group")]
582 InstanceGroupIsDead,
583
584 #[error("Failed to perform pending DL operation: {0}")]
585 PendingDlOperationFailed(#[from] LinkError),
586
587 #[error(
588 "Tried to resolve a tls symbol from a module that did not initialize thread local storage"
589 )]
590 TlsSymbolWithoutTls,
591}
592
593#[derive(Debug, Clone)]
594pub struct DylinkInfo {
595 pub mem_info: wasmparser::MemInfo,
596 pub needed: Vec<String>,
597 pub import_metadata: HashMap<(String, String), wasmparser::SymbolFlags>,
598 pub export_metadata: HashMap<String, wasmparser::SymbolFlags>,
599 pub runtime_path: Vec<String>,
600}
601
602pub struct LinkedMainModule {
603 pub instance: Instance,
604 pub memory: Memory,
605 pub indirect_function_table: Table,
606 pub stack_low: u64,
607 pub stack_high: u64,
608}
609
610#[derive(Debug)]
611enum UnresolvedGlobal {
612 Mem(NeededSymbolResolutionKey, Global),
614 Func(NeededSymbolResolutionKey, Global),
617}
618
619impl UnresolvedGlobal {
620 fn key(&self) -> &NeededSymbolResolutionKey {
621 match self {
622 Self::Func(key, _) => key,
623 Self::Mem(key, _) => key,
624 }
625 }
626
627 fn global(&self) -> &Global {
628 match self {
629 Self::Func(_, global) => global,
630 Self::Mem(_, global) => global,
631 }
632 }
633
634 fn import_module(&self) -> &str {
635 match self {
636 Self::Func(..) => "GOT.func",
637 Self::Mem(..) => "GOT.mem",
638 }
639 }
640}
641
642#[derive(Debug)]
643struct PendingFunctionResolutionFromLinkerState {
644 resolved_from: ModuleHandle,
645 name: String,
646 function_table_index: u32,
647}
648
649#[derive(Debug)]
650struct PendingTlsPointer {
651 global: Global,
652 resolved_from: ModuleHandle,
653 offset: u64,
654}
655
656#[derive(Debug, Default)]
667struct PendingResolutionsFromLinker {
668 functions: Vec<PendingFunctionResolutionFromLinkerState>,
669 tls: Vec<PendingTlsPointer>,
670}
671
672#[derive(Debug, Clone, PartialEq, Eq, Hash)]
673pub struct NeededSymbolResolutionKey {
674 module_handle: ModuleHandle,
675 import_module: String,
680 import_name: String,
681}
682
683#[derive(Debug)]
684enum InProgressSymbolResolution {
685 Function(ModuleHandle),
686 StubFunction(FunctionType),
687 MemGlobal(ModuleHandle),
689 FuncGlobal(ModuleHandle),
690 UnresolvedMemGlobal,
691 UnresolvedFuncGlobal,
692}
693
694#[derive(Debug)]
695struct InProgressModuleLoad {
696 handle: ModuleHandle,
697 module: Module,
698 dylink_info: DylinkInfo,
699}
700
701#[derive(Default, Debug)]
702struct InProgressLinkState {
703 new_modules: Vec<InProgressModuleLoad>,
705
706 pending_module_paths: Vec<PathBuf>,
708
709 symbols: HashMap<NeededSymbolResolutionKey, InProgressSymbolResolution>,
713
714 unresolved_globals: Vec<UnresolvedGlobal>,
715}
716
717#[derive(Debug, Clone, PartialEq, Eq, Hash)]
718pub enum SymbolResolutionKey {
719 Needed(NeededSymbolResolutionKey),
720 Requested {
721 resolve_from: Option<ModuleHandle>,
727 name: String,
728 },
729}
730
731#[derive(Debug)]
732pub enum SymbolResolutionResult {
733 Memory(u64),
739 Tls {
743 resolved_from: ModuleHandle,
744 offset: u64,
745 },
746 Function {
749 ty: FunctionType,
750 resolved_from: ModuleHandle,
751 },
752 FunctionPointer {
754 resolved_from: ModuleHandle,
755 function_table_index: u32,
756 },
757 StubFunction(FunctionType),
761}
762
763#[derive(Debug, Clone)]
766enum DlOperation {
767 LoadModules(Vec<ModuleHandle>),
768 ResolveFunction {
769 name: String,
770 resolved_from: ModuleHandle,
771 function_table_index: u32,
774 },
775 AllocateFunctionTable {
777 index: u32,
778 size: u32,
779 },
780}
781
782struct DlModule {
783 module: Module,
784 dylink_info: DylinkInfo,
785 memory_base: u64,
786 table_base: u64,
787}
788
789struct DlInstance {
790 instance: Instance,
791 #[allow(dead_code)]
792 instance_handles: WasiModuleInstanceHandles,
793 tls_base: Option<u64>,
794}
795
796struct InstanceGroupState {
797 main_instance: Option<Instance>,
798 main_instance_tls_base: u64,
799
800 side_instances: HashMap<ModuleHandle, DlInstance>,
801
802 stack_pointer: Global,
803 memory: Memory,
804 indirect_function_table: Table,
805 c_longjmp: Tag,
806 cpp_exception: Tag,
807
808 recv_pending_operation_barrier: bus::BusReader<Arc<Barrier>>,
811 recv_pending_operation: bus::BusReader<DlOperation>,
814}
815
816struct LinkerState {
818 engine: Engine,
819
820 main_module: Module,
821 main_module_dylink_info: DylinkInfo,
822
823 side_modules: BTreeMap<ModuleHandle, DlModule>,
831 side_modules_by_name: HashMap<PathBuf, ModuleHandle>,
832 next_module_handle: u32,
833
834 memory_allocator: MemoryAllocator,
835 heap_base: u64,
836
837 allocated_closure_functions: BTreeMap<u32, bool>,
841 available_closure_functions: Vec<u32>,
844
845 symbol_resolution_records: HashMap<SymbolResolutionKey, SymbolResolutionResult>,
846
847 send_pending_operation_barrier: bus::Bus<Arc<Barrier>>,
848 send_pending_operation: bus::Bus<DlOperation>,
849}
850
851#[derive(Clone)]
857pub struct Linker {
858 linker_state: Arc<RwLock<LinkerState>>,
859 instance_group_state: Arc<Mutex<Option<InstanceGroupState>>>,
860
861 dl_operation_pending: Arc<AtomicBool>,
869}
870
871macro_rules! write_linker_state {
879 ($guard:ident, $linker:expr, $group_state:ident, $ctx:ident) => {
880 #[allow(unused_mut)]
881 let mut $guard = loop {
882 match $linker.linker_state.try_write() {
883 Ok(guard) => break guard,
884 Err(TryLockError::WouldBlock) => {
885 let env = $ctx.as_ref();
888 let mut store = $ctx.as_store_mut();
889 $linker.do_pending_link_operations_internal($group_state, &mut store, &env)?;
890 std::thread::sleep(std::time::Duration::from_millis(10));
895 }
896 Err(TryLockError::Poisoned(_)) => panic!("The linker state's lock is poisoned"),
897 }
898 };
899 };
900}
901
902macro_rules! lock_instance_group_state {
903 ($guard:ident, $state:ident, $linker:expr, $err:expr) => {
904 let mut $guard = $linker.instance_group_state.lock().unwrap();
905 if $guard.is_none() {
906 return Err($err);
907 }
908 let $state = $guard.deref_mut().as_mut().unwrap();
909 };
910}
911
912impl std::fmt::Debug for Linker {
913 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
914 f.debug_struct("Linker").finish()
915 }
916}
917
918pub enum DlModuleSpec<'a> {
919 FileSystem {
920 module_spec: &'a Path,
921 ld_library_path: &'a [&'a Path],
922 },
923 Memory {
924 module_name: &'a str,
925 bytes: &'a [u8],
926 },
927}
928
929impl std::fmt::Debug for DlModuleSpec<'_> {
930 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
931 match self {
932 Self::FileSystem { module_spec, .. } => f
933 .debug_struct("FileSystem")
934 .field("module_spec", module_spec)
935 .finish(),
936 Self::Memory { module_name, .. } => f
937 .debug_struct("Memory")
938 .field("module_name", module_name)
939 .finish(),
940 }
941 }
942}
943
944impl Linker {
945 pub fn new(
950 engine: Engine,
951 main_module: &Module,
952 store: &mut StoreMut<'_>,
953 memory: Option<Memory>,
954 func_env: &mut WasiFunctionEnv,
955 stack_size: u64,
956 ld_library_path: &[&Path],
957 ) -> Result<(Self, LinkedMainModule), LinkError> {
958 let dylink_section = parse_dylink0_section(main_module)?;
959
960 trace!(?dylink_section, "Loading main module");
961
962 let mut imports = import_object_for_all_wasi_versions(main_module, store, &func_env.env);
963
964 let function_table_type = main_module
965 .imports()
966 .tables()
967 .filter_map(|t| {
968 if t.ty().ty == Type::FuncRef
969 && t.name() == "__indirect_function_table"
970 && t.module() == "env"
971 {
972 Some(*t.ty())
973 } else {
974 None
975 }
976 })
977 .next()
978 .ok_or(LinkError::MissingMainModuleImport(
979 "env.__indirect_function_table".to_string(),
980 ))?;
981
982 trace!(
983 minimum_size = ?function_table_type.minimum,
984 "Creating indirect function table"
985 );
986 let indirect_function_table = Table::new(store, function_table_type, Value::FuncRef(None))
987 .map_err(LinkError::TableAllocationError)?;
988
989 let expected_table_length =
993 dylink_section.mem_info.table_size + MAIN_MODULE_TABLE_BASE as u32;
994 if indirect_function_table.size(store) < expected_table_length {
996 let current_size = indirect_function_table.size(store);
997 let delta = expected_table_length - current_size;
998 trace!(?current_size, ?delta, "Growing indirect function table");
999 indirect_function_table
1000 .grow(store, delta, Value::FuncRef(None))
1001 .map_err(LinkError::TableAllocationError)?;
1002 }
1003
1004 trace!(
1005 size = indirect_function_table.size(store),
1006 "Indirect function table initial size"
1007 );
1008
1009 let memory_type = main_module
1010 .imports()
1011 .memories()
1012 .filter_map(|t| {
1013 if t.name() == "memory" && t.module() == "env" {
1014 Some(*t.ty())
1015 } else {
1016 None
1017 }
1018 })
1019 .next()
1020 .ok_or(LinkError::MissingMainModuleImport("env.memory".to_string()))?;
1021
1022 let memory = match memory {
1023 Some(m) => m,
1024 None => Memory::new(store, memory_type)?,
1025 };
1026
1027 let stack_low = {
1028 let data_end = dylink_section.mem_info.memory_size as u64;
1029 if data_end % 1024 != 0 {
1030 data_end + 1024 - (data_end % 1024)
1031 } else {
1032 data_end
1033 }
1034 };
1035
1036 if stack_size % 1024 != 0 {
1037 panic!("Stack size must be 1024-bit aligned");
1038 }
1039
1040 let stack_high = stack_low + stack_size;
1041
1042 memory.grow_at_least(store, stack_high)?;
1045
1046 trace!(
1047 memory_pages = ?memory.grow(store, 0).unwrap(),
1048 stack_low,
1049 stack_high,
1050 "Memory layout"
1051 );
1052
1053 let stack_pointer_import = main_module
1054 .imports()
1055 .find(|i| i.module() == "env" && i.name() == "__stack_pointer")
1056 .ok_or(LinkError::MissingMainModuleImport(
1057 "__stack_pointer".to_string(),
1058 ))?;
1059
1060 let stack_pointer = define_integer_global_import(store, &stack_pointer_import, stack_high)?;
1061
1062 let c_longjmp = Tag::new(store, vec![Type::I32]);
1063 let cpp_exception = Tag::new(store, vec![Type::I32]);
1064
1065 let mut barrier_tx = Bus::new(1);
1066 let barrier_rx = barrier_tx.add_rx();
1067 let mut operation_tx = Bus::new(1);
1068 let operation_rx = operation_tx.add_rx();
1069
1070 let mut instance_group = InstanceGroupState {
1071 main_instance: None,
1072 main_instance_tls_base: MAIN_MODULE_MEMORY_BASE,
1075 side_instances: HashMap::new(),
1076 stack_pointer,
1077 memory: memory.clone(),
1078 indirect_function_table: indirect_function_table.clone(),
1079 c_longjmp,
1080 cpp_exception,
1081 recv_pending_operation_barrier: barrier_rx,
1082 recv_pending_operation: operation_rx,
1083 };
1084
1085 let mut linker_state = LinkerState {
1086 engine,
1087 main_module: main_module.clone(),
1088 main_module_dylink_info: dylink_section,
1089 side_modules: BTreeMap::new(),
1090 side_modules_by_name: HashMap::new(),
1091 next_module_handle: MAIN_MODULE_HANDLE.0 + 1,
1092 memory_allocator: MemoryAllocator::new(),
1093 allocated_closure_functions: BTreeMap::new(),
1094 available_closure_functions: Vec::new(),
1095 heap_base: stack_high,
1096 symbol_resolution_records: HashMap::new(),
1097 send_pending_operation_barrier: barrier_tx,
1098 send_pending_operation: operation_tx,
1099 };
1100
1101 let mut link_state = InProgressLinkState::default();
1102
1103 let well_known_imports = [
1104 ("env", "__memory_base", MAIN_MODULE_MEMORY_BASE),
1105 ("env", "__table_base", MAIN_MODULE_TABLE_BASE),
1106 ("GOT.mem", "__stack_high", stack_high),
1107 ("GOT.mem", "__stack_low", stack_low),
1108 ("GOT.mem", "__heap_base", stack_high),
1109 ];
1110
1111 trace!("Resolving main module's symbols");
1112 linker_state.resolve_symbols(
1113 &instance_group,
1114 store,
1115 main_module,
1116 MAIN_MODULE_HANDLE,
1117 &mut link_state,
1118 &well_known_imports,
1119 )?;
1120
1121 trace!("Populating main module's imports object");
1122 instance_group.populate_imports_from_link_state(
1123 MAIN_MODULE_HANDLE,
1124 &mut linker_state,
1125 &mut link_state,
1126 store,
1127 main_module,
1128 &mut imports,
1129 &func_env.env,
1130 &well_known_imports,
1131 )?;
1132
1133 let main_instance = Instance::new(store, main_module, &imports)?;
1138 instance_group.main_instance = Some(main_instance.clone());
1139
1140 let runtime_path = linker_state.main_module_dylink_info.runtime_path.clone();
1141 for needed in linker_state.main_module_dylink_info.needed.clone() {
1142 trace!(name = needed, "Loading module needed by main");
1146 let wasi_env = func_env.data(store);
1147 linker_state.load_module_tree(
1148 DlModuleSpec::FileSystem {
1149 module_spec: Path::new(needed.as_str()),
1150 ld_library_path,
1151 },
1152 &mut link_state,
1153 &wasi_env.runtime,
1154 &wasi_env.state,
1155 runtime_path.as_ref(),
1156 Some(Path::new("./main.wasm")),
1163 )?;
1164 }
1165
1166 for module_handle in link_state
1167 .new_modules
1168 .iter()
1169 .map(|m| m.handle)
1170 .collect::<Vec<_>>()
1171 {
1172 trace!(?module_handle, "Instantiating module");
1173 instance_group.instantiate_side_module_from_link_state(
1174 &mut linker_state,
1175 store,
1176 &func_env.env,
1177 &mut link_state,
1178 module_handle,
1179 )?;
1180 }
1181
1182 let linker = Self {
1183 linker_state: Arc::new(RwLock::new(linker_state)),
1184 instance_group_state: Arc::new(Mutex::new(Some(instance_group))),
1185 dl_operation_pending: Arc::new(AtomicBool::new(false)),
1186 };
1187
1188 let stack_layout = WasiMemoryLayout {
1189 stack_lower: stack_low,
1190 stack_upper: stack_high,
1191 stack_size: stack_high - stack_low,
1192 guard_size: 0,
1193 tls_base: Some(MAIN_MODULE_MEMORY_BASE),
1194 };
1195 let module_handles = WasiModuleTreeHandles::Dynamic {
1196 linker: linker.clone(),
1197 main_module_instance_handles: WasiModuleInstanceHandles::new(
1198 memory.clone(),
1199 store,
1200 main_instance.clone(),
1201 Some(indirect_function_table.clone()),
1202 ),
1203 };
1204
1205 func_env
1206 .initialize_handles_and_layout(
1207 store,
1208 main_instance.clone(),
1209 module_handles,
1210 Some(stack_layout),
1211 true,
1212 )
1213 .map_err(LinkError::MainModuleHandleInitFailed)?;
1214
1215 trace!("Calling data relocator function for main module");
1218 call_initialization_function::<()>(&main_instance, store, "__wasm_apply_data_relocs")?;
1219 call_initialization_function::<()>(&main_instance, store, "__wasm_apply_tls_relocs")?;
1220
1221 {
1222 let group_guard = linker.instance_group_state.lock().unwrap();
1223 let mut linker_state = linker.linker_state.write().unwrap();
1224 trace!("Finalizing linking of main module");
1225 linker.finalize_link_operation(group_guard, &mut linker_state, store, link_state)?;
1226 }
1227
1228 trace!("Calling main module's _initialize function");
1229 call_initialization_function::<()>(&main_instance, store, "_initialize")?;
1230
1231 trace!("Link complete");
1232
1233 Ok((
1234 linker,
1235 LinkedMainModule {
1236 instance: main_instance,
1237 memory,
1238 indirect_function_table,
1239 stack_low,
1240 stack_high,
1241 },
1242 ))
1243 }
1244
1245 pub fn create_instance_group(
1246 &self,
1247 parent_ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1248 store: &mut StoreMut<'_>,
1249 func_env: &mut WasiFunctionEnv,
1250 ) -> Result<(Self, LinkedMainModule), LinkError> {
1251 trace!("Spawning new instance group");
1252
1253 lock_instance_group_state!(
1254 parent_group_state_guard,
1255 parent_group_state,
1256 self,
1257 LinkError::InstanceGroupIsDead
1258 );
1259
1260 write_linker_state!(linker_state, self, parent_group_state, parent_ctx);
1263
1264 let parent_store = parent_ctx.as_store_mut();
1265
1266 let main_module = linker_state.main_module.clone();
1267 let memory = parent_group_state
1268 .memory
1269 .share_in_store(&parent_store, store)?;
1270
1271 let mut imports = import_object_for_all_wasi_versions(&main_module, store, &func_env.env);
1272
1273 let indirect_function_table_type =
1274 parent_group_state.indirect_function_table.ty(&parent_store);
1275 trace!(
1276 minimum_size = ?indirect_function_table_type.minimum,
1277 "Creating indirect function table"
1278 );
1279
1280 let indirect_function_table =
1281 Table::new(store, indirect_function_table_type, Value::FuncRef(None))
1282 .map_err(LinkError::TableAllocationError)?;
1283
1284 let expected_table_length = parent_group_state
1285 .indirect_function_table
1286 .size(&parent_store);
1287 if indirect_function_table.size(store) < expected_table_length {
1289 let current_size = indirect_function_table.size(store);
1290 let delta = expected_table_length - current_size;
1291 trace!(?current_size, ?delta, "Growing indirect function table");
1292 indirect_function_table
1293 .grow(store, delta, Value::FuncRef(None))
1294 .map_err(LinkError::TableAllocationError)?;
1295 }
1296
1297 trace!(
1298 size = indirect_function_table.size(store),
1299 "Indirect function table initial size"
1300 );
1301
1302 let (stack_low, stack_high, tls_base) = {
1306 let layout = &func_env.env.as_ref(store).layout;
1307 (
1308 layout.stack_lower,
1309 layout.stack_upper,
1310 layout.tls_base.expect(
1311 "tls_base must be set in memory layout of new instance group's main instance",
1312 ),
1313 )
1314 };
1315
1316 trace!(stack_low, stack_high, "Memory layout");
1317
1318 let stack_pointer_import = main_module
1319 .imports()
1320 .find(|i| i.module() == "env" && i.name() == "__stack_pointer")
1321 .ok_or(LinkError::MissingMainModuleImport(
1322 "__stack_pointer".to_string(),
1323 ))?;
1324
1325 let stack_pointer = define_integer_global_import(store, &stack_pointer_import, 0)?;
1328
1329 let c_longjmp = Tag::new(store, vec![Type::I32]);
1330 let cpp_exception = Tag::new(store, vec![Type::I32]);
1331
1332 let barrier_rx = linker_state.send_pending_operation_barrier.add_rx();
1333 let operation_rx = linker_state.send_pending_operation.add_rx();
1334
1335 let mut instance_group = InstanceGroupState {
1336 main_instance: None,
1337 main_instance_tls_base: tls_base,
1338 side_instances: HashMap::new(),
1339 stack_pointer,
1340 memory: memory.clone(),
1341 indirect_function_table: indirect_function_table.clone(),
1342 c_longjmp,
1343 cpp_exception,
1344 recv_pending_operation_barrier: barrier_rx,
1345 recv_pending_operation: operation_rx,
1346 };
1347
1348 let mut pending_resolutions = PendingResolutionsFromLinker::default();
1349
1350 let well_known_imports = [
1351 ("env", "__memory_base", MAIN_MODULE_MEMORY_BASE),
1352 ("env", "__table_base", MAIN_MODULE_TABLE_BASE),
1353 ("GOT.mem", "__stack_high", stack_high),
1354 ("GOT.mem", "__stack_low", stack_low),
1355 ("GOT.mem", "__heap_base", linker_state.heap_base),
1356 ];
1357
1358 trace!("Populating imports object for new instance group's main instance");
1359 instance_group.populate_imports_from_linker(
1360 MAIN_MODULE_HANDLE,
1361 &linker_state,
1362 store,
1363 &main_module,
1364 &mut imports,
1365 &func_env.env,
1366 &well_known_imports,
1367 &mut pending_resolutions,
1368 )?;
1369
1370 let main_instance = Instance::new(store, &main_module, &imports)?;
1371
1372 instance_group.main_instance = Some(main_instance.clone());
1373
1374 for side in &linker_state.side_modules {
1375 trace!(module_handle = ?side.0, "Instantiating existing side module");
1376 instance_group.instantiate_side_module_from_linker(
1377 &linker_state,
1378 store,
1379 &func_env.env,
1380 *side.0,
1381 &mut pending_resolutions,
1382 )?;
1383 }
1384
1385 trace!("Finalizing pending functions");
1386 instance_group.finalize_pending_resolutions_from_linker(&pending_resolutions, store)?;
1387
1388 trace!("Applying externally-requested function table entries");
1389 instance_group.apply_requested_symbols_from_linker(store, &linker_state)?;
1390
1391 let linker = Self {
1392 linker_state: self.linker_state.clone(),
1393 instance_group_state: Arc::new(Mutex::new(Some(instance_group))),
1394 dl_operation_pending: self.dl_operation_pending.clone(),
1395 };
1396
1397 let module_handles = WasiModuleTreeHandles::Dynamic {
1398 linker: linker.clone(),
1399 main_module_instance_handles: WasiModuleInstanceHandles::new(
1400 memory.clone(),
1401 store,
1402 main_instance.clone(),
1403 Some(indirect_function_table.clone()),
1404 ),
1405 };
1406
1407 func_env
1408 .initialize_handles_and_layout(
1409 store,
1410 main_instance.clone(),
1411 module_handles,
1412 None,
1413 false,
1414 )
1415 .map_err(LinkError::MainModuleHandleInitFailed)?;
1416
1417 trace!("Instance group spawned successfully");
1418
1419 Ok((
1420 linker,
1421 LinkedMainModule {
1422 instance: main_instance,
1423 memory,
1424 indirect_function_table,
1425 stack_low,
1426 stack_high,
1427 },
1428 ))
1429 }
1430
1431 pub fn shutdown_instance_group(
1432 &self,
1433 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1434 ) -> Result<(), LinkError> {
1435 trace!("Shutting instance group down");
1436
1437 let mut guard = self.instance_group_state.lock().unwrap();
1438 match guard.as_mut() {
1439 None => Ok(()),
1440 Some(group_state) => {
1441 write_linker_state!(linker_state, self, group_state, ctx);
1445 guard.take();
1446 drop(linker_state);
1447
1448 trace!("Instance group shut down");
1449
1450 Ok(())
1451 }
1452 }
1453 }
1454
1455 pub fn allocate_closure_index(
1457 &self,
1458 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1459 ) -> Result<u32, LinkError> {
1460 lock_instance_group_state!(
1461 group_state_guard,
1462 group_state,
1463 self,
1464 LinkError::InstanceGroupIsDead
1465 );
1466 write_linker_state!(linker_state, self, group_state, ctx);
1467
1468 let mut store = ctx.as_store_mut();
1469
1470 if let Some(function_index) = linker_state.available_closure_functions.pop() {
1472 linker_state
1473 .allocated_closure_functions
1474 .insert(function_index, true);
1475 return Ok(function_index);
1476 }
1477
1478 const CLOSURE_ALLOCATION_SIZE: u32 = 100;
1480
1481 let function_index = group_state
1482 .allocate_function_table(&mut store, CLOSURE_ALLOCATION_SIZE, 0)
1483 .map_err(LinkError::TableAllocationError)? as u32;
1484
1485 linker_state
1486 .available_closure_functions
1487 .reserve(CLOSURE_ALLOCATION_SIZE as usize - 1);
1488 for i in 1..CLOSURE_ALLOCATION_SIZE {
1489 linker_state
1490 .available_closure_functions
1491 .push(function_index + i);
1492 linker_state
1493 .allocated_closure_functions
1494 .insert(function_index + i, false);
1495 }
1496 linker_state
1497 .allocated_closure_functions
1498 .insert(function_index, true);
1499
1500 self.synchronize_link_operation(
1501 DlOperation::AllocateFunctionTable {
1502 index: function_index,
1503 size: CLOSURE_ALLOCATION_SIZE,
1504 },
1505 linker_state,
1506 group_state,
1507 &ctx.data().process,
1508 ctx.data().tid(),
1509 );
1510
1511 Ok(function_index)
1512 }
1513
1514 pub fn free_closure_index(
1518 &self,
1519 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1520 function_id: u32,
1521 ) -> Result<(), LinkError> {
1522 lock_instance_group_state!(
1523 group_state_guard,
1524 group_state,
1525 self,
1526 LinkError::InstanceGroupIsDead
1527 );
1528 write_linker_state!(linker_state, self, group_state, ctx);
1529
1530 let Some(entry) = linker_state
1531 .allocated_closure_functions
1532 .get_mut(&function_id)
1533 else {
1534 return Ok(());
1536 };
1537 if !*entry {
1538 return Ok(());
1540 }
1541
1542 *entry = false;
1543 linker_state.available_closure_functions.push(function_id);
1544 Ok(())
1545 }
1546
1547 pub fn is_closure(&self, function_id: u32) -> bool {
1551 let linker = self.linker_state.read().unwrap();
1553 linker
1554 .allocated_closure_functions
1555 .contains_key(&function_id)
1556 }
1557
1558 pub fn load_module(
1562 &self,
1563 module_spec: DlModuleSpec,
1564 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1565 ) -> Result<ModuleHandle, LinkError> {
1566 trace!(?module_spec, "Loading module");
1567
1568 lock_instance_group_state!(
1569 group_state_guard,
1570 group_state,
1571 self,
1572 LinkError::InstanceGroupIsDead
1573 );
1574
1575 write_linker_state!(linker_state, self, group_state, ctx);
1580
1581 let mut link_state = InProgressLinkState::default();
1582 let env = ctx.as_ref();
1583 let mut store = ctx.as_store_mut();
1584
1585 trace!("Loading module tree for requested module");
1586 let wasi_env = env.as_ref(&store);
1587 let runtime_path: &[String] = &[];
1588 let module_handle = linker_state.load_module_tree(
1589 module_spec,
1590 &mut link_state,
1591 &wasi_env.runtime,
1592 &wasi_env.state,
1593 runtime_path, Option::<&Path>::None, )?;
1596
1597 let new_modules = link_state
1598 .new_modules
1599 .iter()
1600 .map(|m| m.handle)
1601 .collect::<Vec<_>>();
1602
1603 for handle in &new_modules {
1604 trace!(?module_handle, "Instantiating module");
1605 group_state.instantiate_side_module_from_link_state(
1606 &mut linker_state,
1607 &mut store,
1608 &env,
1609 &mut link_state,
1610 *handle,
1611 )?;
1612 }
1613
1614 trace!("Finalizing link");
1615 self.finalize_link_operation(group_state_guard, &mut linker_state, &mut store, link_state)?;
1616
1617 if !new_modules.is_empty() {
1618 lock_instance_group_state!(
1620 group_state_guard,
1621 group_state,
1622 self,
1623 LinkError::InstanceGroupIsDead
1624 );
1625
1626 self.synchronize_link_operation(
1627 DlOperation::LoadModules(new_modules),
1628 linker_state,
1629 group_state,
1630 &ctx.data().process,
1631 ctx.data().tid(),
1632 );
1633 }
1634
1635 trace!("Module load complete");
1653
1654 Ok(module_handle)
1655 }
1656
1657 fn finalize_link_operation(
1658 &self,
1659 mut group_state_guard: MutexGuard<'_, Option<InstanceGroupState>>,
1661 linker_state: &mut LinkerState,
1662 store: &mut impl AsStoreMut,
1663 link_state: InProgressLinkState,
1664 ) -> Result<(), LinkError> {
1665 let group_state = group_state_guard.as_mut().unwrap();
1666
1667 trace!(?link_state, "Finalizing link operation");
1668
1669 group_state.finalize_pending_globals(
1670 linker_state,
1671 store,
1672 &link_state.unresolved_globals,
1673 )?;
1674
1675 let new_instances = link_state
1676 .new_modules
1677 .iter()
1678 .map(|m| group_state.side_instances[&m.handle].instance.clone())
1679 .collect::<Vec<_>>();
1680
1681 drop(group_state_guard);
1684
1685 trace!("Calling data relocation functions");
1689 for instance in &new_instances {
1690 call_initialization_function::<()>(instance, store, "__wasm_apply_data_relocs")?;
1691 call_initialization_function::<()>(instance, store, "__wasm_apply_tls_relocs")?;
1692 }
1693
1694 trace!("Calling ctor functions");
1695 for instance in &new_instances {
1696 call_initialization_function::<()>(instance, store, "__wasm_call_ctors")?;
1697 }
1698
1699 Ok(())
1700 }
1701
1702 pub fn resolve_export(
1712 &self,
1713 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1714 module_handle: Option<ModuleHandle>,
1715 symbol: &str,
1716 ) -> Result<ResolvedExport, ResolveError> {
1717 trace!(?module_handle, symbol, "Resolving symbol");
1718
1719 let resolution_key = SymbolResolutionKey::Requested {
1720 resolve_from: module_handle,
1721 name: symbol.to_string(),
1722 };
1723
1724 lock_instance_group_state!(guard, group_state, self, ResolveError::InstanceGroupIsDead);
1725
1726 if let Ok(linker_state) = self.linker_state.try_read() {
1727 if let Some(resolution) = linker_state.symbol_resolution_records.get(&resolution_key) {
1728 trace!(?resolution, "Already have a resolution for this symbol");
1729 match resolution {
1730 SymbolResolutionResult::FunctionPointer {
1731 function_table_index: addr,
1732 ..
1733 } => {
1734 return Ok(ResolvedExport::Function {
1735 func_ptr: *addr as u64,
1736 });
1737 }
1738 SymbolResolutionResult::Memory(addr) => {
1739 return Ok(ResolvedExport::Global { data_ptr: *addr });
1740 }
1741 SymbolResolutionResult::Tls {
1742 resolved_from,
1743 offset,
1744 } => {
1745 let Some(tls_base) = group_state.tls_base(*resolved_from) else {
1746 return Err(ResolveError::TlsSymbolWithoutTls);
1747 };
1748 return Ok(ResolvedExport::Global {
1749 data_ptr: tls_base + offset,
1750 });
1751 }
1752 r => panic!(
1753 "Internal error: unexpected symbol resolution \
1754 {r:?} for requested symbol {symbol}"
1755 ),
1756 }
1757 }
1758 }
1759
1760 write_linker_state!(linker_state, self, group_state, ctx);
1761
1762 let mut store = ctx.as_store_mut();
1763
1764 trace!("Resolving export");
1765 let (export, resolved_from) =
1766 group_state.resolve_export(&linker_state, &mut store, module_handle, symbol, false)?;
1767
1768 trace!(?export, ?resolved_from, "Resolved export");
1769
1770 match export {
1771 PartiallyResolvedExport::Global(addr) => {
1772 linker_state
1773 .symbol_resolution_records
1774 .insert(resolution_key, SymbolResolutionResult::Memory(addr));
1775
1776 Ok(ResolvedExport::Global { data_ptr: addr })
1777 }
1778 PartiallyResolvedExport::Tls { offset, final_addr } => {
1779 linker_state.symbol_resolution_records.insert(
1780 resolution_key,
1781 SymbolResolutionResult::Tls {
1782 resolved_from,
1783 offset,
1784 },
1785 );
1786
1787 Ok(ResolvedExport::Global {
1788 data_ptr: final_addr,
1789 })
1790 }
1791 PartiallyResolvedExport::Function(func) => {
1792 let func_ptr = group_state
1793 .append_to_function_table(&mut store, func.clone())
1794 .map_err(ResolveError::TableAllocationError)?;
1795 trace!(
1796 ?func_ptr,
1797 table_size = group_state.indirect_function_table.size(&store),
1798 "Placed resolved function into table"
1799 );
1800 linker_state.symbol_resolution_records.insert(
1801 resolution_key,
1802 SymbolResolutionResult::FunctionPointer {
1803 resolved_from,
1804 function_table_index: func_ptr,
1805 },
1806 );
1807
1808 self.synchronize_link_operation(
1809 DlOperation::ResolveFunction {
1810 name: symbol.to_string(),
1811 resolved_from,
1812 function_table_index: func_ptr,
1813 },
1814 linker_state,
1815 group_state,
1816 &ctx.data().process,
1817 ctx.data().tid(),
1818 );
1819
1820 Ok(ResolvedExport::Function {
1821 func_ptr: func_ptr as u64,
1822 })
1823 }
1824 }
1825 }
1826
1827 pub fn is_handle_valid(
1828 &self,
1829 handle: ModuleHandle,
1830 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1831 ) -> Result<bool, LinkError> {
1832 lock_instance_group_state!(guard, group_state, self, LinkError::InstanceGroupIsDead);
1834 write_linker_state!(linker_state, self, group_state, ctx);
1835 Ok(linker_state.side_modules.contains_key(&handle))
1836 }
1837
1838 fn synchronize_link_operation(
1842 &self,
1843 op: DlOperation,
1844 mut linker_state_write_lock: RwLockWriteGuard<LinkerState>,
1845 group_state: &mut InstanceGroupState,
1846 wasi_process: &WasiProcess,
1847 self_thread_id: WasiThreadId,
1848 ) {
1849 trace!(?op, "Synchronizing link operation");
1850
1851 let num_groups = linker_state_write_lock.send_pending_operation.rx_count();
1852
1853 if num_groups <= 1 {
1854 trace!("No other living instance groups, nothing to do");
1855 return;
1856 }
1857
1858 let barrier = Arc::new(Barrier::new(num_groups));
1860 if linker_state_write_lock
1861 .send_pending_operation_barrier
1862 .try_broadcast(barrier.clone())
1863 .is_err()
1864 {
1865 panic!("Internal error: more than one synchronized link operation active")
1868 }
1869
1870 self.dl_operation_pending.store(true, Ordering::SeqCst);
1872
1873 trace!("Signalling wasix threads to wake up");
1874 for thread in wasi_process
1875 .all_threads()
1876 .into_iter()
1877 .filter(|tid| *tid != self_thread_id)
1878 {
1879 wasi_process.signal_thread(&thread, wasmer_wasix_types::wasi::Signal::Sigwakeup);
1881 }
1882
1883 trace!("Waiting at barrier");
1884 barrier.wait();
1886
1887 trace!("All threads now processing dl op");
1888
1889 self.dl_operation_pending.store(false, Ordering::SeqCst);
1891
1892 if linker_state_write_lock
1896 .send_pending_operation
1897 .try_broadcast(op.clone())
1898 .is_err()
1899 {
1900 panic!("Internal error: more than one synchronized link operation active")
1902 }
1903
1904 trace!("Unlocking linker state");
1909 drop(linker_state_write_lock);
1910 let linker_state_read_lock = self.linker_state.read().unwrap();
1911
1912 _ = group_state.recv_pending_operation_barrier.recv().unwrap();
1915 _ = group_state.recv_pending_operation.recv().unwrap();
1916
1917 trace!("Waiting for other threads to finish processing the dl op");
1922 barrier.wait();
1923
1924 drop(linker_state_read_lock);
1926
1927 trace!("Synchronization complete");
1928 }
1929
1930 pub(crate) fn do_pending_link_operations(
1931 &self,
1932 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1933 fast: bool,
1934 ) -> Result<(), LinkError> {
1935 if !self.dl_operation_pending.load(if fast {
1943 Ordering::Relaxed
1944 } else {
1945 Ordering::SeqCst
1946 }) {
1947 return Ok(());
1948 }
1949
1950 lock_instance_group_state!(guard, group_state, self, LinkError::InstanceGroupIsDead);
1951
1952 let env = ctx.as_ref();
1953 let mut store = ctx.as_store_mut();
1954 self.do_pending_link_operations_internal(group_state, &mut store, &env)
1955 }
1956
1957 fn do_pending_link_operations_internal(
1958 &self,
1959 group_state: &mut InstanceGroupState,
1960 store: &mut impl AsStoreMut,
1961 env: &FunctionEnv<WasiEnv>,
1962 ) -> Result<(), LinkError> {
1963 if !self.dl_operation_pending.load(Ordering::SeqCst) {
1964 return Ok(());
1965 }
1966
1967 trace!("Pending link operation discovered, will process");
1968
1969 let barrier = group_state.recv_pending_operation_barrier.recv().expect(
1971 "Failed to receive barrier while a DL operation was \
1972 in progress; this condition can't be recovered from",
1973 );
1974 barrier.wait();
1975
1976 trace!("Past the barrier, now processing operation");
1977
1978 let op = group_state.recv_pending_operation.recv().unwrap();
1981 let linker_state = self.linker_state.read().unwrap();
1984
1985 let result = group_state.apply_dl_operation(linker_state.deref(), op, store, env);
1986
1987 trace!("Operation applied, now waiting at second barrier");
1988
1989 barrier.wait();
1992 drop(linker_state);
1994
1995 trace!("Pending link operation applied successfully");
1996
1997 result
1998 }
1999}
2000
2001impl LinkerState {
2002 fn allocate_memory(
2003 &mut self,
2004 store: &mut impl AsStoreMut,
2005 memory: &Memory,
2006 mem_info: &wasmparser::MemInfo,
2007 ) -> Result<u64, MemoryError> {
2008 trace!(?mem_info, "Allocating memory");
2009
2010 let new_size = if mem_info.memory_size == 0 {
2011 0
2012 } else {
2013 self.memory_allocator.allocate(
2014 memory,
2015 store,
2016 mem_info.memory_size,
2017 2_u32.pow(mem_info.memory_alignment),
2018 )? as u64
2019 };
2020
2021 trace!(new_size, "Final size");
2022
2023 Ok(new_size)
2024 }
2025
2026 fn memory_base(&self, module_handle: ModuleHandle) -> u64 {
2027 if module_handle == MAIN_MODULE_HANDLE {
2028 MAIN_MODULE_MEMORY_BASE
2029 } else {
2030 self.side_modules
2031 .get(&module_handle)
2032 .expect("Internal error: bad module handle")
2033 .memory_base
2034 }
2035 }
2036
2037 fn dylink_info(&self, module_handle: ModuleHandle) -> &DylinkInfo {
2038 if module_handle == MAIN_MODULE_HANDLE {
2039 &self.main_module_dylink_info
2040 } else {
2041 &self
2042 .side_modules
2043 .get(&module_handle)
2044 .expect("Internal error: bad module handle")
2045 .dylink_info
2046 }
2047 }
2048
2049 fn resolve_symbols(
2058 &self,
2059 group: &InstanceGroupState,
2060 store: &mut impl AsStoreMut,
2061 module: &Module,
2062 module_handle: ModuleHandle,
2063 link_state: &mut InProgressLinkState,
2064 well_known_imports: &[(&str, &str, u64)],
2068 ) -> Result<(), LinkError> {
2069 trace!(?module_handle, "Resolving symbols");
2070 for import in module.imports() {
2071 if well_known_imports
2073 .iter()
2074 .any(|i| i.0 == import.module() && i.1 == import.name())
2075 {
2076 trace!(?import, "Skipping resolution of well-known symbol");
2077 continue;
2078 }
2079
2080 match import.name() {
2082 "memory"
2083 | "__indirect_function_table"
2084 | "__stack_pointer"
2085 | "__c_longjmp"
2086 | "__cpp_exception" => {
2087 trace!(?import, "Skipping resolution of special symbol");
2088 continue;
2089 }
2090 _ => (),
2091 }
2092
2093 match import.module() {
2094 "env" => {
2095 let resolution = self.resolve_env_symbol(group, &import, store)?;
2096 trace!(?import, ?resolution, "Symbol resolved");
2097 link_state.symbols.insert(
2098 NeededSymbolResolutionKey {
2099 module_handle,
2100 import_module: "env".to_owned(),
2101 import_name: import.name().to_string(),
2102 },
2103 resolution,
2104 );
2105 }
2106 "GOT.mem" => {
2107 let resolution = self.resolve_got_mem_symbol(group, &import, store)?;
2108 trace!(?import, ?resolution, "Symbol resolved");
2109 link_state.symbols.insert(
2110 NeededSymbolResolutionKey {
2111 module_handle,
2112 import_module: "GOT.mem".to_owned(),
2113 import_name: import.name().to_string(),
2114 },
2115 resolution,
2116 );
2117 }
2118 "GOT.func" => {
2119 let resolution = self.resolve_got_func_symbol(group, &import, store)?;
2120 trace!(?import, ?resolution, "Symbol resolved");
2121 link_state.symbols.insert(
2122 NeededSymbolResolutionKey {
2123 module_handle,
2124 import_module: "GOT.func".to_owned(),
2125 import_name: import.name().to_string(),
2126 },
2127 resolution,
2128 );
2129 }
2130 _ => (),
2131 }
2132 }
2133
2134 trace!(?module_handle, "All symbols resolved");
2135
2136 Ok(())
2137 }
2138
2139 fn resolve_env_symbol(
2145 &self,
2146 group: &InstanceGroupState,
2147 import: &ImportType,
2148 store: &impl AsStoreRef,
2149 ) -> Result<InProgressSymbolResolution, LinkError> {
2150 let ExternType::Function(import_func_ty) = import.ty() else {
2151 return Err(LinkError::ImportMustBeFunction(
2152 "env",
2153 import.name().to_string(),
2154 ));
2155 };
2156
2157 let export = group.resolve_exported_symbol(import.name());
2158
2159 match export {
2160 Some((module_handle, export)) => {
2161 let Extern::Function(export_func) = export else {
2162 return Err(LinkError::ImportTypeMismatch(
2163 "env".to_string(),
2164 import.name().to_string(),
2165 ExternType::Function(import_func_ty.clone()),
2166 export.ty(store).clone(),
2167 ));
2168 };
2169
2170 if export_func.ty(store) != *import_func_ty {
2171 return Err(LinkError::ImportTypeMismatch(
2172 "env".to_string(),
2173 import.name().to_string(),
2174 ExternType::Function(import_func_ty.clone()),
2175 export.ty(store).clone(),
2176 ));
2177 }
2178
2179 Ok(InProgressSymbolResolution::Function(module_handle))
2180 }
2181 None => {
2182 Ok(InProgressSymbolResolution::StubFunction(
2188 import_func_ty.clone(),
2189 ))
2190 }
2191 }
2192 }
2193
2194 fn resolve_got_mem_symbol(
2197 &self,
2198 group: &InstanceGroupState,
2199 import: &ImportType,
2200 store: &impl AsStoreRef,
2201 ) -> Result<InProgressSymbolResolution, LinkError> {
2202 let global_type = get_integer_global_type_from_import(import)?;
2203
2204 match group.resolve_exported_symbol(import.name()) {
2205 Some((module_handle, export)) => {
2206 let ExternType::Global(global_type) = export.ty(store) else {
2207 return Err(LinkError::ImportTypeMismatch(
2208 "GOT.mem".to_string(),
2209 import.name().to_string(),
2210 ExternType::Global(global_type),
2211 export.ty(store).clone(),
2212 ));
2213 };
2214
2215 if !matches!(global_type.ty, Type::I32 | Type::I64) {
2216 return Err(LinkError::ImportTypeMismatch(
2217 "GOT.mem".to_string(),
2218 import.name().to_string(),
2219 ExternType::Global(global_type),
2220 export.ty(store).clone(),
2221 ));
2222 }
2223
2224 Ok(InProgressSymbolResolution::MemGlobal(module_handle))
2225 }
2226 None => Ok(InProgressSymbolResolution::UnresolvedMemGlobal),
2227 }
2228 }
2229
2230 fn resolve_got_func_symbol(
2234 &self,
2235 group: &InstanceGroupState,
2236 import: &ImportType,
2237 store: &impl AsStoreRef,
2238 ) -> Result<InProgressSymbolResolution, LinkError> {
2239 let _ = get_integer_global_type_from_import(import)?;
2241
2242 match group.resolve_exported_symbol(import.name()) {
2243 Some((module_handle, export)) => {
2244 let ExternType::Function(_) = export.ty(store) else {
2245 return Err(LinkError::ExportMustBeFunction(
2246 import.name().to_string(),
2247 export.ty(store).clone(),
2248 ));
2249 };
2250
2251 Ok(InProgressSymbolResolution::FuncGlobal(module_handle))
2252 }
2253 None => Ok(InProgressSymbolResolution::UnresolvedFuncGlobal),
2254 }
2255 }
2256
2257 fn load_module_tree(
2266 &mut self,
2267 module_spec: DlModuleSpec,
2268 link_state: &mut InProgressLinkState,
2269 runtime: &Arc<dyn Runtime + Send + Sync + 'static>,
2270 wasi_state: &WasiState,
2271 runtime_path: &[impl AsRef<str>],
2272 calling_module_path: Option<impl AsRef<Path>>,
2273 ) -> Result<ModuleHandle, LinkError> {
2274 let module_name = match module_spec {
2275 DlModuleSpec::FileSystem { module_spec, .. } => Cow::Borrowed(module_spec),
2276 DlModuleSpec::Memory { module_name, .. } => {
2277 Cow::Owned(PathBuf::from(format!("::in-memory::{module_name}")))
2278 }
2279 };
2280 trace!(?module_name, "Locating and loading module");
2281
2282 if let Some(handle) = self.side_modules_by_name.get(module_name.as_ref()) {
2283 let handle = *handle;
2284
2285 trace!(?module_name, ?handle, "Module was already loaded");
2286
2287 return Ok(handle);
2288 }
2289
2290 let (module_data, paths) = match module_spec {
2292 DlModuleSpec::FileSystem {
2293 module_spec,
2294 ld_library_path,
2295 } => {
2296 let (full_path, bytes) = InlineWaker::block_on(locate_module(
2297 module_spec,
2298 ld_library_path,
2299 runtime_path,
2300 calling_module_path,
2301 &wasi_state.fs,
2302 ))?;
2303 if link_state.pending_module_paths.contains(&full_path) {
2306 trace!("Module is already pending, won't load again");
2307 return Ok(INVALID_MODULE_HANDLE);
2312 }
2313
2314 (
2315 HashedModuleData::new(bytes),
2316 Some((full_path, ld_library_path)),
2317 )
2318 }
2319 DlModuleSpec::Memory { bytes, .. } => (HashedModuleData::new(bytes), None),
2320 };
2321
2322 let module = runtime.load_hashed_module_sync(module_data, Some(&self.engine))?;
2323
2324 let dylink_info = parse_dylink0_section(&module)?;
2325
2326 trace!(?dylink_info, "Loading side module");
2327
2328 if let Some((full_path, ld_library_path)) = paths {
2329 link_state.pending_module_paths.push(full_path.clone());
2330 let num_pending_modules = link_state.pending_module_paths.len();
2331 let pop_pending_module = |link_state: &mut InProgressLinkState| {
2332 assert_eq!(
2333 num_pending_modules,
2334 link_state.pending_module_paths.len(),
2335 "Internal error: pending modules not maintained correctly"
2336 );
2337 link_state.pending_module_paths.pop().unwrap();
2338 };
2339
2340 for needed in &dylink_info.needed {
2341 trace!(needed, "Loading needed side module");
2342 match self.load_module_tree(
2343 DlModuleSpec::FileSystem {
2344 module_spec: Path::new(needed.as_str()),
2345 ld_library_path,
2346 },
2347 link_state,
2348 runtime,
2349 wasi_state,
2350 dylink_info.runtime_path.as_ref(),
2354 Some(&full_path),
2355 ) {
2356 Ok(_) => (),
2357 Err(e) => {
2358 pop_pending_module(link_state);
2359 return Err(e);
2360 }
2361 }
2362 }
2363
2364 pop_pending_module(link_state);
2365 } else if !dylink_info.needed.is_empty() {
2366 unreachable!(
2367 "Internal error: in-memory modules with further needed modules not \
2368 supported and no code paths can create such a module"
2369 );
2370 }
2371
2372 let handle = ModuleHandle(self.next_module_handle);
2373 self.next_module_handle += 1;
2374
2375 trace!(?module_name, ?handle, "Assigned handle to module");
2376
2377 link_state.new_modules.push(InProgressModuleLoad {
2378 handle,
2379 dylink_info,
2380 module,
2381 });
2382 self.side_modules_by_name
2387 .insert(module_name.into_owned(), handle);
2388
2389 Ok(handle)
2390 }
2391}
2392
2393impl InstanceGroupState {
2394 fn main_instance(&self) -> Option<&Instance> {
2395 self.main_instance.as_ref()
2396 }
2397
2398 fn tls_base(&self, module_handle: ModuleHandle) -> Option<u64> {
2399 if module_handle == MAIN_MODULE_HANDLE {
2400 Some(self.main_instance_tls_base)
2402 } else {
2403 self.side_instances
2404 .get(&module_handle)
2405 .expect("Internal error: bad module handle")
2406 .tls_base
2407 }
2408 }
2409
2410 fn try_instance(&self, handle: ModuleHandle) -> Option<&Instance> {
2411 if handle == MAIN_MODULE_HANDLE {
2412 self.main_instance.as_ref()
2413 } else {
2414 self.side_instances.get(&handle).map(|i| &i.instance)
2415 }
2416 }
2417
2418 fn instance(&self, handle: ModuleHandle) -> &Instance {
2419 self.try_instance(handle)
2420 .expect("Internal error: bad module handle or not instantiated in this group")
2421 }
2422
2423 fn allocate_function_table(
2427 &mut self,
2428 store: &mut impl AsStoreMut,
2429 table_size: u32,
2430 table_alignment: u32,
2431 ) -> Result<u64, RuntimeError> {
2432 trace!(table_size, "Allocating table indices");
2433
2434 let base_index = if table_size == 0 {
2435 0
2436 } else {
2437 let current_size = self.indirect_function_table.size(store);
2438 let alignment = 2_u32.pow(table_alignment);
2439
2440 let offset = if current_size % alignment != 0 {
2441 alignment - (current_size % alignment)
2442 } else {
2443 0
2444 };
2445
2446 let delta = table_size + offset;
2447 trace!(?current_size, ?delta, "Growing indirect function table");
2448 let start = self
2449 .indirect_function_table
2450 .grow(store, delta, Value::FuncRef(None))?;
2451
2452 (start + offset) as u64
2453 };
2454
2455 trace!(
2456 base_index,
2457 new_table_size = ?self.indirect_function_table.size(store),
2458 "Allocated table indices"
2459 );
2460
2461 Ok(base_index)
2462 }
2463
2464 fn append_to_function_table(
2465 &self,
2466 store: &mut impl AsStoreMut,
2467 func: Function,
2468 ) -> Result<u32, RuntimeError> {
2469 let table = &self.indirect_function_table;
2470
2471 let ty = func.ty(store).to_string();
2472 let index: u32 = table.size(store);
2473 trace!(?index, ?ty, "Appending function in table");
2474
2475 table.grow(store, 1, func.into())
2476 }
2477
2478 fn place_in_function_table_at(
2479 &self,
2480 store: &mut impl AsStoreMut,
2481 func: Function,
2482 index: u32,
2483 ) -> Result<(), RuntimeError> {
2484 trace!(
2485 ?index,
2486 ?func,
2487 "Placing function in table at pre-defined index"
2488 );
2489
2490 let table = &self.indirect_function_table;
2491 let size = table.size(store);
2492
2493 if size <= index {
2494 let delta = index - size + 1;
2495 trace!(
2496 current_size = ?size,
2497 ?delta,
2498 "Growing indirect function table"
2499 );
2500 table.grow(store, delta, Value::FuncRef(None))?;
2501 } else {
2502 let existing = table.get(store, index).unwrap();
2503 if let Value::FuncRef(Some(_)) = existing {
2504 panic!("Internal error: function table index {index} already occupied");
2505 }
2506 }
2507
2508 let ty = func.ty(store).to_string();
2509 trace!(?index, ?ty, "Placing function in table at index");
2510 table.set(store, index, Value::FuncRef(Some(func)))
2511 }
2512
2513 fn instantiate_side_module_from_link_state(
2514 &mut self,
2515 linker_state: &mut LinkerState,
2516 store: &mut impl AsStoreMut,
2517 env: &FunctionEnv<WasiEnv>,
2518 link_state: &mut InProgressLinkState,
2519 module_handle: ModuleHandle,
2520 ) -> Result<(), LinkError> {
2521 let Some(pending_module) = link_state
2522 .new_modules
2523 .iter()
2524 .find(|m| m.handle == module_handle)
2525 else {
2526 panic!(
2527 "Only recently-loaded modules in the link state can be instantiated \
2528 by instantiate_side_module_from_link_state"
2529 )
2530 };
2531
2532 trace!(
2533 ?module_handle,
2534 ?link_state,
2535 "Instantiating module from link state"
2536 );
2537
2538 let memory_base = linker_state.allocate_memory(
2539 store,
2540 &self.memory,
2541 &pending_module.dylink_info.mem_info,
2542 )?;
2543 let table_base = self
2544 .allocate_function_table(
2545 store,
2546 pending_module.dylink_info.mem_info.table_size,
2547 pending_module.dylink_info.mem_info.table_alignment,
2548 )
2549 .map_err(LinkError::TableAllocationError)?;
2550
2551 trace!(
2552 memory_base,
2553 table_base, "Allocated memory and table for module"
2554 );
2555
2556 let mut imports = import_object_for_all_wasi_versions(&pending_module.module, store, env);
2557
2558 let well_known_imports = [
2559 ("env", "__memory_base", memory_base),
2560 ("env", "__table_base", table_base),
2561 ];
2562
2563 let module = pending_module.module.clone();
2564 let dylink_info = pending_module.dylink_info.clone();
2565
2566 trace!(?module_handle, "Resolving symbols");
2567 linker_state.resolve_symbols(
2568 self,
2569 store,
2570 &module,
2571 module_handle,
2572 link_state,
2573 &well_known_imports,
2574 )?;
2575
2576 trace!(?module_handle, "Populating imports object");
2577 self.populate_imports_from_link_state(
2578 module_handle,
2579 linker_state,
2580 link_state,
2581 store,
2582 &module,
2583 &mut imports,
2584 env,
2585 &well_known_imports,
2586 )?;
2587
2588 let instance = Instance::new(store, &module, &imports)?;
2589
2590 let instance_handles = WasiModuleInstanceHandles::new(
2591 self.memory.clone(),
2592 store,
2593 instance.clone(),
2594 Some(self.indirect_function_table.clone()),
2595 );
2596
2597 let dl_module = DlModule {
2598 module,
2599 dylink_info,
2600 memory_base,
2601 table_base,
2602 };
2603
2604 let dl_instance = DlInstance {
2605 instance: instance.clone(),
2606 instance_handles,
2607 tls_base: Some(memory_base),
2610 };
2611
2612 linker_state.side_modules.insert(module_handle, dl_module);
2613 self.side_instances.insert(module_handle, dl_instance);
2614
2615 trace!(?module_handle, "Module instantiated");
2616
2617 Ok(())
2618 }
2619
2620 fn allocate_function_table_for_existing_module(
2622 &mut self,
2623 linker_state: &LinkerState,
2624 store: &mut impl AsStoreMut,
2625 module_handle: ModuleHandle,
2626 ) -> Result<(), LinkError> {
2627 if self.side_instances.contains_key(&module_handle) {
2628 panic!(
2629 "Internal error: Module with handle {module_handle:?} \
2630 was already instantiated in this group"
2631 )
2632 };
2633
2634 let dl_module = linker_state
2635 .side_modules
2636 .get(&module_handle)
2637 .expect("Internal error: module not loaded into linker");
2638
2639 let table_base = self
2640 .allocate_function_table(
2641 store,
2642 dl_module.dylink_info.mem_info.table_size,
2643 dl_module.dylink_info.mem_info.table_alignment,
2644 )
2645 .map_err(LinkError::TableAllocationError)?;
2646
2647 if table_base != dl_module.table_base {
2648 panic!("Internal error: table base out of sync with linker state");
2649 }
2650
2651 trace!(table_base, "Allocated table indices for existing module");
2652
2653 Ok(())
2654 }
2655
2656 fn instantiate_side_module_from_linker(
2658 &mut self,
2659 linker_state: &LinkerState,
2660 store: &mut impl AsStoreMut,
2661 env: &FunctionEnv<WasiEnv>,
2662 module_handle: ModuleHandle,
2663 pending_resolutions: &mut PendingResolutionsFromLinker,
2664 ) -> Result<(), LinkError> {
2665 if self.side_instances.contains_key(&module_handle) {
2666 panic!(
2667 "Internal error: Module with handle {module_handle:?} \
2668 was already instantiated in this group"
2669 )
2670 };
2671
2672 trace!(?module_handle, "Instantiating existing module from linker");
2673
2674 let dl_module = linker_state
2675 .side_modules
2676 .get(&module_handle)
2677 .expect("Internal error: module not loaded into linker");
2678
2679 let mut imports = import_object_for_all_wasi_versions(&dl_module.module, store, env);
2680
2681 let well_known_imports = [
2682 ("env", "__memory_base", dl_module.memory_base),
2683 ("env", "__table_base", dl_module.table_base),
2684 ];
2685
2686 trace!(?module_handle, "Populating imports object");
2687 self.populate_imports_from_linker(
2688 module_handle,
2689 linker_state,
2690 store,
2691 &dl_module.module,
2692 &mut imports,
2693 env,
2694 &well_known_imports,
2695 pending_resolutions,
2696 )?;
2697
2698 let instance = Instance::new(store, &dl_module.module, &imports)?;
2699
2700 let tls_base = call_initialization_function::<i32>(&instance, store, "__wasix_init_tls")?
2702 .map(|v| v as u64);
2703
2704 let instance_handles = WasiModuleInstanceHandles::new(
2705 self.memory.clone(),
2706 store,
2707 instance.clone(),
2708 Some(self.indirect_function_table.clone()),
2709 );
2710
2711 let dl_instance = DlInstance {
2712 instance: instance.clone(),
2713 instance_handles,
2714 tls_base,
2715 };
2716
2717 self.side_instances.insert(module_handle, dl_instance);
2718
2719 trace!(?module_handle, "Existing module instantiated successfully");
2724
2725 Ok(())
2726 }
2727
2728 fn finalize_pending_resolutions_from_linker(
2729 &self,
2730 pending_resolutions: &PendingResolutionsFromLinker,
2731 store: &mut impl AsStoreMut,
2732 ) -> Result<(), LinkError> {
2733 trace!("Finalizing pending functions");
2734
2735 for pending in &pending_resolutions.functions {
2736 let func = self
2737 .instance(pending.resolved_from)
2738 .exports
2739 .get_function(&pending.name)
2740 .unwrap_or_else(|e| {
2741 panic!(
2742 "Internal error: failed to resolve exported function {}: {e:?}",
2743 pending.name
2744 )
2745 });
2746
2747 self.place_in_function_table_at(store, func.clone(), pending.function_table_index)
2748 .map_err(LinkError::TableAllocationError)?;
2749
2750 trace!(?pending, "Placed pending function in table");
2751 }
2752
2753 for tls in &pending_resolutions.tls {
2754 let Some(tls_base) = self.tls_base(tls.resolved_from) else {
2755 panic!(
2759 "Internal error: Tried to import TLS symbol from module {} that \
2760 has no TLS base",
2761 tls.resolved_from.0
2762 );
2763 };
2764
2765 let final_addr = tls_base + tls.offset;
2766 set_integer_global(store, "<pending TLS global>", &tls.global, final_addr)?;
2767 trace!(?tls, tls_base, final_addr, "Setting pending TLS global");
2768 }
2769
2770 Ok(())
2771 }
2772
2773 fn apply_resolved_function(
2774 &self,
2775 store: &mut impl AsStoreMut,
2776 name: &str,
2777 resolved_from: ModuleHandle,
2778 function_table_index: u32,
2779 ) -> Result<(), LinkError> {
2780 trace!(
2781 ?name,
2782 ?resolved_from,
2783 function_table_index,
2784 "Applying resolved function"
2785 );
2786
2787 let instance = &self.try_instance(resolved_from).unwrap_or_else(|| {
2788 panic!("Internal error: module {resolved_from:?} not loaded by this group")
2789 });
2790
2791 let func = instance.exports.get_function(name).unwrap_or_else(|e| {
2792 panic!("Internal error: failed to resolve exported function {name}: {e:?}")
2793 });
2794
2795 self.place_in_function_table_at(store, func.clone(), function_table_index)
2796 .map_err(LinkError::TableAllocationError)?;
2797
2798 Ok(())
2799 }
2800
2801 pub fn apply_function_table_allocation(
2802 &mut self,
2803 store: &mut impl AsStoreMut,
2804 index: u32,
2805 size: u32,
2806 ) -> Result<(), LinkError> {
2807 trace!(index, "Applying function table allocation");
2808 let allocated_index = self
2809 .allocate_function_table(store, size, 0)
2810 .map_err(LinkError::TableAllocationError)? as u32;
2811 if allocated_index != index {
2812 panic!(
2813 "Internal error: allocated index {allocated_index} does not match expected index {index}"
2814 );
2815 }
2816 Ok(())
2817 }
2818
2819 fn apply_dl_operation(
2820 &mut self,
2821 linker_state: &LinkerState,
2822 operation: DlOperation,
2823 store: &mut impl AsStoreMut,
2824 env: &FunctionEnv<WasiEnv>,
2825 ) -> Result<(), LinkError> {
2826 trace!(?operation, "Applying operation");
2827 match operation {
2828 DlOperation::LoadModules(module_handles) => {
2829 let mut pending_functions = PendingResolutionsFromLinker::default();
2830 for handle in module_handles {
2831 self.allocate_function_table_for_existing_module(linker_state, store, handle)?;
2837 self.instantiate_side_module_from_linker(
2838 linker_state,
2839 store,
2840 env,
2841 handle,
2842 &mut pending_functions,
2843 )?;
2844 }
2845 self.finalize_pending_resolutions_from_linker(&pending_functions, store)?;
2846 }
2847 DlOperation::ResolveFunction {
2848 name,
2849 resolved_from,
2850 function_table_index,
2851 } => self.apply_resolved_function(store, &name, resolved_from, function_table_index)?,
2852 DlOperation::AllocateFunctionTable { index, size } => {
2853 self.apply_function_table_allocation(store, index, size)?
2854 }
2855 };
2856 trace!("Operation applied successfully");
2857 Ok(())
2858 }
2859
2860 fn apply_requested_symbols_from_linker(
2861 &self,
2862 store: &mut impl AsStoreMut,
2863 linker_state: &LinkerState,
2864 ) -> Result<(), LinkError> {
2865 for (key, val) in &linker_state.symbol_resolution_records {
2866 if let SymbolResolutionKey::Requested { name, .. } = key {
2867 if let SymbolResolutionResult::FunctionPointer {
2868 resolved_from,
2869 function_table_index,
2870 } = val
2871 {
2872 self.apply_resolved_function(
2873 store,
2874 name,
2875 *resolved_from,
2876 *function_table_index,
2877 )?;
2878 }
2879 }
2880 }
2881 Ok(())
2882 }
2883
2884 fn resolve_exported_symbol(&self, symbol: &str) -> Option<(ModuleHandle, &Extern)> {
2887 if let Some(export) = self
2888 .main_instance()
2889 .and_then(|instance| instance.exports.get_extern(symbol))
2890 {
2891 trace!(symbol, from = ?MAIN_MODULE_HANDLE, ?export, "Resolved exported symbol");
2892 Some((MAIN_MODULE_HANDLE, export))
2893 } else {
2894 for (handle, dl_instance) in &self.side_instances {
2895 if let Some(export) = dl_instance.instance.exports.get_extern(symbol) {
2896 trace!(symbol, from = ?handle, ?export, "Resolved exported symbol");
2897 return Some((*handle, export));
2898 }
2899 }
2900
2901 trace!(symbol, "Failed to resolve exported symbol");
2902 None
2903 }
2904 }
2905
2906 fn populate_imports_from_link_state(
2909 &self,
2910 module_handle: ModuleHandle,
2911 linker_state: &mut LinkerState,
2912 link_state: &mut InProgressLinkState,
2913 store: &mut impl AsStoreMut,
2914 module: &Module,
2915 imports: &mut Imports,
2916 env: &FunctionEnv<WasiEnv>,
2917 well_known_imports: &[(&str, &str, u64)],
2918 ) -> Result<(), LinkError> {
2919 trace!(?module_handle, "Populating imports object from link state");
2920
2921 for import in module.imports() {
2922 if !matches!(import.module(), "env" | "GOT.mem" | "GOT.func") {
2924 continue;
2925 }
2926
2927 if import.module() == "env" {
2929 match import.name() {
2930 "memory" => {
2931 let ExternType::Memory(memory_ty) = import.ty() else {
2932 return Err(LinkError::BadImport(
2933 import.module().to_string(),
2934 import.name().to_string(),
2935 import.ty().clone(),
2936 ));
2937 };
2938 trace!(?module_handle, ?import, "Main memory");
2939
2940 let current_size = self.memory.grow(store, 0)?;
2942 if current_size < memory_ty.minimum {
2943 self.memory.grow(store, memory_ty.minimum - current_size)?;
2944 }
2945
2946 imports.define(
2947 import.module(),
2948 import.name(),
2949 Extern::Memory(self.memory.clone()),
2950 );
2951 continue;
2952 }
2953 "__indirect_function_table" => {
2954 if !matches!(import.ty(), ExternType::Table(ty) if ty.ty == Type::FuncRef) {
2955 return Err(LinkError::BadImport(
2956 import.module().to_string(),
2957 import.name().to_string(),
2958 import.ty().clone(),
2959 ));
2960 }
2961 trace!(?module_handle, ?import, "Function table");
2962 imports.define(
2963 import.module(),
2964 import.name(),
2965 Extern::Table(self.indirect_function_table.clone()),
2966 );
2967 continue;
2968 }
2969 "__stack_pointer" => {
2970 if !matches!(import.ty(), ExternType::Global(ty) if *ty == self.stack_pointer.ty(store))
2971 {
2972 return Err(LinkError::BadImport(
2973 import.module().to_string(),
2974 import.name().to_string(),
2975 import.ty().clone(),
2976 ));
2977 }
2978 trace!(?module_handle, ?import, "Stack pointer");
2979 imports.define(
2980 import.module(),
2981 import.name(),
2982 Extern::Global(self.stack_pointer.clone()),
2983 );
2984 continue;
2985 }
2986 "__c_longjmp" => {
2988 if !matches!(import.ty(), ExternType::Tag(ty) if *ty.params == [Type::I32])
2989 {
2990 return Err(LinkError::BadImport(
2991 import.module().to_string(),
2992 import.name().to_string(),
2993 import.ty().clone(),
2994 ));
2995 }
2996 trace!(?module_handle, ?import, "setjmp/longjmp exception tag");
2997 imports.define(import.module(), import.name(), self.c_longjmp.clone());
2998 continue;
2999 }
3000 "__cpp_exception" => {
3002 if !matches!(import.ty(), ExternType::Tag(ty) if *ty.params == [Type::I32])
3003 {
3004 return Err(LinkError::BadImport(
3005 import.module().to_string(),
3006 import.name().to_string(),
3007 import.ty().clone(),
3008 ));
3009 }
3010 trace!(?module_handle, ?import, "C++ exception tag");
3011 imports.define(import.module(), import.name(), self.cpp_exception.clone());
3012 continue;
3013 }
3014 _ => (),
3015 }
3016 }
3017
3018 if let Some(well_known_value) = well_known_imports.iter().find_map(|i| {
3020 if i.0 == import.module() && i.1 == import.name() {
3021 Some(i.2)
3022 } else {
3023 None
3024 }
3025 }) {
3026 trace!(
3027 ?module_handle,
3028 ?import,
3029 well_known_value,
3030 "Well-known value"
3031 );
3032 imports.define(
3033 import.module(),
3034 import.name(),
3035 define_integer_global_import(store, &import, well_known_value)?,
3036 );
3037 continue;
3038 }
3039
3040 let key = NeededSymbolResolutionKey {
3041 module_handle,
3042 import_module: import.module().to_owned(),
3043 import_name: import.name().to_owned(),
3044 };
3045
3046 let resolution = link_state.symbols.get(&key).unwrap_or_else(|| {
3048 panic!(
3049 "Internal error: missing import resolution '{0}'.{1}",
3050 key.import_module, key.import_name
3051 )
3052 });
3053
3054 trace!(?module_handle, ?import, ?resolution, "Resolution");
3055
3056 match resolution {
3057 InProgressSymbolResolution::Function(module_handle) => {
3058 let func = self
3059 .instance(*module_handle)
3060 .exports
3061 .get_function(import.name())
3062 .expect("Internal error: bad in-progress symbol resolution");
3063 imports.define(import.module(), import.name(), func.clone());
3064 linker_state.symbol_resolution_records.insert(
3065 SymbolResolutionKey::Needed(key.clone()),
3066 SymbolResolutionResult::Function {
3067 ty: func.ty(store),
3068 resolved_from: *module_handle,
3069 },
3070 );
3071 }
3072
3073 InProgressSymbolResolution::StubFunction(func_ty) => {
3074 let func = self.generate_stub_function(
3075 store,
3076 func_ty,
3077 env,
3078 module_handle,
3079 import.name().to_string(),
3080 );
3081 imports.define(import.module(), import.name(), func);
3082 linker_state.symbol_resolution_records.insert(
3083 SymbolResolutionKey::Needed(key.clone()),
3084 SymbolResolutionResult::StubFunction(func_ty.clone()),
3085 );
3086 }
3087
3088 InProgressSymbolResolution::MemGlobal(module_handle) => {
3089 let export = self
3090 .resolve_export_from(
3091 store,
3092 *module_handle,
3093 import.name(),
3094 self.instance(*module_handle),
3095 linker_state.dylink_info(*module_handle),
3096 linker_state.memory_base(*module_handle),
3097 self.tls_base(*module_handle),
3098 true,
3099 )
3100 .expect("Internal error: bad in-progress symbol resolution");
3101
3102 match export {
3103 PartiallyResolvedExport::Global(addr) => {
3104 trace!(?module_handle, ?import, addr, "Memory address");
3105
3106 let global =
3107 define_integer_global_import(store, &import, addr).unwrap();
3108
3109 imports.define(import.module(), import.name(), global);
3110 linker_state.symbol_resolution_records.insert(
3111 SymbolResolutionKey::Needed(key.clone()),
3112 SymbolResolutionResult::Memory(addr),
3113 );
3114 }
3115
3116 PartiallyResolvedExport::Tls { offset, final_addr } => {
3117 trace!(?module_handle, ?import, offset, final_addr, "TLS address");
3118
3119 let global =
3120 define_integer_global_import(store, &import, final_addr).unwrap();
3121
3122 imports.define(import.module(), import.name(), global);
3123 linker_state.symbol_resolution_records.insert(
3124 SymbolResolutionKey::Needed(key.clone()),
3125 SymbolResolutionResult::Tls {
3126 resolved_from: *module_handle,
3127 offset,
3128 },
3129 );
3130 }
3131
3132 PartiallyResolvedExport::Function(_) => {
3133 panic!("Internal error: bad in-progress symbol resolution")
3134 }
3135 }
3136 }
3137
3138 InProgressSymbolResolution::UnresolvedMemGlobal => {
3139 let global = define_integer_global_import(store, &import, 0).unwrap();
3140 imports.define(import.module(), import.name(), global.clone());
3141
3142 link_state
3143 .unresolved_globals
3144 .push(UnresolvedGlobal::Mem(key, global));
3145 }
3146
3147 InProgressSymbolResolution::FuncGlobal(module_handle) => {
3148 let func = self
3149 .instance(*module_handle)
3150 .exports
3151 .get_function(import.name())
3152 .expect("Internal error: bad in-progress symbol resolution");
3153
3154 let func_handle = self
3155 .append_to_function_table(store, func.clone())
3156 .map_err(LinkError::TableAllocationError)?;
3157 trace!(
3158 ?module_handle,
3159 ?import,
3160 index = func_handle,
3161 "Allocated function table index"
3162 );
3163 let global =
3164 define_integer_global_import(store, &import, func_handle as u64).unwrap();
3165
3166 imports.define(import.module(), import.name(), global);
3167 linker_state.symbol_resolution_records.insert(
3168 SymbolResolutionKey::Needed(key.clone()),
3169 SymbolResolutionResult::FunctionPointer {
3170 resolved_from: *module_handle,
3171 function_table_index: func_handle,
3172 },
3173 );
3174 }
3175
3176 InProgressSymbolResolution::UnresolvedFuncGlobal => {
3177 let global = define_integer_global_import(store, &import, 0).unwrap();
3178 imports.define(import.module(), import.name(), global.clone());
3179
3180 link_state
3181 .unresolved_globals
3182 .push(UnresolvedGlobal::Func(key, global));
3183 }
3184 }
3185 }
3186
3187 trace!(?module_handle, "Imports object populated successfully");
3188
3189 Ok(())
3190 }
3191
3192 fn populate_imports_from_linker(
3194 &self,
3195 module_handle: ModuleHandle,
3196 linker_state: &LinkerState,
3197 store: &mut impl AsStoreMut,
3198 module: &Module,
3199 imports: &mut Imports,
3200 env: &FunctionEnv<WasiEnv>,
3201 well_known_imports: &[(&str, &str, u64)],
3202 pending_resolutions: &mut PendingResolutionsFromLinker,
3203 ) -> Result<(), LinkError> {
3204 trace!(
3205 ?module_handle,
3206 "Populating imports object for existing module from linker state"
3207 );
3208
3209 for import in module.imports() {
3210 if !matches!(import.module(), "env" | "GOT.mem" | "GOT.func") {
3212 continue;
3213 }
3214
3215 if import.module() == "env" {
3217 match import.name() {
3218 "memory" => {
3219 if !matches!(import.ty(), ExternType::Memory(_)) {
3220 return Err(LinkError::BadImport(
3221 import.module().to_string(),
3222 import.name().to_string(),
3223 import.ty().clone(),
3224 ));
3225 }
3226 trace!(?module_handle, ?import, "Main memory");
3227 imports.define(
3228 import.module(),
3229 import.name(),
3230 Extern::Memory(self.memory.clone()),
3231 );
3232 continue;
3233 }
3234 "__indirect_function_table" => {
3235 if !matches!(import.ty(), ExternType::Table(ty) if ty.ty == Type::FuncRef) {
3236 return Err(LinkError::BadImport(
3237 import.module().to_string(),
3238 import.name().to_string(),
3239 import.ty().clone(),
3240 ));
3241 }
3242 trace!(?module_handle, ?import, "Function table");
3243 imports.define(
3244 import.module(),
3245 import.name(),
3246 Extern::Table(self.indirect_function_table.clone()),
3247 );
3248 continue;
3249 }
3250 "__stack_pointer" => {
3251 if !matches!(import.ty(), ExternType::Global(ty) if *ty == self.stack_pointer.ty(store))
3252 {
3253 return Err(LinkError::BadImport(
3254 import.module().to_string(),
3255 import.name().to_string(),
3256 import.ty().clone(),
3257 ));
3258 }
3259 trace!(?module_handle, ?import, "Stack pointer");
3260 imports.define(
3261 import.module(),
3262 import.name(),
3263 Extern::Global(self.stack_pointer.clone()),
3264 );
3265 continue;
3266 }
3267 "__c_longjmp" => {
3268 if !matches!(import.ty(), ExternType::Tag(ty) if *ty.params == [Type::I32])
3269 {
3270 return Err(LinkError::BadImport(
3271 import.module().to_string(),
3272 import.name().to_string(),
3273 import.ty().clone(),
3274 ));
3275 }
3276 trace!(?module_handle, ?import, "setjmp/longjmp exception tag");
3277 imports.define(import.module(), import.name(), self.c_longjmp.clone());
3278 continue;
3279 }
3280 "__cpp_exception" => {
3281 if !matches!(import.ty(), ExternType::Tag(ty) if *ty.params == [Type::I32])
3282 {
3283 return Err(LinkError::BadImport(
3284 import.module().to_string(),
3285 import.name().to_string(),
3286 import.ty().clone(),
3287 ));
3288 }
3289 trace!(?module_handle, ?import, "C++ exception tag");
3290 imports.define(import.module(), import.name(), self.cpp_exception.clone());
3291 continue;
3292 }
3293 _ => (),
3294 }
3295 }
3296
3297 if let Some(well_known_value) = well_known_imports.iter().find_map(|i| {
3299 if i.0 == import.module() && i.1 == import.name() {
3300 Some(i.2)
3301 } else {
3302 None
3303 }
3304 }) {
3305 trace!(
3306 ?module_handle,
3307 ?import,
3308 well_known_value,
3309 "Well-known value"
3310 );
3311 imports.define(
3312 import.module(),
3313 import.name(),
3314 define_integer_global_import(store, &import, well_known_value)?,
3315 );
3316 continue;
3317 }
3318
3319 let key = SymbolResolutionKey::Needed(NeededSymbolResolutionKey {
3320 module_handle,
3321 import_module: import.module().to_owned(),
3322 import_name: import.name().to_owned(),
3323 });
3324
3325 let resolution = linker_state
3327 .symbol_resolution_records
3328 .get(&key)
3329 .unwrap_or_else(|| {
3330 panic!(
3331 "Internal error: missing symbol resolution record for '{0}'.{1}",
3332 import.module(),
3333 import.name()
3334 )
3335 });
3336
3337 trace!(?module_handle, ?import, ?resolution, "Resolution");
3338
3339 match resolution {
3340 SymbolResolutionResult::Function { ty, resolved_from } => {
3341 let func = match self.try_instance(*resolved_from) {
3342 Some(instance) => {
3343 trace!(
3344 ?module_handle,
3345 ?import,
3346 ?resolved_from,
3347 "Already have instance to resolve from"
3348 );
3349 instance
3350 .exports
3351 .get_function(import.name())
3352 .expect("Internal error: failed to get exported function")
3353 .clone()
3354 }
3355 None => {
3360 trace!(
3361 ?module_handle,
3362 ?import,
3363 ?resolved_from,
3364 "Don't have instance yet"
3365 );
3366
3367 self.generate_stub_function(
3368 store,
3369 ty,
3370 env,
3371 module_handle,
3372 import.name().to_owned(),
3373 )
3374 }
3375 };
3376 imports.define(import.module(), import.name(), func);
3377 }
3378 SymbolResolutionResult::StubFunction(ty) => {
3379 let func = self.generate_stub_function(
3380 store,
3381 ty,
3382 env,
3383 module_handle,
3384 import.name().to_owned(),
3385 );
3386 imports.define(import.module(), import.name(), func.clone());
3387 }
3388 SymbolResolutionResult::FunctionPointer {
3389 resolved_from,
3390 function_table_index,
3391 } => {
3392 let func = self.try_instance(*resolved_from).map(|instance| {
3393 instance
3394 .exports
3395 .get_function(import.name())
3396 .unwrap_or_else(|e| {
3397 panic!(
3398 "Internal error: failed to resolve function {}: {e:?}",
3399 import.name()
3400 )
3401 })
3402 });
3403 match func {
3404 Some(func) => {
3405 trace!(
3406 ?module_handle,
3407 ?import,
3408 function_table_index,
3409 "Placing function pointer into table"
3410 );
3411 self.place_in_function_table_at(
3412 store,
3413 func.clone(),
3414 *function_table_index,
3415 )
3416 .map_err(LinkError::TableAllocationError)?;
3417 }
3418 None => {
3419 trace!(
3420 ?module_handle,
3421 ?import,
3422 function_table_index,
3423 "Don't have instance yet, creating a pending function"
3424 );
3425 pending_resolutions.functions.push(
3428 PendingFunctionResolutionFromLinkerState {
3429 resolved_from: *resolved_from,
3430 name: import.name().to_string(),
3431 function_table_index: *function_table_index,
3432 },
3433 );
3434 }
3435 };
3436 let global =
3437 define_integer_global_import(store, &import, *function_table_index as u64)?;
3438 imports.define(import.module(), import.name(), global);
3439 }
3440 SymbolResolutionResult::Memory(addr) => {
3441 let global = define_integer_global_import(store, &import, *addr)?;
3442 imports.define(import.module(), import.name(), global);
3443 }
3444 SymbolResolutionResult::Tls {
3445 resolved_from,
3446 offset,
3447 } => {
3448 let global = define_integer_global_import(store, &import, 0)?;
3449 pending_resolutions.tls.push(PendingTlsPointer {
3450 global: global.clone(),
3451 resolved_from: *resolved_from,
3452 offset: *offset,
3453 });
3454 imports.define(import.module(), import.name(), global);
3455 }
3456 }
3457 }
3458
3459 Ok(())
3460 }
3461
3462 fn resolve_export(
3466 &self,
3467 linker_state: &LinkerState,
3468 store: &mut impl AsStoreMut,
3469 module_handle: Option<ModuleHandle>,
3470 symbol: &str,
3471 allow_hidden: bool,
3472 ) -> Result<(PartiallyResolvedExport, ModuleHandle), ResolveError> {
3473 trace!(?module_handle, ?symbol, "Resolving export");
3474 match module_handle {
3475 Some(module_handle) => {
3476 let instance = self
3477 .try_instance(module_handle)
3478 .ok_or(ResolveError::InvalidModuleHandle)?;
3479 let tls_base = self.tls_base(module_handle);
3480 let memory_base = linker_state.memory_base(module_handle);
3481 let dylink_info = linker_state.dylink_info(module_handle);
3482 Ok((
3483 self.resolve_export_from(
3484 store,
3485 module_handle,
3486 symbol,
3487 instance,
3488 dylink_info,
3489 memory_base,
3490 tls_base,
3491 allow_hidden,
3492 )?,
3493 module_handle,
3494 ))
3495 }
3496
3497 None => {
3498 if let Some(instance) = self.main_instance() {
3500 match self.resolve_export_from(
3501 store,
3502 MAIN_MODULE_HANDLE,
3503 symbol,
3504 instance,
3505 &linker_state.main_module_dylink_info,
3506 linker_state.memory_base(MAIN_MODULE_HANDLE),
3507 Some(self.main_instance_tls_base),
3508 allow_hidden,
3509 ) {
3510 Ok(export) => return Ok((export, MAIN_MODULE_HANDLE)),
3511 Err(ResolveError::MissingExport) => (),
3512 Err(e) => return Err(e),
3513 }
3514 }
3515
3516 for (handle, module) in &linker_state.side_modules {
3522 let instance = &self.side_instances[handle];
3523 match self.resolve_export_from(
3524 store,
3525 *handle,
3526 symbol,
3527 &instance.instance,
3528 &module.dylink_info,
3529 linker_state.memory_base(*handle),
3530 instance.tls_base,
3531 allow_hidden,
3532 ) {
3533 Ok(export) => return Ok((export, *handle)),
3534 Err(ResolveError::MissingExport) => (),
3535 Err(e) => return Err(e),
3536 }
3537 }
3538
3539 trace!(
3540 ?module_handle,
3541 ?symbol,
3542 "Failed to locate symbol after searching all instances"
3543 );
3544 Err(ResolveError::MissingExport)
3545 }
3546 }
3547 }
3548
3549 fn resolve_export_from(
3550 &self,
3551 store: &mut impl AsStoreMut,
3552 module_handle: ModuleHandle,
3553 symbol: &str,
3554 instance: &Instance,
3555 dylink_info: &DylinkInfo,
3556 memory_base: u64,
3557 tls_base: Option<u64>,
3558 allow_hidden: bool,
3559 ) -> Result<PartiallyResolvedExport, ResolveError> {
3560 trace!(from = ?module_handle, symbol, "Resolving export from instance");
3561 let export = instance.exports.get_extern(symbol).ok_or_else(|| {
3562 trace!(from = ?module_handle, symbol, "Not found");
3563 ResolveError::MissingExport
3564 })?;
3565
3566 if !allow_hidden
3567 && dylink_info
3568 .export_metadata
3569 .get(symbol)
3570 .map(|flags| flags.contains(wasmparser::SymbolFlags::VISIBILITY_HIDDEN))
3571 .unwrap_or(false)
3572 {
3573 return Err(ResolveError::MissingExport);
3574 }
3575
3576 match export.ty(store) {
3577 ExternType::Function(_) => {
3578 trace!(from = ?module_handle, symbol, "Found function");
3579 Ok(PartiallyResolvedExport::Function(
3580 Function::get_self_from_extern(export).unwrap().clone(),
3581 ))
3582 }
3583 ty @ ExternType::Global(_) => {
3584 let global = Global::get_self_from_extern(export).unwrap();
3585 let value = match global.get(store) {
3586 Value::I32(value) => value as u64,
3587 Value::I64(value) => value as u64,
3588 _ => return Err(ResolveError::InvalidExportType(ty.clone())),
3589 };
3590
3591 let is_tls = dylink_info
3592 .export_metadata
3593 .get(symbol)
3594 .map(|flags| flags.contains(wasmparser::SymbolFlags::TLS))
3595 .unwrap_or(false);
3596
3597 if is_tls {
3598 let Some(tls_base) = tls_base else {
3599 return Err(ResolveError::TlsSymbolWithoutTls);
3600 };
3601 let final_value = value + tls_base;
3602 trace!(
3603 from = ?module_handle,
3604 symbol,
3605 value,
3606 offset = value,
3607 final_value,
3608 "Found TLS global"
3609 );
3610 Ok(PartiallyResolvedExport::Tls {
3611 offset: value,
3612 final_addr: final_value,
3613 })
3614 } else {
3615 let final_value = value + memory_base;
3616 trace!(from = ?module_handle, symbol, value, final_value, "Found global");
3617 Ok(PartiallyResolvedExport::Global(final_value))
3618 }
3619 }
3620 ty => Err(ResolveError::InvalidExportType(ty.clone())),
3621 }
3622 }
3623
3624 fn generate_stub_function(
3625 &self,
3626 store: &mut impl AsStoreMut,
3627 ty: &FunctionType,
3628 env: &FunctionEnv<WasiEnv>,
3629 requesting_module: ModuleHandle,
3630 name: String,
3631 ) -> Function {
3632 trace!(?requesting_module, name, "Generating stub function");
3635
3636 let ty = ty.clone();
3637 let resolved: Mutex<Option<Option<Function>>> = Mutex::new(None);
3638
3639 Function::new_with_env(
3640 store,
3641 env,
3642 ty.clone(),
3643 move |mut env: FunctionEnvMut<'_, WasiEnv>, params: &[Value]| {
3644 let mk_error = || {
3645 RuntimeError::user(Box::new(WasiError::DlSymbolResolutionFailed(name.clone())))
3646 };
3647
3648 let mut resolved_guard = resolved.lock().unwrap();
3649 let func = match *resolved_guard {
3650 None => {
3651 trace!(?requesting_module, name, "Resolving stub function");
3652
3653 let (data, store) = env.data_and_store_mut();
3654 let env_inner = data.inner();
3655 let linker = env_inner.linker().unwrap();
3657
3658 let linker_state = match linker.linker_state.try_write() {
3669 Ok(guard) => {
3670 trace!(
3671 ?requesting_module,
3672 name, "Locked linker state successfully"
3673 );
3674 Some(guard)
3675 }
3676 Err(TryLockError::WouldBlock) => {
3677 trace!(?requesting_module, name, "Failed to lock linker state");
3678 None
3679 }
3680 Err(TryLockError::Poisoned(_)) => {
3681 *resolved_guard = Some(None);
3682 return Err(mk_error());
3683 }
3684 };
3685
3686 let group_guard = linker.instance_group_state.lock().unwrap();
3687 let Some(group_state) = group_guard.as_ref() else {
3688 trace!(?requesting_module, name, "Instance group is already dead");
3689 *resolved_guard = Some(None);
3690 return Err(mk_error());
3691 };
3692
3693 let resolution_key =
3694 SymbolResolutionKey::Needed(NeededSymbolResolutionKey {
3695 module_handle: requesting_module,
3696 import_module: "env".to_owned(),
3697 import_name: name.clone(),
3698 });
3699
3700 match linker_state
3701 .as_ref()
3702 .and_then(|l| l.symbol_resolution_records.get(&resolution_key))
3703 {
3704 Some(SymbolResolutionResult::Function {
3705 resolved_from,
3706 ty: resolved_ty,
3707 }) => {
3708 trace!(
3709 ?requesting_module,
3710 name, "Function was already resolved in the linker"
3711 );
3712
3713 if ty != *resolved_ty {
3714 *resolved_guard = Some(None);
3715 return Err(mk_error());
3716 }
3717
3718 let func = group_state
3719 .instance(*resolved_from)
3720 .exports
3721 .get_function(&name)
3722 .unwrap()
3723 .clone();
3724 *resolved_guard = Some(Some(func.clone()));
3725 func
3726 }
3727 Some(SymbolResolutionResult::StubFunction(_)) | None => {
3728 trace!(?requesting_module, name, "Resolving function");
3729
3730 let Some((resolved_from, export)) =
3731 group_state.resolve_exported_symbol(name.as_str())
3732 else {
3733 trace!(?requesting_module, name, "Failed to resolve symbol");
3734 *resolved_guard = Some(None);
3735 return Err(mk_error());
3736 };
3737 let Extern::Function(func) = export else {
3738 trace!(
3739 ?requesting_module,
3740 name,
3741 ?resolved_from,
3742 "Resolved symbol is not a function"
3743 );
3744 *resolved_guard = Some(None);
3745 return Err(mk_error());
3746 };
3747 if func.ty(&store) != ty {
3748 trace!(
3749 ?requesting_module,
3750 name,
3751 ?resolved_from,
3752 "Resolved function has bad type"
3753 );
3754 *resolved_guard = Some(None);
3755 return Err(mk_error());
3756 }
3757
3758 trace!(
3759 ?requesting_module,
3760 name,
3761 ?resolved_from,
3762 "Function resolved successfully"
3763 );
3764
3765 if let Some(mut linker_state) = linker_state {
3768 trace!(
3769 ?requesting_module,
3770 name,
3771 ?resolved_from,
3772 "Updating linker state with this resolution"
3773 );
3774
3775 *resolved_guard = Some(Some(func.clone()));
3776 linker_state.symbol_resolution_records.insert(
3777 resolution_key,
3778 SymbolResolutionResult::Function {
3779 ty: func.ty(&store),
3780 resolved_from,
3781 },
3782 );
3783 }
3784
3785 func.clone()
3786 }
3787 Some(resolution) => panic!(
3788 "Internal error: resolution record for symbol \
3789 {name} indicates non-function resolution {resolution:?}"
3790 ),
3791 }
3792 }
3793 Some(None) => return Err(mk_error()),
3794 Some(Some(ref func)) => func.clone(),
3795 };
3796 drop(resolved_guard);
3797
3798 let mut store = env.as_store_mut();
3799 func.call(&mut store, params)
3800 .map(|ret| ret.into())
3801 .map_err(crate::flatten_runtime_error)
3802 },
3803 )
3804 }
3805
3806 fn finalize_pending_globals(
3807 &self,
3808 linker_state: &mut LinkerState,
3809 store: &mut impl AsStoreMut,
3810 unresolved_globals: &Vec<UnresolvedGlobal>,
3811 ) -> Result<(), LinkError> {
3812 trace!("Finalizing pending globals");
3813
3814 for unresolved in unresolved_globals {
3815 let key = unresolved.key();
3816 let import_metadata = &linker_state.dylink_info(key.module_handle).import_metadata;
3817 let is_weak = import_metadata
3818 .get(&(key.import_module.to_owned(), key.import_name.to_owned()))
3819 .or_else(|| import_metadata.get(&("env".to_owned(), key.import_name.to_owned())))
3822 .map(|flags| flags.contains(wasmparser::SymbolFlags::BINDING_WEAK))
3823 .unwrap_or(false);
3824 trace!(?unresolved, is_weak, "Resolving pending global");
3825
3826 match (
3827 unresolved,
3828 self.resolve_export(linker_state, store, None, &key.import_name, true),
3829 ) {
3830 (
3831 UnresolvedGlobal::Mem(key, global),
3832 Ok((PartiallyResolvedExport::Global(addr), resolved_from)),
3833 ) => {
3834 trace!(
3835 ?unresolved,
3836 ?resolved_from,
3837 addr,
3838 "Resolved to memory address"
3839 );
3840 set_integer_global(store, &key.import_name, global, addr)?;
3841 linker_state.symbol_resolution_records.insert(
3842 SymbolResolutionKey::Needed(key.clone()),
3843 SymbolResolutionResult::Memory(addr),
3844 );
3845 }
3846
3847 (
3848 UnresolvedGlobal::Mem(key, global),
3849 Ok((PartiallyResolvedExport::Tls { offset, final_addr }, resolved_from)),
3850 ) => {
3851 trace!(
3852 ?unresolved,
3853 ?resolved_from,
3854 offset,
3855 final_addr,
3856 "Resolved to TLS address"
3857 );
3858 set_integer_global(store, &key.import_name, global, final_addr)?;
3859 linker_state.symbol_resolution_records.insert(
3860 SymbolResolutionKey::Needed(key.clone()),
3861 SymbolResolutionResult::Tls {
3862 resolved_from,
3863 offset,
3864 },
3865 );
3866 }
3867
3868 (
3869 UnresolvedGlobal::Func(key, global),
3870 Ok((PartiallyResolvedExport::Function(func), resolved_from)),
3871 ) => {
3872 let func_handle = self
3873 .append_to_function_table(store, func)
3874 .map_err(LinkError::TableAllocationError)?;
3875 trace!(
3876 ?unresolved,
3877 ?resolved_from,
3878 function_table_index = ?func_handle,
3879 "Resolved to function pointer"
3880 );
3881 set_integer_global(store, &key.import_name, global, func_handle as u64)?;
3882 linker_state.symbol_resolution_records.insert(
3883 SymbolResolutionKey::Needed(key.clone()),
3884 SymbolResolutionResult::FunctionPointer {
3885 resolved_from,
3886 function_table_index: func_handle,
3887 },
3888 );
3889 }
3890
3891 (_, Ok(_)) => {
3893 return Err(LinkError::UnresolvedGlobal(
3894 unresolved.import_module().to_string(),
3895 key.import_name.clone(),
3896 Box::new(ResolveError::MissingExport),
3897 ));
3898 }
3899
3900 (_, Err(ResolveError::MissingExport)) if is_weak => {
3902 trace!(?unresolved, "Weak global not found");
3903 set_integer_global(store, &key.import_name, unresolved.global(), 0)?;
3904 linker_state.symbol_resolution_records.insert(
3905 SymbolResolutionKey::Needed(key.clone()),
3906 SymbolResolutionResult::Memory(0),
3907 );
3908 }
3909
3910 (_, Err(e)) => {
3911 return Err(LinkError::UnresolvedGlobal(
3912 "GOT.mem".to_string(),
3913 key.import_name.clone(),
3914 Box::new(e),
3915 ));
3916 }
3917 }
3918 }
3919
3920 Ok(())
3921 }
3922}
3923
3924async fn locate_module(
3925 module_path: &Path,
3926 library_path: &[impl AsRef<Path>],
3927 runtime_path: &[impl AsRef<str>],
3928 calling_module_path: Option<impl AsRef<Path>>,
3929 fs: &WasiFs,
3930) -> Result<(PathBuf, OwnedBuffer), LinkError> {
3931 async fn try_load(
3932 fs: &WasiFsRoot,
3933 path: impl AsRef<Path>,
3934 ) -> Result<(PathBuf, OwnedBuffer), FsError> {
3935 let mut file = match fs.new_open_options().read(true).open(path.as_ref()) {
3936 Ok(f) => f,
3937 Err(_) if path.as_ref().extension() == Some(OsStr::new("so")) => fs
3940 .new_open_options()
3941 .read(true)
3942 .open(path.as_ref().with_extension("wasm"))?,
3943 Err(e) => return Err(e),
3944 };
3945
3946 let buf = if let Some(buf) = file.as_owned_buffer() {
3947 buf
3948 } else {
3949 let mut buf = Vec::new();
3950 file.read_to_end(&mut buf).await?;
3951 OwnedBuffer::from(buf)
3952 };
3953
3954 Ok((path.as_ref().to_owned(), buf))
3955 }
3956
3957 if module_path.is_absolute() {
3958 trace!(?module_path, "Locating module with absolute path");
3959 try_load(&fs.root_fs, module_path).await.map_err(|e| {
3960 LinkError::SharedLibraryMissing(
3961 module_path.to_string_lossy().into_owned(),
3962 LocateModuleError::Single(e),
3963 )
3964 })
3965 } else if module_path.components().count() > 1 {
3966 trace!(?module_path, "Locating module with relative path");
3967 try_load(
3968 &fs.root_fs,
3969 fs.relative_path_to_absolute(module_path.to_string_lossy().into_owned()),
3970 )
3971 .await
3972 .map_err(|e| {
3973 LinkError::SharedLibraryMissing(
3974 module_path.to_string_lossy().into_owned(),
3975 LocateModuleError::Single(e),
3976 )
3977 })
3978 } else {
3979 trace!(
3986 ?module_path,
3987 "Locating module by name in default runtime path"
3988 );
3989
3990 let calling_module_dir = calling_module_path
3991 .as_ref()
3992 .map(|p| p.as_ref().parent().unwrap_or_else(|| p.as_ref()));
3993
3994 let runtime_path = runtime_path.iter().map(|path| {
3995 let path = path.as_ref();
3996
3997 let relative = path
3998 .strip_prefix("$ORIGIN")
3999 .or_else(|| path.strip_prefix("${ORIGIN}"));
4000
4001 match relative {
4002 Some(relative) => {
4003 let Some(calling_module_dir) = calling_module_dir else {
4004 panic!(
4010 "Internal error: $ORIGIN or ${{ORIGIN}} in RUNPATH, but \
4011 no calling module path provided"
4012 );
4013 };
4014 Cow::Owned(PathBuf::from(
4015 fs.relative_path_to_absolute(
4016 calling_module_dir
4017 .join(relative)
4018 .to_string_lossy()
4019 .into_owned(),
4020 ),
4021 ))
4022 }
4023 None => Cow::Borrowed(Path::new(path)),
4024 }
4025 });
4026
4027 let search_paths = library_path
4029 .iter()
4030 .map(|path| Cow::Borrowed(path.as_ref()))
4031 .chain(runtime_path)
4032 .chain(
4033 DEFAULT_RUNTIME_PATH
4034 .iter()
4035 .map(|path| Cow::Borrowed(Path::new(path))),
4036 );
4037
4038 let mut errors: Vec<(PathBuf, FsError)> = Vec::new();
4039 for path in search_paths {
4040 let full_path = path.join(module_path);
4041 trace!(search_path = ?path, full_path = ?full_path, "Searching module");
4042 match try_load(&fs.root_fs, &full_path).await {
4043 Ok(ret) => {
4044 trace!(?module_path, full_path = ?ret.0, "Located module");
4045 return Ok(ret);
4046 }
4047 Err(e) => errors.push((full_path, e)),
4048 };
4049 }
4050
4051 trace!(?module_path, "Failed to locate module");
4052 Err(LinkError::SharedLibraryMissing(
4053 module_path.to_string_lossy().into_owned(),
4054 LocateModuleError::Multiple(errors),
4055 ))
4056 }
4057}
4058
4059pub fn is_dynamically_linked(module: &Module) -> bool {
4060 module.custom_sections("dylink.0").next().is_some()
4061}
4062
4063const WASM_DYLINK_RUNTIME_PATH: u8 = 5;
4065
4066pub fn parse_dylink0_section(module: &Module) -> Result<DylinkInfo, LinkError> {
4067 let mut sections = module.custom_sections("dylink.0");
4068
4069 let Some(section) = sections.next() else {
4070 return Err(LinkError::NotDynamicLibrary);
4071 };
4072
4073 let None = sections.next() else {
4075 return Err(LinkError::NotDynamicLibrary);
4076 };
4077
4078 let reader = wasmparser::Dylink0SectionReader::new(wasmparser::BinaryReader::new(§ion, 0));
4079
4080 let mut mem_info = None;
4081 let mut needed = None;
4082 let mut import_metadata = HashMap::new();
4083 let mut export_metadata = HashMap::new();
4084 let mut runtime_path = Vec::new();
4085
4086 for subsection in reader {
4087 let subsection = subsection?;
4088 match subsection {
4089 wasmparser::Dylink0Subsection::MemInfo(m) => {
4090 mem_info = Some(m);
4091 }
4092
4093 wasmparser::Dylink0Subsection::Needed(n) => {
4094 needed = Some(n.iter().map(|s| s.to_string()).collect::<Vec<_>>());
4095 }
4096
4097 wasmparser::Dylink0Subsection::ImportInfo(i) => {
4098 for i in i {
4099 import_metadata.insert((i.module.to_owned(), i.field.to_owned()), i.flags);
4100 }
4101 }
4102
4103 wasmparser::Dylink0Subsection::ExportInfo(e) => {
4104 for e in e {
4105 export_metadata.insert(e.name.to_owned(), e.flags);
4106 }
4107 }
4108
4109 wasmparser::Dylink0Subsection::Unknown {
4110 ty: WASM_DYLINK_RUNTIME_PATH,
4111 data,
4112 range,
4113 } => {
4114 let mut reader = wasmparser::BinaryReader::new(data, range.start);
4115 runtime_path.extend(
4116 (0..reader.read_var_u32()?)
4117 .map(|_| reader.read_string().map(ToOwned::to_owned))
4118 .collect::<Result<Vec<_>, _>>()?
4119 .into_iter(),
4120 )
4121 }
4122
4123 wasmparser::Dylink0Subsection::Unknown { ty, .. } => {
4124 tracing::warn!("Skipping unknown dylink.0 subsection {ty}");
4125 }
4126 }
4127 }
4128
4129 Ok(DylinkInfo {
4130 mem_info: mem_info.unwrap_or(wasmparser::MemInfo {
4131 memory_size: 0,
4132 memory_alignment: 0,
4133 table_size: 0,
4134 table_alignment: 0,
4135 }),
4136 needed: needed.unwrap_or_default(),
4137 import_metadata,
4138 export_metadata,
4139 runtime_path,
4140 })
4141}
4142
4143fn get_integer_global_type_from_import(import: &ImportType) -> Result<GlobalType, LinkError> {
4144 let import_type = import.ty();
4145 let ExternType::Global(ty) = import_type else {
4146 return Err(LinkError::BadImport(
4147 import.module().to_owned(),
4148 import.name().to_owned(),
4149 import_type.clone(),
4150 ));
4151 };
4152
4153 if !matches!(ty.ty, Type::I32 | Type::I64) {
4154 return Err(LinkError::NonIntegerGlobal(
4155 import.module().to_owned(),
4156 import.name().to_owned(),
4157 ));
4158 }
4159
4160 Ok(*ty)
4161}
4162
4163fn define_integer_global_import(
4164 store: &mut impl AsStoreMut,
4165 import: &ImportType,
4166 value: u64,
4167) -> Result<Global, LinkError> {
4168 let ExternType::Global(GlobalType { ty, mutability }) = import.ty() else {
4169 return Err(LinkError::BadImport(
4170 import.module().to_string(),
4171 import.name().to_string(),
4172 import.ty().clone(),
4173 ));
4174 };
4175
4176 let new_global = if mutability.is_mutable() {
4177 Global::new_mut
4178 } else {
4179 Global::new
4180 };
4181
4182 let global = match ty {
4183 Type::I32 => new_global(store, wasmer::Value::I32(value as i32)),
4184 Type::I64 => new_global(store, wasmer::Value::I64(value as i64)),
4185 _ => {
4186 return Err(LinkError::BadImport(
4187 import.module().to_string(),
4188 import.name().to_string(),
4189 import.ty().clone(),
4190 ));
4191 }
4192 };
4193
4194 Ok(global)
4195}
4196
4197fn set_integer_global(
4198 store: &mut impl AsStoreMut,
4199 name: &str,
4200 global: &Global,
4201 value: u64,
4202) -> Result<(), LinkError> {
4203 match global.ty(store).ty {
4204 Type::I32 => global
4205 .set(store, Value::I32(value as i32))
4206 .map_err(|e| LinkError::GlobalUpdateFailed(name.to_owned(), e))?,
4207 Type::I64 => global
4208 .set(store, Value::I64(value as i64))
4209 .map_err(|e| LinkError::GlobalUpdateFailed(name.to_owned(), e))?,
4210 _ => {
4211 unreachable!("Internal error: expected global of type I32 or I64");
4213 }
4214 }
4215
4216 Ok(())
4217}
4218
4219fn call_initialization_function<Ret: WasmTypeList>(
4220 instance: &Instance,
4221 store: &mut impl AsStoreMut,
4222 name: &str,
4223) -> Result<Option<Ret>, LinkError> {
4224 match instance.exports.get_typed_function::<(), Ret>(store, name) {
4225 Ok(f) => {
4226 let ret = f
4227 .call(store)
4228 .map_err(|e| LinkError::InitFunctionFailed(name.to_string(), e))?;
4229 Ok(Some(ret))
4230 }
4231 Err(ExportError::Missing(_)) => Ok(None),
4232 Err(ExportError::IncompatibleType) => {
4233 Err(LinkError::InitFuncWithInvalidSignature(name.to_string()))
4234 }
4235 }
4236}
4237
4238#[cfg(test)]
4239mod memory_allocator_tests {
4240 use wasmer::{Engine, Memory, Store};
4241
4242 use super::MemoryAllocator;
4243
4244 const WASM_PAGE_SIZE: u32 = wasmer::WASM_PAGE_SIZE as u32;
4245
4246 #[test]
4247 fn test_memory_allocator() {
4248 let engine = Engine::default();
4249 let mut store = Store::new(engine);
4250 let memory = Memory::new(
4251 &mut store,
4252 wasmer::MemoryType {
4253 minimum: wasmer::Pages(2),
4254 maximum: None,
4255 shared: true,
4256 },
4257 )
4258 .unwrap();
4259 let mut allocator = MemoryAllocator::new();
4260
4261 let addr = allocator.allocate(&memory, &mut store, 24, 4).unwrap();
4263 assert_eq!(addr, 2 * WASM_PAGE_SIZE);
4264 assert_eq!(memory.grow(&mut store, 0).unwrap().0, 3);
4265
4266 let addr = allocator.allocate(&memory, &mut store, 16, 4).unwrap();
4268 assert_eq!(addr, 2 * WASM_PAGE_SIZE + 24);
4269
4270 let addr = allocator.allocate(&memory, &mut store, 64, 32).unwrap();
4272 assert_eq!(addr, 2 * WASM_PAGE_SIZE + 64);
4273 assert_eq!(memory.grow(&mut store, 0).unwrap().0, 3);
4275
4276 let addr = allocator
4278 .allocate(&memory, &mut store, 2 * WASM_PAGE_SIZE + 256, 1024)
4279 .unwrap();
4280 assert_eq!(addr, WASM_PAGE_SIZE * 3);
4281 assert_eq!(memory.grow(&mut store, 0).unwrap().0, 6);
4282
4283 let addr = allocator
4287 .allocate(&memory, &mut store, 1024 * 63, 64)
4288 .unwrap();
4289 assert_eq!(addr, 5 * WASM_PAGE_SIZE + 256);
4290
4291 let addr = allocator.allocate(&memory, &mut store, 4096, 512).unwrap();
4293 assert_eq!(addr, 2 * WASM_PAGE_SIZE + 512);
4294 }
4295}