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