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