1use std::sync::{Mutex, TryLockError};
2
3use tracing::trace;
4use wasmer::{
5 AsStoreMut, Extern, ExternType, Function, FunctionEnv, FunctionEnvMut, FunctionType,
6 ImportType, Imports, Module, RuntimeError, Type, Value,
7};
8
9use crate::{WasiEnv, WasiError, flatten_runtime_error};
10
11use super::{
12 InProgressLinkState, InProgressSymbolResolution, InstanceGroupState, LinkError, LinkerState,
13 ModuleHandle, NeededSymbolResolutionKey, PartiallyResolvedExport,
14 PendingFunctionResolutionFromLinkerState, PendingResolutionsFromLinker, PendingTlsPointer,
15 ResolveError, SymbolResolutionKey, SymbolResolutionResult, UnresolvedGlobal,
16 define_integer_global_import,
17};
18
19#[derive(Clone, Copy)]
20enum MemoryImportMode {
21 GrowToMinimum,
22 DefineOnly,
23}
24
25impl InstanceGroupState {
26 pub(in crate::state::linker) fn populate_imports_from_link_state(
29 &self,
30 module_handle: ModuleHandle,
31 linker_state: &mut LinkerState,
32 link_state: &mut InProgressLinkState,
33 store: &mut impl AsStoreMut,
34 module: &Module,
35 imports: &mut Imports,
36 env: &FunctionEnv<WasiEnv>,
37 well_known_imports: &[(&str, &str, u64)],
38 ) -> Result<(), LinkError> {
39 trace!(?module_handle, "Populating imports object from link state");
40
41 for import in module.imports() {
42 if !matches!(import.module(), "env" | "GOT.mem" | "GOT.func") {
44 continue;
45 }
46
47 if self.define_common_import(
48 module_handle,
49 store,
50 &import,
51 imports,
52 well_known_imports,
53 MemoryImportMode::GrowToMinimum,
54 )? {
55 continue;
56 }
57
58 let key = NeededSymbolResolutionKey {
59 module_handle,
60 import_module: import.module().to_owned(),
61 import_name: import.name().to_owned(),
62 };
63
64 let resolution = link_state.symbols.get(&key).unwrap_or_else(|| {
66 panic!(
67 "Internal error: missing import resolution '{0}'.{1}",
68 key.import_module, key.import_name
69 )
70 });
71
72 trace!(?module_handle, ?import, ?resolution, "Resolution");
73
74 match resolution {
75 InProgressSymbolResolution::Function(module_handle) => {
76 let func = self
77 .instance(*module_handle)
78 .exports
79 .get_function(import.name())
80 .expect("Internal error: bad in-progress symbol resolution");
81 imports.define(import.module(), import.name(), func.clone());
82 linker_state.symbol_resolution_records.insert(
83 SymbolResolutionKey::Needed(key.clone()),
84 SymbolResolutionResult::Function {
85 ty: func.ty(store),
86 resolved_from: *module_handle,
87 },
88 );
89 }
90
91 InProgressSymbolResolution::StubFunction(func_ty) => {
92 let func = self.generate_stub_function(
93 store,
94 func_ty,
95 env,
96 module_handle,
97 import.name().to_string(),
98 );
99 imports.define(import.module(), import.name(), func);
100 linker_state.symbol_resolution_records.insert(
101 SymbolResolutionKey::Needed(key.clone()),
102 SymbolResolutionResult::StubFunction(func_ty.clone()),
103 );
104 }
105
106 InProgressSymbolResolution::MemGlobal(module_handle) => {
107 let export = match self.resolve_export_from(
108 store,
109 *module_handle,
110 import.name(),
111 self.instance(*module_handle),
112 linker_state.dylink_info(*module_handle),
113 linker_state.memory_base(*module_handle),
114 self.tls_base(*module_handle),
115 true,
116 ) {
117 Ok(export) => export,
118 Err(ResolveError::NoTlsBaseGlobalExport) => {
119 return Err(LinkError::MissingTlsBaseExport(
120 import.name().to_string(),
121 *module_handle,
122 ));
123 }
124 Err(e) => {
125 panic!("Internal error: bad in-progress symbol resolution: {e:?}")
126 }
127 };
128
129 match export {
130 PartiallyResolvedExport::Global(addr) => {
131 trace!(?module_handle, ?import, addr, "Memory address");
132
133 let global =
134 define_integer_global_import(store, &import, addr).unwrap();
135
136 imports.define(import.module(), import.name(), global);
137 linker_state.symbol_resolution_records.insert(
138 SymbolResolutionKey::Needed(key.clone()),
139 SymbolResolutionResult::Memory(addr),
140 );
141 }
142
143 PartiallyResolvedExport::Tls { offset, final_addr } => {
144 trace!(?module_handle, ?import, offset, final_addr, "TLS address");
145
146 let global =
147 define_integer_global_import(store, &import, final_addr).unwrap();
148
149 imports.define(import.module(), import.name(), global);
150 linker_state.symbol_resolution_records.insert(
151 SymbolResolutionKey::Needed(key.clone()),
152 SymbolResolutionResult::Tls {
153 resolved_from: *module_handle,
154 offset,
155 },
156 );
157 }
158
159 PartiallyResolvedExport::Function(_) => {
160 panic!("Internal error: bad in-progress symbol resolution")
161 }
162 }
163 }
164
165 InProgressSymbolResolution::UnresolvedMemGlobal => {
166 let global = define_integer_global_import(store, &import, 0).unwrap();
167 imports.define(import.module(), import.name(), global.clone());
168
169 link_state
170 .unresolved_globals
171 .push(UnresolvedGlobal::Mem(key, global));
172 }
173
174 InProgressSymbolResolution::FuncGlobal(module_handle) => {
175 let func = self
176 .instance(*module_handle)
177 .exports
178 .get_function(import.name())
179 .expect("Internal error: bad in-progress symbol resolution");
180
181 let func_handle = self
182 .append_to_function_table(store, func.clone())
183 .map_err(LinkError::TableAllocationError)?;
184 trace!(
185 ?module_handle,
186 ?import,
187 index = func_handle,
188 "Allocated function table index"
189 );
190 let global =
191 define_integer_global_import(store, &import, func_handle as u64).unwrap();
192
193 imports.define(import.module(), import.name(), global);
194 linker_state.symbol_resolution_records.insert(
195 SymbolResolutionKey::Needed(key.clone()),
196 SymbolResolutionResult::FunctionPointer {
197 resolved_from: *module_handle,
198 function_table_index: func_handle,
199 },
200 );
201 }
202
203 InProgressSymbolResolution::UnresolvedFuncGlobal => {
204 let global = define_integer_global_import(store, &import, 0).unwrap();
205 imports.define(import.module(), import.name(), global.clone());
206
207 link_state
208 .unresolved_globals
209 .push(UnresolvedGlobal::Func(key, global));
210 }
211 }
212 }
213
214 trace!(?module_handle, "Imports object populated successfully");
215
216 Ok(())
217 }
218
219 pub(in crate::state::linker) fn populate_imports_from_linker(
221 &self,
222 module_handle: ModuleHandle,
223 linker_state: &LinkerState,
224 store: &mut impl AsStoreMut,
225 module: &Module,
226 imports: &mut Imports,
227 env: &FunctionEnv<WasiEnv>,
228 well_known_imports: &[(&str, &str, u64)],
229 pending_resolutions: &mut PendingResolutionsFromLinker,
230 ) -> Result<(), LinkError> {
231 trace!(
232 ?module_handle,
233 "Populating imports object for existing module from linker state"
234 );
235
236 for import in module.imports() {
237 if !matches!(import.module(), "env" | "GOT.mem" | "GOT.func") {
239 continue;
240 }
241
242 if self.define_common_import(
243 module_handle,
244 store,
245 &import,
246 imports,
247 well_known_imports,
248 MemoryImportMode::DefineOnly,
249 )? {
250 continue;
251 }
252
253 let key = SymbolResolutionKey::Needed(NeededSymbolResolutionKey {
254 module_handle,
255 import_module: import.module().to_owned(),
256 import_name: import.name().to_owned(),
257 });
258
259 let resolution = linker_state
261 .symbol_resolution_records
262 .get(&key)
263 .unwrap_or_else(|| {
264 panic!(
265 "Internal error: missing symbol resolution record for '{0}'.{1}",
266 import.module(),
267 import.name()
268 )
269 });
270
271 trace!(?module_handle, ?import, ?resolution, "Resolution");
272
273 match resolution {
274 SymbolResolutionResult::Function { ty, resolved_from } => {
275 let func = match self.try_instance(*resolved_from) {
276 Some(instance) => {
277 trace!(
278 ?module_handle,
279 ?import,
280 ?resolved_from,
281 "Already have instance to resolve from"
282 );
283 instance
284 .exports
285 .get_function(import.name())
286 .expect("Internal error: failed to get exported function")
287 .clone()
288 }
289 None => {
294 trace!(
295 ?module_handle,
296 ?import,
297 ?resolved_from,
298 "Don't have instance yet"
299 );
300
301 self.generate_stub_function(
302 store,
303 ty,
304 env,
305 module_handle,
306 import.name().to_owned(),
307 )
308 }
309 };
310 imports.define(import.module(), import.name(), func);
311 }
312 SymbolResolutionResult::StubFunction(ty) => {
313 let func = self.generate_stub_function(
314 store,
315 ty,
316 env,
317 module_handle,
318 import.name().to_owned(),
319 );
320 imports.define(import.module(), import.name(), func.clone());
321 }
322 SymbolResolutionResult::FunctionPointer {
323 resolved_from,
324 function_table_index,
325 } => {
326 let func = self.try_instance(*resolved_from).map(|instance| {
327 instance
328 .exports
329 .get_function(import.name())
330 .unwrap_or_else(|e| {
331 panic!(
332 "Internal error: failed to resolve function {}: {e:?}",
333 import.name()
334 )
335 })
336 });
337 match func {
338 Some(func) => {
339 trace!(
340 ?module_handle,
341 ?import,
342 function_table_index,
343 "Placing function pointer into table"
344 );
345 self.place_in_function_table_at(
346 store,
347 func.clone(),
348 *function_table_index,
349 )
350 .map_err(LinkError::TableAllocationError)?;
351 }
352 None => {
353 trace!(
354 ?module_handle,
355 ?import,
356 function_table_index,
357 "Don't have instance yet, creating a pending function"
358 );
359 pending_resolutions.functions.push(
362 PendingFunctionResolutionFromLinkerState {
363 resolved_from: *resolved_from,
364 name: import.name().to_string(),
365 function_table_index: *function_table_index,
366 },
367 );
368 }
369 };
370 let global =
371 define_integer_global_import(store, &import, *function_table_index as u64)?;
372 imports.define(import.module(), import.name(), global);
373 }
374 SymbolResolutionResult::Memory(addr) => {
375 let global = define_integer_global_import(store, &import, *addr)?;
376 imports.define(import.module(), import.name(), global);
377 }
378 SymbolResolutionResult::Tls {
379 resolved_from,
380 offset,
381 } => {
382 let global = define_integer_global_import(store, &import, 0)?;
383 pending_resolutions.tls.push(PendingTlsPointer {
384 global: global.clone(),
385 resolved_from: *resolved_from,
386 offset: *offset,
387 });
388 imports.define(import.module(), import.name(), global);
389 }
390 }
391 }
392
393 Ok(())
394 }
395
396 fn define_common_import(
397 &self,
398 module_handle: ModuleHandle,
399 store: &mut impl AsStoreMut,
400 import: &ImportType,
401 imports: &mut Imports,
402 well_known_imports: &[(&str, &str, u64)],
403 memory_import_mode: MemoryImportMode,
404 ) -> Result<bool, LinkError> {
405 if import.module() == "env" {
407 match import.name() {
408 "memory" => {
409 let ExternType::Memory(memory_ty) = import.ty() else {
410 return Err(LinkError::BadImport(
411 import.module().to_string(),
412 import.name().to_string(),
413 import.ty().clone(),
414 ));
415 };
416 trace!(?module_handle, ?import, "Main memory");
417
418 if matches!(memory_import_mode, MemoryImportMode::GrowToMinimum) {
419 let current_size = self.memory.grow(store, 0)?;
421 if current_size < memory_ty.minimum {
422 self.memory.grow(store, memory_ty.minimum - current_size)?;
423 }
424 }
425
426 imports.define(
427 import.module(),
428 import.name(),
429 Extern::Memory(self.memory.clone()),
430 );
431 return Ok(true);
432 }
433 "__indirect_function_table" => {
434 if !matches!(import.ty(), ExternType::Table(ty) if ty.ty == Type::FuncRef) {
435 return Err(LinkError::BadImport(
436 import.module().to_string(),
437 import.name().to_string(),
438 import.ty().clone(),
439 ));
440 }
441 trace!(?module_handle, ?import, "Function table");
442 imports.define(
443 import.module(),
444 import.name(),
445 Extern::Table(self.indirect_function_table.clone()),
446 );
447 return Ok(true);
448 }
449 "__stack_pointer" => {
450 if !matches!(import.ty(), ExternType::Global(ty) if *ty == self.stack_pointer.ty(store))
451 {
452 return Err(LinkError::BadImport(
453 import.module().to_string(),
454 import.name().to_string(),
455 import.ty().clone(),
456 ));
457 }
458 trace!(?module_handle, ?import, "Stack pointer");
459 imports.define(
460 import.module(),
461 import.name(),
462 Extern::Global(self.stack_pointer.clone()),
463 );
464 return Ok(true);
465 }
466 "__c_longjmp" => {
468 if !matches!(import.ty(), ExternType::Tag(ty) if *ty.params == [Type::I32]) {
469 return Err(LinkError::BadImport(
470 import.module().to_string(),
471 import.name().to_string(),
472 import.ty().clone(),
473 ));
474 }
475 trace!(?module_handle, ?import, "setjmp/longjmp exception tag");
476 imports.define(import.module(), import.name(), self.c_longjmp.clone());
477 return Ok(true);
478 }
479 "__cpp_exception" => {
481 if !matches!(import.ty(), ExternType::Tag(ty) if *ty.params == [Type::I32]) {
482 return Err(LinkError::BadImport(
483 import.module().to_string(),
484 import.name().to_string(),
485 import.ty().clone(),
486 ));
487 }
488 trace!(?module_handle, ?import, "C++ exception tag");
489 imports.define(import.module(), import.name(), self.cpp_exception.clone());
490 return Ok(true);
491 }
492 _ => (),
493 }
494 }
495
496 if let Some(well_known_value) = well_known_imports.iter().find_map(|i| {
497 if i.0 == import.module() && i.1 == import.name() {
498 Some(i.2)
499 } else {
500 None
501 }
502 }) {
503 trace!(
504 ?module_handle,
505 ?import,
506 well_known_value,
507 "Well-known value"
508 );
509 imports.define(
510 import.module(),
511 import.name(),
512 define_integer_global_import(store, import, well_known_value)?,
513 );
514 return Ok(true);
515 }
516
517 Ok(false)
518 }
519
520 fn generate_stub_function(
521 &self,
522 store: &mut impl AsStoreMut,
523 ty: &FunctionType,
524 env: &FunctionEnv<WasiEnv>,
525 requesting_module: ModuleHandle,
526 name: String,
527 ) -> Function {
528 trace!(?requesting_module, name, "Generating stub function");
531
532 let ty = ty.clone();
533 let resolved: Mutex<Option<Option<Function>>> = Mutex::new(None);
534
535 Function::new_with_env(
536 store,
537 env,
538 ty.clone(),
539 move |mut env: FunctionEnvMut<'_, WasiEnv>, params: &[Value]| {
540 let mk_error = || {
541 RuntimeError::user(Box::new(WasiError::DlSymbolResolutionFailed(name.clone())))
542 };
543
544 let mut resolved_guard = resolved.lock().unwrap();
545 let func = match *resolved_guard {
546 None => {
547 trace!(?requesting_module, name, "Resolving stub function");
548
549 let (data, store) = env.data_and_store_mut();
550 let env_inner = data.inner();
551 let linker = env_inner.linker().unwrap();
553
554 let linker_state = match linker.shared.try_write_linker_state() {
558 Ok(guard) => {
559 trace!(
560 ?requesting_module,
561 name, "Locked linker state successfully"
562 );
563 Some(guard)
564 }
565 Err(TryLockError::WouldBlock) => {
566 trace!(?requesting_module, name, "Failed to lock linker state");
567 None
568 }
569 Err(TryLockError::Poisoned(_)) => {
570 *resolved_guard = Some(None);
571 return Err(mk_error());
572 }
573 };
574
575 let group_guard = linker.instance_group_state.lock().unwrap();
576 let Some(group_state) = group_guard.as_ref() else {
577 trace!(?requesting_module, name, "Instance group is already dead");
578 *resolved_guard = Some(None);
579 return Err(mk_error());
580 };
581
582 let resolution_key =
583 SymbolResolutionKey::Needed(NeededSymbolResolutionKey {
584 module_handle: requesting_module,
585 import_module: "env".to_owned(),
586 import_name: name.clone(),
587 });
588
589 match linker_state
590 .as_ref()
591 .and_then(|l| l.symbol_resolution_records.get(&resolution_key))
592 {
593 Some(SymbolResolutionResult::Function {
594 resolved_from,
595 ty: resolved_ty,
596 }) => {
597 trace!(
598 ?requesting_module,
599 name, "Function was already resolved in the linker"
600 );
601
602 if ty != *resolved_ty {
603 *resolved_guard = Some(None);
604 return Err(mk_error());
605 }
606
607 let func = group_state
608 .instance(*resolved_from)
609 .exports
610 .get_function(&name)
611 .unwrap()
612 .clone();
613 *resolved_guard = Some(Some(func.clone()));
614 func
615 }
616 Some(SymbolResolutionResult::StubFunction(_)) | None => {
617 trace!(?requesting_module, name, "Resolving function");
618
619 let Some((resolved_from, export)) =
620 group_state.resolve_exported_symbol(name.as_str())
621 else {
622 trace!(?requesting_module, name, "Failed to resolve symbol");
623 *resolved_guard = Some(None);
624 return Err(mk_error());
625 };
626 let Extern::Function(func) = export else {
627 trace!(
628 ?requesting_module,
629 name,
630 ?resolved_from,
631 "Resolved symbol is not a function"
632 );
633 *resolved_guard = Some(None);
634 return Err(mk_error());
635 };
636 if func.ty(&store) != ty {
637 trace!(
638 ?requesting_module,
639 name,
640 ?resolved_from,
641 "Resolved function has bad type"
642 );
643 *resolved_guard = Some(None);
644 return Err(mk_error());
645 }
646
647 trace!(
648 ?requesting_module,
649 name,
650 ?resolved_from,
651 "Function resolved successfully"
652 );
653
654 if let Some(mut linker_state) = linker_state {
657 trace!(
658 ?requesting_module,
659 name,
660 ?resolved_from,
661 "Updating linker state with this resolution"
662 );
663
664 *resolved_guard = Some(Some(func.clone()));
665 linker_state.symbol_resolution_records.insert(
666 resolution_key,
667 SymbolResolutionResult::Function {
668 ty: func.ty(&store),
669 resolved_from,
670 },
671 );
672 }
673
674 func.clone()
675 }
676 Some(resolution) => panic!(
677 "Internal error: resolution record for symbol \
678 {name} indicates non-function resolution {resolution:?}"
679 ),
680 }
681 }
682 Some(None) => return Err(mk_error()),
683 Some(Some(ref func)) => func.clone(),
684 };
685 drop(resolved_guard);
686
687 let mut store = env.as_store_mut();
688 func.call(&mut store, params)
689 .map(|ret| ret.into())
690 .map_err(flatten_runtime_error)
691 },
692 )
693 }
694}