1use {
26 crate::encoding::fixup::{AddressDest, FixupModule, ImportedInstance, StartAction},
27 crate::encoding::{ComponentEncoder, Instance, Item, LibraryInfo, MainOrAdapter},
28 anyhow::{Context, Result, anyhow, bail},
29 indexmap::{IndexMap, IndexSet, map::Entry},
30 metadata::{Export, ExportKey, FunctionType, GlobalType, Metadata, Type, ValueType},
31 std::{
32 borrow::Cow,
33 collections::{BTreeMap, HashMap, HashSet},
34 fmt::Debug,
35 hash::Hash,
36 },
37 wasm_encoder::{
38 CodeSection, ConstExpr, Elements, EntityType, ExportKind, ExportSection, Function,
39 FunctionSection, GlobalSection, ImportSection, MemArg, MemorySection, MemoryType, Module,
40 RawCustomSection, RefType, TableSection, TableType, TypeSection, ValType,
41 },
42 wasmparser::SymbolFlags,
43};
44
45pub(crate) mod metadata;
46
47const PAGE_SIZE_BYTES: u32 = 65536;
48pub const DEFAULT_STACK_SIZE_BYTES: u32 = 16 * PAGE_SIZE_BYTES;
50const HEAP_ALIGNMENT_BYTES: u32 = 16;
51const STUB_LIBRARY_NAME: &str = "wit-component:stubs";
52const CABI_REALLOC: &str = "cabi_realloc";
53
54static ENV_REEXPORTS: &[(&str, &[ValueType], &[ValueType])] =
59 &[(metadata::TASK_HOOK, &[ValueType::I32], &[])];
60
61enum Address<'a> {
62 Function(u32),
63 Global(&'a str),
64}
65
66struct DlOpenables<'a> {
71 table_base: u32,
73
74 memory_base: u32,
76
77 buffer: Vec<u8>,
79
80 global_addresses: Vec<(&'a str, &'a str, u32)>,
84
85 function_count: u32,
87
88 libraries_address: u32,
93}
94
95impl<'a> DlOpenables<'a> {
96 fn new(table_base: u32, memory_base: u32, metadata: &'a [Metadata<'a>]) -> Self {
99 let mut function_count = 0;
100 let mut buffer = Vec::new();
101 let mut global_addresses = Vec::new();
102 let mut libraries = metadata
103 .iter()
104 .filter(|metadata| metadata.dl_openable)
105 .map(|metadata| {
106 let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
107 write_bytes_padded(&mut buffer, metadata.name.as_bytes());
108
109 let mut symbols = metadata
110 .exports
111 .iter()
112 .filter_map(|export| {
113 let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
114 write_bytes_padded(&mut buffer, export.key.name.as_bytes());
115
116 let address = match &export.key.ty {
117 Type::Function(_) => Address::Function(
118 table_base + get_and_increment(&mut function_count),
119 ),
120 Type::Global(_) => Address::Global(export.key.name),
121 Type::Tag(_) => return None,
122 };
123
124 Some((export.key.name, name_address, address))
125 })
126 .collect::<Vec<_>>();
127
128 symbols.sort_by_key(|(name, ..)| *name);
129
130 let start = buffer.len();
131 for (name, name_address, address) in symbols {
132 write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
133 write_u32(&mut buffer, name_address);
134 match address {
135 Address::Function(address) => write_u32(&mut buffer, address),
136 Address::Global(name) => {
137 global_addresses.push((
138 metadata.name,
139 name,
140 memory_base + u32::try_from(buffer.len()).unwrap(),
141 ));
142
143 write_u32(&mut buffer, 0);
144 }
145 }
146 }
147
148 (
149 metadata.name,
150 name_address,
151 metadata.exports.len(),
152 memory_base + u32::try_from(start).unwrap(),
153 )
154 })
155 .collect::<Vec<_>>();
156
157 libraries.sort_by_key(|(name, ..)| *name);
158
159 let start = buffer.len();
160 for (name, name_address, count, symbols) in &libraries {
161 write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
162 write_u32(&mut buffer, *name_address);
163 write_u32(&mut buffer, u32::try_from(*count).unwrap());
164 write_u32(&mut buffer, *symbols);
165 }
166
167 let libraries_address = memory_base + u32::try_from(buffer.len()).unwrap();
168 write_u32(&mut buffer, u32::try_from(libraries.len()).unwrap());
169 write_u32(&mut buffer, memory_base + u32::try_from(start).unwrap());
170
171 Self {
172 table_base,
173 memory_base,
174 buffer,
175 global_addresses,
176 function_count,
177 libraries_address,
178 }
179 }
180}
181
182#[derive(Default)]
197struct TlsLayout {
198 main_thread_tls_base: u32,
202
203 library_info: u32,
205
206 program_info: u32,
208
209 slots: Vec<Option<u32>>,
212
213 buffer: Vec<u8>,
215}
216
217impl TlsLayout {
218 fn new(metadata: &[Metadata], memory_offset: &mut u32) -> Self {
226 let needs_tls_base = metadata
227 .iter()
228 .any(|m| m.needs_get_tls_base || m.needs_set_tls_base);
229 let needs_program_info = metadata.iter().any(|m| m.needs_program_tls_info);
230 if !needs_tls_base && !needs_program_info {
231 return Self::default();
232 }
233
234 let libraries = metadata
236 .iter()
237 .enumerate()
238 .filter(|(_, metadata)| metadata.has_library_tls_info)
239 .map(|(index, _)| index)
240 .collect::<Vec<_>>();
241
242 let mut slots = vec![None; metadata.len()];
243 for (slot, index) in libraries.iter().enumerate() {
244 slots[*index] = Some(u32::try_from(slot).unwrap());
245 }
246 let count = u32::try_from(libraries.len()).unwrap();
247
248 *memory_offset = align(*memory_offset, 4);
250 let main_thread_tls_base = *memory_offset;
251 *memory_offset += count * 4;
252
253 let mut library_info = 0;
254 let mut program_info = 0;
255 let mut buffer = Vec::new();
256 if needs_program_info {
257 library_info = *memory_offset;
258 *memory_offset += count * 4;
259 program_info = *memory_offset;
260 *memory_offset += 12;
261
262 write_u32(&mut buffer, count);
263 write_u32(&mut buffer, library_info);
264 write_u32(&mut buffer, main_thread_tls_base);
265 }
266
267 Self {
268 main_thread_tls_base,
269 library_info,
270 program_info,
271 slots,
272 buffer,
273 }
274 }
275
276 fn slot(&self, index: usize) -> Option<u32> {
278 self.slots.get(index).copied().flatten()
279 }
280}
281
282fn write_u32(buffer: &mut Vec<u8>, value: u32) {
283 buffer.extend(value.to_le_bytes());
284}
285
286fn write_bytes_padded(buffer: &mut Vec<u8>, bytes: &[u8]) {
287 buffer.extend(bytes);
288
289 let len = u32::try_from(bytes.len()).unwrap();
290 for _ in len..align(len, 4) {
291 buffer.push(0);
292 }
293}
294
295fn align(a: u32, b: u32) -> u32 {
296 assert!(b.is_power_of_two());
297 (a + (b - 1)) & !(b - 1)
298}
299
300fn get_and_increment(n: &mut u32) -> u32 {
301 let v = *n;
302 *n += 1;
303 v
304}
305
306fn const_u32(a: u32) -> ConstExpr {
307 ConstExpr::i32_const(a as i32)
308}
309
310trait Length {
312 fn len(&self) -> usize;
313}
314
315impl<T> Length for HashSet<T> {
316 fn len(&self) -> usize {
317 HashSet::len(self)
318 }
319}
320
321impl<K, V> Length for HashMap<K, V> {
322 fn len(&self) -> usize {
323 HashMap::len(self)
324 }
325}
326
327impl<T> Length for IndexSet<T> {
328 fn len(&self) -> usize {
329 IndexSet::len(self)
330 }
331}
332
333impl<K, V> Length for IndexMap<K, V> {
334 fn len(&self) -> usize {
335 IndexMap::len(self)
336 }
337}
338
339trait CollectUnique: Iterator + Sized {
342 fn collect_unique<T: FromIterator<Self::Item> + Length>(self) -> T {
343 let tmp = self.collect::<Vec<_>>();
344 let len = tmp.len();
345 let result = tmp.into_iter().collect::<T>();
346 assert!(
347 result.len() == len,
348 "one or more duplicate items detected when collecting into set or map"
349 );
350 result
351 }
352}
353
354impl<T: Iterator> CollectUnique for T {}
355
356trait InsertUnique {
358 type Key;
359 type Value;
360
361 fn insert_unique(&mut self, k: Self::Key, v: Self::Value);
362}
363
364impl<K: Hash + Eq + PartialEq + Debug, V: Debug> InsertUnique for HashMap<K, V> {
365 type Key = K;
366 type Value = V;
367
368 fn insert_unique(&mut self, k: Self::Key, v: Self::Value) {
369 if let Some(old_v) = self.get(&k) {
370 panic!(
371 "duplicate item inserted into map for key {k:?} (old value: {old_v:?}; new value: {v:?})"
372 );
373 }
374 self.insert(k, v);
375 }
376}
377
378fn make_env_module<'a>(
381 metadata: &'a [Metadata<'a>],
382 env_exports: &[EnvExport<'_>],
383 cabi_realloc_exporter: Option<&str>,
384 stack_size_bytes: u32,
385) -> (Vec<u8>, DlOpenables<'a>, TlsLayout, u32) {
386 let mut types = TypeSection::new();
388 let mut imports = ImportSection::new();
389 let mut import_map = IndexMap::new();
390 let mut function_count = 0;
391 let mut global_offset = 0;
392 let mut wasi_start = None;
393
394 for metadata in metadata {
395 for import in &metadata.imports {
396 if let Entry::Vacant(entry) = import_map.entry(import) {
397 imports.import(
398 import.module,
399 import.name,
400 match &import.ty {
401 Type::Function(ty) => {
402 let index = get_and_increment(&mut function_count);
403 entry.insert(index);
404 types.ty().function(
405 ty.parameters.iter().copied().map(ValType::from),
406 ty.results.iter().copied().map(ValType::from),
407 );
408 EntityType::Function(index)
409 }
410 Type::Global(ty) => {
411 entry.insert(get_and_increment(&mut global_offset));
412 EntityType::Global(wasm_encoder::GlobalType {
413 val_type: ty.ty.into(),
414 mutable: ty.mutable,
415 shared: ty.shared,
416 })
417 }
418 Type::Tag(_) => continue,
419 },
420 );
421 }
422 }
423
424 if metadata.has_wasi_start {
425 if wasi_start.is_some() {
426 panic!("multiple libraries export {}", metadata::START);
427 }
428 let index = get_and_increment(&mut function_count);
429
430 types.ty().function(vec![], vec![]);
431 imports.import(metadata.name, metadata::START, EntityType::Function(index));
432
433 wasi_start = Some(index);
434 }
435 }
436
437 let mut memory_offset = stack_size_bytes;
438
439 let mut table_offset = 1;
443 let mut globals = GlobalSection::new();
444 let mut exports = ExportSection::new();
445
446 if let Some(exporter) = cabi_realloc_exporter {
447 let index = get_and_increment(&mut function_count);
448 types.ty().function([ValType::I32; 4], [ValType::I32]);
449 imports.import(exporter, CABI_REALLOC, EntityType::Function(index));
450 exports.export(CABI_REALLOC, ExportKind::Func, index);
451 }
452
453 let indirect_tls_base = metadata
456 .iter()
457 .any(|m| m.needs_get_tls_base || m.needs_set_tls_base)
458 && metadata.iter().any(|m| m.uses_thread_new_indirect);
459 let tls_context_get = if indirect_tls_base {
460 let index = get_and_increment(&mut function_count);
461 types.ty().function([], [ValType::I32]);
462 imports.import(
463 metadata::ROOT,
464 metadata::CONTEXT_GET_1,
465 EntityType::Function(index),
466 );
467 Some(index)
468 } else {
469 None
470 };
471
472 let mut add_global_export = |name: &str, value, mutable| {
473 let index = globals.len();
474 globals.global(
475 wasm_encoder::GlobalType {
476 val_type: ValType::I32,
477 mutable,
478 shared: false,
479 },
480 &const_u32(value),
481 );
482 exports.export(name, ExportKind::Global, index);
483 };
484
485 let dl_openables = DlOpenables::new(table_offset, memory_offset, metadata);
486
487 if metadata.iter().any(|m| m.needs_libdl_libraries) {
488 add_global_export(
489 metadata::LIBDL_LIBRARIES,
490 dl_openables.libraries_address,
491 true,
492 );
493 }
494
495 table_offset += dl_openables.function_count;
496 memory_offset += u32::try_from(dl_openables.buffer.len()).unwrap();
497
498 let tls = TlsLayout::new(metadata, &mut memory_offset);
499
500 if metadata.iter().any(|m| m.needs_program_tls_info) {
501 add_global_export(metadata::PROGRAM_TLS_INFO, tls.program_info, true);
502 }
503
504 let memory_size = {
505 if metadata.iter().any(|m| m.needs_stack_pointer) {
506 add_global_export(metadata::STACK_POINTER, stack_size_bytes, true);
507 }
508 if metadata.iter().any(|m| m.needs_init_stack_pointer) {
509 add_global_export(metadata::INIT_STACK_POINTER, stack_size_bytes, false);
510 }
511
512 let has_asyncified_module = metadata.iter().any(|m| m.is_asyncified);
515 if has_asyncified_module {
516 add_global_export(metadata::ASYNCIFY_STATE, 0, true);
517 add_global_export(metadata::ASYNCIFY_DATA, 0, true);
518 }
519
520 if metadata.iter().any(|m| m.needs_stack_high) {
522 add_global_export(metadata::STACK_HIGH, stack_size_bytes, true);
523 }
524 if metadata.iter().any(|m| m.needs_stack_low) {
525 add_global_export(metadata::STACK_LOW, 0, true);
526 }
527
528 for metadata in metadata {
529 memory_offset = align(memory_offset, 1 << metadata.mem_info.memory_alignment);
530 table_offset = align(table_offset, 1 << metadata.mem_info.table_alignment);
531
532 add_global_export(
533 &format!("{}:memory_base", metadata.name),
534 memory_offset,
535 false,
536 );
537 add_global_export(
538 &format!("{}:table_base", metadata.name),
539 table_offset,
540 false,
541 );
542
543 memory_offset += metadata.mem_info.memory_size;
544 table_offset += metadata.mem_info.table_size;
545
546 for import in &metadata.memory_address_imports {
547 add_global_export(&format!("{}:{import}", metadata.name), 0, true);
550 }
551 }
552
553 {
554 let offsets = env_exports
555 .iter()
556 .enumerate()
557 .map(|(offset, EnvExport { name, exporter, .. })| {
558 (
559 *name,
560 (
561 table_offset + u32::try_from(offset).unwrap(),
562 metadata[*exporter].name == STUB_LIBRARY_NAME,
563 ),
564 )
565 })
566 .collect_unique::<HashMap<_, _>>();
567
568 for metadata in metadata {
569 for import in &metadata.table_address_imports {
570 let &(offset, is_stub) = offsets.get(import).unwrap();
571 if is_stub
572 && metadata
573 .env_imports
574 .iter()
575 .any(|e| e.0 == *import && e.1.1.contains(SymbolFlags::BINDING_WEAK))
576 {
577 add_global_export(&format!("{}:{import}", metadata.name), 0, true);
578 } else {
579 add_global_export(&format!("{}:{import}", metadata.name), offset, true);
580 }
581 }
582 }
583 }
584
585 memory_offset = align(memory_offset, HEAP_ALIGNMENT_BYTES);
586 if metadata.iter().any(|m| m.needs_heap_base) {
587 add_global_export(metadata::HEAP_BASE, memory_offset, true);
588 }
589
590 let heap_end = align(memory_offset, PAGE_SIZE_BYTES);
591 if metadata.iter().any(|m| m.needs_heap_end) {
592 add_global_export(metadata::HEAP_END, heap_end, true);
593 }
594 heap_end / PAGE_SIZE_BYTES
595 };
596
597 let indirection_table_base = table_offset;
598
599 let mut functions = FunctionSection::new();
600 let mut code = CodeSection::new();
601 for export in env_exports {
602 let index = get_and_increment(&mut function_count);
603 types.ty().function(
604 export.ty.parameters.iter().copied().map(ValType::from),
605 export.ty.results.iter().copied().map(ValType::from),
606 );
607 functions.function(u32::try_from(index).unwrap());
608 let mut function = Function::new([]);
609 for local in 0..export.ty.parameters.len() {
610 function
611 .instructions()
612 .local_get(u32::try_from(local).unwrap());
613 }
614 function
615 .instructions()
616 .i32_const(i32::try_from(table_offset).unwrap())
617 .call_indirect(0, u32::try_from(index).unwrap())
618 .end();
619 code.function(&function);
620 exports.export(export.name, ExportKind::Func, index);
621
622 table_offset += 1;
623 }
624
625 for (index, metadata) in metadata.iter().enumerate() {
629 let Some(slot) = tls.slot(index) else {
633 for (needed, name, params, results) in [
634 (
635 metadata.needs_get_tls_base,
636 metadata::GET_TLS_BASE,
637 &[][..],
638 &[ValType::I32][..],
639 ),
640 (
641 metadata.needs_set_tls_base,
642 metadata::SET_TLS_BASE,
643 &[ValType::I32][..],
644 &[][..],
645 ),
646 ] {
647 if !needed {
648 continue;
649 }
650 let func = get_and_increment(&mut function_count);
651 types
652 .ty()
653 .function(params.iter().copied(), results.iter().copied());
654 functions.function(func);
655 let mut function = Function::new([]);
656 function.instructions().unreachable().end();
657 code.function(&function);
658 exports.export(&format!("{}:{name}", metadata.name), ExportKind::Func, func);
659 }
660 continue;
661 };
662
663 let mem_arg = MemArg {
664 offset: u64::from(slot * 4),
665 align: 2,
666 memory_index: 0,
667 };
668
669 if metadata.needs_get_tls_base {
670 let func = get_and_increment(&mut function_count);
671 types.ty().function([], [ValType::I32]);
672 functions.function(func);
673 let mut function = Function::new([]);
674 match tls_context_get {
677 Some(get) => {
678 function.instructions().call(get);
679 }
680 None => {
681 function
682 .instructions()
683 .i32_const(i32::try_from(tls.main_thread_tls_base).unwrap());
684 }
685 }
686 function.instructions().i32_load(mem_arg).end();
687 code.function(&function);
688 exports.export(
689 &format!("{}:{}", metadata.name, metadata::GET_TLS_BASE),
690 ExportKind::Func,
691 func,
692 );
693 }
694
695 if metadata.needs_set_tls_base {
696 let func = get_and_increment(&mut function_count);
697 types.ty().function([ValType::I32], []);
698 functions.function(func);
699 let mut function = Function::new_with_locals_types(if tls_context_get.is_some() {
700 vec![ValType::I32]
701 } else {
702 vec![]
703 });
704 match tls_context_get {
710 Some(get) => {
711 function
712 .instructions()
713 .call(get)
714 .local_tee(1)
715 .i32_eqz()
716 .if_(wasm_encoder::BlockType::Empty)
717 .i32_const(i32::try_from(tls.main_thread_tls_base).unwrap())
718 .local_get(0)
719 .i32_store(mem_arg)
720 .else_()
721 .local_get(1)
722 .local_get(0)
723 .i32_store(mem_arg)
724 .end()
725 .end();
726 }
727 None => {
728 function
729 .instructions()
730 .i32_const(i32::try_from(tls.main_thread_tls_base).unwrap())
731 .local_get(0)
732 .i32_store(mem_arg)
733 .end();
734 }
735 }
736 code.function(&function);
737 exports.export(
738 &format!("{}:{}", metadata.name, metadata::SET_TLS_BASE),
739 ExportKind::Func,
740 func,
741 );
742 }
743 }
744
745 for (import, offset) in import_map {
746 exports.export(
747 &format!("{}:{}", import.module, import.name),
748 ExportKind::from(&import.ty),
749 offset,
750 );
751 }
752 if let Some(index) = wasi_start {
753 exports.export(metadata::START, ExportKind::Func, index);
754 }
755
756 let mut module = Module::new();
757
758 module.section(&types);
759 module.section(&imports);
760 module.section(&functions);
761
762 {
763 let mut tables = TableSection::new();
764 tables.table(TableType {
765 element_type: RefType::FUNCREF,
766 minimum: table_offset.into(),
767 maximum: None,
768 table64: false,
769 shared: false,
770 });
771 exports.export(metadata::INDIRECT_FUNCTION_TABLE, ExportKind::Table, 0);
772 module.section(&tables);
773 }
774
775 {
776 let mut memories = MemorySection::new();
777 memories.memory(MemoryType {
778 minimum: u64::from(memory_size),
779 maximum: None,
780 memory64: false,
781 shared: false,
782 page_size_log2: None,
783 });
784 exports.export(metadata::MEMORY, ExportKind::Memory, 0);
785 module.section(&memories);
786 }
787
788 module.section(&globals);
789 module.section(&exports);
790 module.section(&code);
791 module.section(&RawCustomSection(
792 &crate::base_producers().raw_custom_section(),
793 ));
794
795 let module = module.finish();
796 wasmparser::validate(&module).unwrap();
797
798 (module, dl_openables, tls, indirection_table_base)
799}
800
801fn make_init_module(
806 fixups: &mut FixupModule,
807 metadata: &[Metadata],
808 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
809 env_exports: &[EnvExport<'_>],
810 dl_openables: &DlOpenables,
811 tls: &TlsLayout,
812 indirection_table_base: u32,
813) -> Result<()> {
814 let thunk_ty = fixups.type_thunk();
815 let memory = fixups.import(
816 &ImportedInstance::Main,
817 metadata::MEMORY,
818 MemoryType {
819 minimum: 0,
820 maximum: None,
821 memory64: false,
822 shared: false,
823 page_size_log2: None,
824 }
825 .into(),
826 )?;
827 let table = fixups.import(
828 &ImportedInstance::Main,
829 metadata::INDIRECT_FUNCTION_TABLE,
830 TableType {
831 element_type: RefType::FUNCREF,
832 minimum: 0,
833 maximum: None,
834 table64: false,
835 shared: false,
836 }
837 .into(),
838 )?;
839
840 let module_name_to_instance = |module: &str| match module {
841 metadata::ENV => ImportedInstance::Main,
842 other => ImportedInstance::Adapter(other.to_string()),
843 };
844
845 let mut global_map = HashMap::new();
846 let mut add_global_import = |fixups: &mut FixupModule, module: &str, name: &str, mutable| {
847 *global_map
848 .entry((module.to_owned(), name.to_owned()))
849 .or_insert_with(|| {
850 fixups
851 .import_global(
852 &module_name_to_instance(module),
853 name,
854 wasm_encoder::GlobalType {
855 val_type: ValType::I32,
856 mutable,
857 shared: false,
858 },
859 )
860 .unwrap()
861 })
862 };
863
864 let mut function_map = HashMap::new();
865 let mut add_function_import = |fixups: &mut FixupModule, module: &str, name: &str, ty| {
866 *function_map
867 .entry((module.to_owned(), name.to_owned()))
868 .or_insert_with(|| {
869 fixups
870 .import_func(&module_name_to_instance(module), name, ty)
871 .unwrap()
872 })
873 };
874
875 let mut names = HashMap::new();
876 for (index, metadata) in metadata.iter().enumerate() {
877 names.insert_unique(index, metadata.name);
878 }
879
880 for (exporter, export, address) in dl_openables.global_addresses.iter() {
881 let memory_base = add_global_import(
882 fixups,
883 metadata::ENV,
884 &format!("{exporter}:memory_base"),
885 false,
886 );
887 let export = add_global_import(fixups, exporter, export, false);
888
889 fixups.add_start_abi_detail(StartAction::InitializeAddress {
890 memory_base,
891 export,
892 dest: AddressDest::LinearMemory {
893 address: *address,
894 memory,
895 },
896 });
897 }
898
899 for metadata in metadata {
900 for import in &metadata.memory_address_imports {
901 let (exporter, _) = find_offset_exporter(import, exporters)?;
902
903 let memory_base = add_global_import(
904 fixups,
905 metadata::ENV,
906 &format!("{exporter}:memory_base"),
907 false,
908 );
909 let offset = add_global_import(fixups, exporter, import, false);
910 let address = add_global_import(
911 fixups,
912 metadata::ENV,
913 &format!("{}:{import}", metadata.name),
914 true,
915 );
916 fixups.add_start_abi_detail(StartAction::InitializeAddress {
917 memory_base,
918 export: offset,
919 dest: AddressDest::Global(address),
920 });
921 }
922 }
923
924 for metadata in metadata {
925 if metadata.has_data_relocs {
926 let func =
927 add_function_import(fixups, metadata.name, metadata::APPLY_DATA_RELOCS, thunk_ty);
928 fixups.add_start_abi_detail(StartAction::Call(func));
929 }
930 }
931
932 for metadata in metadata {
933 if metadata.has_ctors && metadata.has_initialize {
934 bail!(
935 "library {} exports both `{}` and `{}`; \
936 expected at most one of the two",
937 metadata.name,
938 metadata::CALL_CTORS,
939 metadata::INITIALIZE
940 );
941 }
942
943 if metadata.has_ctors {
944 let func = add_function_import(fixups, metadata.name, metadata::CALL_CTORS, thunk_ty);
945 fixups.add_start_user_func(StartAction::Call(func));
946 }
947
948 if metadata.has_initialize {
949 let func = add_function_import(fixups, metadata.name, metadata::INITIALIZE, thunk_ty);
950 fixups.add_start_user_func(StartAction::Call(func));
951 }
952 }
953
954 let intern_type = |fixups: &mut FixupModule, ty: &FunctionType| {
955 fixups.type_intern(
956 ty.parameters.iter().copied().map(|t| t.into()).collect(),
957 ty.results.iter().copied().map(|t| t.into()).collect(),
958 )
959 };
960
961 let mut dl_openable_functions = Vec::new();
962 for metadata in metadata {
963 if metadata.dl_openable {
964 for export in &metadata.exports {
965 if let Type::Function(fty) = &export.key.ty {
966 let ty = intern_type(fixups, fty);
967 dl_openable_functions.push(add_function_import(
968 fixups,
969 metadata.name,
970 export.key.name,
971 ty,
972 ));
973 }
974 }
975 }
976 }
977
978 let indirections = env_exports
979 .iter()
980 .map(|EnvExport { name, exporter, ty }| {
981 let ty = intern_type(fixups, ty);
982 add_function_import(fixups, names[exporter], name, ty)
983 })
984 .collect::<Vec<_>>();
985
986 if tls.library_info != 0 {
991 for (lib_index, tls_index) in tls
992 .slots
993 .iter()
994 .enumerate()
995 .filter_map(|(i, slot)| slot.map(|j| (i, j)))
996 {
997 let metadata = &metadata[lib_index];
998 let memory_base = add_global_import(
999 fixups,
1000 metadata::ENV,
1001 &format!("{}:memory_base", metadata.name),
1002 false,
1003 );
1004 let i = add_global_import(fixups, metadata.name, metadata::LIBRARY_TLS_INFO, false);
1005
1006 fixups.add_start_abi_detail(StartAction::InitializeAddress {
1007 memory_base,
1008 export: i,
1009 dest: AddressDest::LinearMemory {
1010 address: tls.library_info + tls_index * 4,
1011 memory,
1012 },
1013 });
1014 }
1015 }
1016
1017 fixups.elements().active(
1018 if table == 0 { None } else { Some(table) },
1019 &const_u32(dl_openables.table_base),
1020 Elements::Functions(dl_openable_functions.into()),
1021 );
1022 fixups.elements().active(
1023 if table == 0 { None } else { Some(table) },
1024 &const_u32(indirection_table_base),
1025 Elements::Functions(indirections.into()),
1026 );
1027
1028 let data = fixups.data();
1029 data.active(
1030 memory,
1031 &const_u32(dl_openables.memory_base),
1032 dl_openables.buffer.clone(),
1033 );
1034 if !tls.buffer.is_empty() {
1035 data.active(memory, &const_u32(tls.program_info), tls.buffer.clone());
1036 }
1037
1038 Ok(())
1039}
1040
1041fn find_offset_exporter<'a>(
1043 name: &str,
1044 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
1045) -> Result<(&'a str, &'a Export<'a>)> {
1046 let export = ExportKey {
1047 name,
1048 ty: Type::Global(GlobalType {
1049 ty: ValueType::I32,
1050 mutable: false,
1051 shared: false,
1052 }),
1053 };
1054
1055 exporters
1056 .get(&export)
1057 .copied()
1058 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
1059}
1060
1061fn find_function_exporter<'a>(
1063 name: &str,
1064 ty: &FunctionType,
1065 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
1066) -> Result<(&'a str, &'a Export<'a>)> {
1067 let export = ExportKey {
1068 name,
1069 ty: Type::Function(ty.clone()),
1070 };
1071
1072 exporters
1073 .get(&export)
1074 .copied()
1075 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
1076}
1077
1078fn find_tag_exporter<'a>(
1080 name: &str,
1081 ty: &FunctionType,
1082 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
1083) -> Result<(&'a str, &'a Export<'a>)> {
1084 let export = ExportKey {
1085 name,
1086 ty: Type::Tag(ty.clone()),
1087 };
1088
1089 exporters
1090 .get(&export)
1091 .copied()
1092 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
1093}
1094
1095fn resolve_exporters<'a>(
1097 metadata: &'a [Metadata<'a>],
1098) -> Result<IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>> {
1099 let mut exporters = IndexMap::<_, Vec<_>>::new();
1100 for metadata in metadata {
1101 for export in &metadata.exports {
1102 exporters
1103 .entry(&export.key)
1104 .or_default()
1105 .push((metadata.name, export));
1106 }
1107 }
1108 Ok(exporters)
1109}
1110
1111fn resolve_symbols<'a>(
1113 metadata: &'a [Metadata<'a>],
1114 exporters: &'a IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>,
1115) -> (
1116 IndexMap<&'a ExportKey<'a>, (&'a str, &'a Export<'a>)>,
1117 Vec<(&'a str, Export<'a>)>,
1118 Vec<(&'a str, &'a ExportKey<'a>, &'a [(&'a str, &'a Export<'a>)])>,
1119) {
1120 let function_exporters = exporters
1121 .iter()
1122 .filter_map(|(export, exporters)| match &export.ty {
1123 Type::Function(_) => Some((export.name, (export, exporters))),
1124 Type::Global(_) | Type::Tag(_) => None,
1125 })
1126 .collect_unique::<IndexMap<_, _>>();
1127
1128 let mut resolved = IndexMap::new();
1129 let mut missing = Vec::new();
1130 let mut duplicates = Vec::new();
1131
1132 let mut triage = |metadata: &'a Metadata, export: Export<'a>| {
1133 if let Some((key, value)) = exporters.get_key_value(&export.key) {
1134 match value.as_slice() {
1137 [] => unreachable!(),
1138 [exporter] => {
1139 resolved.insert(*key, *exporter);
1140 }
1141 [exporter, ..] => {
1142 resolved.insert(*key, *exporter);
1143 duplicates.push((metadata.name, *key, value.as_slice()));
1144 }
1145 }
1146 } else {
1147 missing.push((metadata.name, export));
1148 }
1149 };
1150
1151 for metadata in metadata {
1152 for (name, (ty, flags)) in &metadata.env_imports {
1153 triage(
1154 metadata,
1155 Export {
1156 key: ExportKey {
1157 name,
1158 ty: Type::Function(ty.clone()),
1159 },
1160 flags: *flags,
1161 },
1162 );
1163 }
1164
1165 for name in &metadata.memory_address_imports {
1166 triage(
1167 metadata,
1168 Export {
1169 key: ExportKey {
1170 name,
1171 ty: Type::Global(GlobalType {
1172 ty: ValueType::I32,
1173 mutable: false,
1174 shared: false,
1175 }),
1176 },
1177 flags: SymbolFlags::empty(),
1178 },
1179 );
1180 }
1181
1182 for (name, ty) in &metadata.tag_imports {
1183 triage(
1184 metadata,
1185 Export {
1186 key: ExportKey {
1187 name,
1188 ty: Type::Tag(ty.clone()),
1189 },
1190 flags: SymbolFlags::empty(),
1191 },
1192 );
1193 }
1194 }
1195
1196 for metadata in metadata {
1197 for name in &metadata.table_address_imports {
1198 if let Some((key, value)) = function_exporters.get(name) {
1199 match value.as_slice() {
1202 [] => unreachable!(),
1203 [exporter] => {
1204 resolved.insert(key, *exporter);
1205 }
1206 [exporter, ..] => {
1207 resolved.insert(key, *exporter);
1208 duplicates.push((metadata.name, *key, value.as_slice()));
1209 }
1210 }
1211 } else if metadata.env_imports.iter().any(|(n, _)| n == name) {
1212 } else {
1215 missing.push((
1216 metadata.name,
1217 Export {
1218 key: ExportKey {
1219 name,
1220 ty: Type::Function(FunctionType {
1221 parameters: Vec::new(),
1222 results: Vec::new(),
1223 }),
1224 },
1225 flags: SymbolFlags::empty(),
1226 },
1227 ));
1228 }
1229 }
1230 }
1231
1232 for (name, params, results) in ENV_REEXPORTS {
1237 let export = Export {
1238 key: ExportKey {
1239 name,
1240 ty: Type::Function(FunctionType {
1241 parameters: params.to_vec(),
1242 results: results.to_vec(),
1243 }),
1244 },
1245 flags: SymbolFlags::empty(),
1246 };
1247
1248 if let Some((key, value)) = exporters.get_key_value(&export.key) {
1249 match value.as_slice() {
1253 [] => unreachable!(),
1254 [exporter] | [exporter, ..] => {
1255 resolved.insert(*key, *exporter);
1256 }
1257 }
1258 }
1259 }
1260
1261 (resolved, missing, duplicates)
1262}
1263
1264fn topo_add(
1267 sorted: &mut IndexSet<usize>,
1268 dependencies: &IndexMap<usize, IndexSet<usize>>,
1269 element: usize,
1270) {
1271 let empty = &IndexSet::new();
1272 let deps = dependencies.get(&element).unwrap_or(empty);
1273
1274 for &dep in deps {
1276 if !(sorted.contains(&dep) || dependencies.get(&dep).unwrap_or(empty).contains(&element)) {
1277 topo_add(sorted, dependencies, dep);
1278 }
1279 }
1280
1281 sorted.insert(element);
1283
1284 for &dep in deps {
1286 if !sorted.contains(&dep) && dependencies.get(&dep).unwrap_or(empty).contains(&element) {
1287 topo_add(sorted, dependencies, dep);
1288 }
1289 }
1290}
1291
1292fn topo_sort(count: usize, dependencies: &IndexMap<usize, IndexSet<usize>>) -> Result<Vec<usize>> {
1295 let mut sorted = IndexSet::new();
1296 for index in 0..count {
1297 topo_add(&mut sorted, &dependencies, index);
1298 }
1299
1300 Ok(sorted.into_iter().collect())
1301}
1302
1303fn find_dependencies(
1306 metadata: &[Metadata],
1307 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
1308) -> Result<IndexMap<usize, IndexSet<usize>>> {
1309 let mut dependencies = IndexMap::<_, IndexSet<_>>::new();
1311 let mut indexes = HashMap::new();
1312 for (index, metadata) in metadata.iter().enumerate() {
1313 indexes.insert_unique(metadata.name, index);
1314 for &needed in &metadata.needed_libs {
1315 dependencies
1316 .entry(metadata.name)
1317 .or_default()
1318 .insert(needed);
1319 }
1320 for (import_name, (ty, _)) in &metadata.env_imports {
1321 dependencies
1322 .entry(metadata.name)
1323 .or_default()
1324 .insert(find_function_exporter(import_name, ty, exporters)?.0);
1325 }
1326 }
1327
1328 let mut dependencies = dependencies
1330 .into_iter()
1331 .map(|(k, v)| {
1332 (
1333 indexes[k],
1334 v.into_iter()
1335 .map(|v| indexes[v])
1336 .collect_unique::<IndexSet<_>>(),
1337 )
1338 })
1339 .collect_unique::<IndexMap<_, _>>();
1340
1341 let empty = &IndexSet::new();
1344
1345 loop {
1346 let mut new = IndexMap::<_, IndexSet<_>>::new();
1347 for (index, exporters) in &dependencies {
1348 for exporter in exporters {
1349 for exporter in dependencies.get(exporter).unwrap_or(empty) {
1350 if !exporters.contains(exporter) {
1351 new.entry(*index).or_default().insert(*exporter);
1352 }
1353 }
1354 }
1355 }
1356
1357 if new.is_empty() {
1358 break Ok(dependencies);
1359 } else {
1360 for (index, exporters) in new {
1361 dependencies.entry(index).or_default().extend(exporters);
1362 }
1363 }
1364 }
1365}
1366
1367struct EnvExports<'a> {
1368 exports: Vec<EnvExport<'a>>,
1369 reexport_cabi_realloc: bool,
1370}
1371
1372struct EnvExport<'a> {
1373 name: &'a str,
1374 ty: Cow<'a, FunctionType>,
1375 exporter: usize,
1376}
1377
1378fn env_exports<'a>(
1388 metadata: &'a [Metadata<'a>],
1389 exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>,
1390 topo_sorted: &[usize],
1391) -> Result<EnvExports<'a>> {
1392 let function_exporters = exporters
1393 .iter()
1394 .filter_map(|(export, exporter)| {
1395 if let Type::Function(ty) = &export.ty {
1396 Some((export.name, (ty, *exporter)))
1397 } else {
1398 None
1399 }
1400 })
1401 .collect_unique::<HashMap<_, _>>();
1402
1403 let indexes = metadata
1404 .iter()
1405 .enumerate()
1406 .map(|(index, metadata)| (metadata.name, index))
1407 .collect_unique::<HashMap<_, _>>();
1408
1409 let mut result = Vec::new();
1410 let mut exported = HashSet::new();
1411 let mut seen = HashSet::new();
1412
1413 for &index in topo_sorted {
1414 let metadata = &metadata[index];
1415
1416 for name in &metadata.table_address_imports {
1417 if !exported.contains(name) {
1418 let (ty, (exporter, _)) = function_exporters
1419 .get(name)
1420 .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?;
1421
1422 result.push(EnvExport {
1423 name: *name,
1424 ty: Cow::Borrowed(*ty),
1425 exporter: indexes[exporter],
1426 });
1427 exported.insert(*name);
1428 }
1429 }
1430
1431 for (import_name, (ty, _)) in &metadata.env_imports {
1432 if !exported.contains(import_name) {
1433 let exporter = indexes[find_function_exporter(import_name, ty, exporters)
1434 .unwrap()
1435 .0];
1436 if !seen.contains(&exporter) {
1437 result.push(EnvExport {
1438 name: *import_name,
1439 ty: Cow::Borrowed(ty),
1440 exporter,
1441 });
1442 exported.insert(*import_name);
1443 }
1444 }
1445 }
1446
1447 seen.insert(index);
1448 }
1449
1450 for (name, params, results) in ENV_REEXPORTS {
1455 if !exported.contains(name) {
1456 let ty = FunctionType {
1457 parameters: params.to_vec(),
1458 results: results.to_vec(),
1459 };
1460 if let Some(exporter) = exporters.get(&ExportKey {
1461 name,
1462 ty: Type::Function(ty.clone()),
1463 }) {
1464 result.push(EnvExport {
1465 name,
1466 ty: Cow::Owned(ty),
1467 exporter: indexes[exporter.0],
1468 });
1469 exported.insert(name);
1470 }
1471 }
1472 }
1473
1474 let reexport_cabi_realloc = exported.contains(CABI_REALLOC);
1475
1476 Ok(EnvExports {
1477 exports: result,
1478 reexport_cabi_realloc,
1479 })
1480}
1481
1482fn make_stubs_module(missing: &[(&str, Export)]) -> Vec<u8> {
1484 let mut types = TypeSection::new();
1485 let mut exports = ExportSection::new();
1486 let mut functions = FunctionSection::new();
1487 let mut code = CodeSection::new();
1488 for (offset, (_, export)) in missing.iter().enumerate() {
1489 let offset = u32::try_from(offset).unwrap();
1490
1491 let Export {
1492 key:
1493 ExportKey {
1494 name,
1495 ty: Type::Function(ty),
1496 },
1497 ..
1498 } = export
1499 else {
1500 unreachable!();
1501 };
1502
1503 types.ty().function(
1504 ty.parameters.iter().copied().map(ValType::from),
1505 ty.results.iter().copied().map(ValType::from),
1506 );
1507 functions.function(offset);
1508 let mut function = Function::new([]);
1509 function.instructions().unreachable().end();
1510 code.function(&function);
1511 exports.export(name, ExportKind::Func, offset);
1512 }
1513
1514 let mut module = Module::new();
1515
1516 module.section(&types);
1517 module.section(&functions);
1518 module.section(&exports);
1519 module.section(&code);
1520 module.section(&RawCustomSection(
1521 &crate::base_producers().raw_custom_section(),
1522 ));
1523
1524 let module = module.finish();
1525 wasmparser::validate(&module).unwrap();
1526
1527 module
1528}
1529
1530fn find_reachable<'a>(
1533 metadata: &'a [Metadata<'a>],
1534 dependencies: &IndexMap<usize, IndexSet<usize>>,
1535) -> IndexSet<&'a str> {
1536 let reachable = metadata
1537 .iter()
1538 .enumerate()
1539 .filter_map(|(index, metadata)| {
1540 if metadata.has_component_exports || metadata.dl_openable || metadata.has_wasi_start {
1541 Some(index)
1542 } else {
1543 None
1544 }
1545 })
1546 .collect_unique::<IndexSet<_>>();
1547
1548 let empty = &IndexSet::new();
1549
1550 reachable
1551 .iter()
1552 .chain(
1553 reachable
1554 .iter()
1555 .flat_map(|index| dependencies.get(index).unwrap_or(empty)),
1556 )
1557 .map(|&index| metadata[index].name)
1558 .collect()
1559}
1560
1561#[derive(Default)]
1563pub struct Linker {
1564 libraries: Vec<(String, Vec<u8>, bool)>,
1568
1569 stub_missing_functions: bool,
1571
1572 use_built_in_libdl: bool,
1574
1575 stack_size: Option<u32>,
1579
1580 encoder: ComponentEncoder,
1581}
1582
1583impl Linker {
1584 pub fn library(&mut self, name: &str, module: &[u8], dl_openable: bool) -> Result<&mut Self> {
1589 self.libraries
1590 .push((name.to_owned(), module.to_vec(), dl_openable));
1591
1592 Ok(self)
1593 }
1594
1595 pub fn stack_size(&mut self, stack_size: u32) -> &mut Self {
1597 self.stack_size = Some(stack_size);
1598 self
1599 }
1600
1601 pub fn stub_missing_functions(&mut self, stub_missing_functions: bool) -> &mut Self {
1603 self.stub_missing_functions = stub_missing_functions;
1604 self
1605 }
1606
1607 pub fn use_built_in_libdl(&mut self, use_built_in_libdl: bool) -> &mut Self {
1609 self.use_built_in_libdl = use_built_in_libdl;
1610 self
1611 }
1612
1613 pub fn encoder(&mut self) -> &mut ComponentEncoder {
1616 &mut self.encoder
1617 }
1618
1619 pub fn encode(mut self) -> Result<Vec<u8>> {
1621 if self.use_built_in_libdl {
1622 self.use_built_in_libdl = false;
1623 self.library("libdl.so", include_bytes!("../libdl.so"), false)?;
1624 }
1625
1626 let adapter_names = self
1627 .encoder
1628 .adapters
1629 .keys()
1630 .map(|name| name.as_str())
1631 .collect::<HashSet<_>>();
1632
1633 let metadata = self
1634 .libraries
1635 .iter()
1636 .map(|(name, module, dl_openable)| {
1637 Metadata::try_new(name, *dl_openable, module, &adapter_names)
1638 .with_context(|| format!("failed to extract linking metadata from {name}"))
1639 })
1640 .collect::<Result<Vec<_>>>()?;
1641
1642 {
1643 let names = self
1644 .libraries
1645 .iter()
1646 .map(|(name, ..)| name.as_str())
1647 .collect_unique::<HashSet<_>>();
1648
1649 let missing = metadata
1650 .iter()
1651 .filter_map(|metadata| {
1652 let missing = metadata
1653 .needed_libs
1654 .iter()
1655 .copied()
1656 .filter(|name| !names.contains(*name))
1657 .collect::<Vec<_>>();
1658
1659 if missing.is_empty() {
1660 None
1661 } else {
1662 Some((metadata.name, missing))
1663 }
1664 })
1665 .collect::<Vec<_>>();
1666
1667 if !missing.is_empty() {
1668 bail!(
1669 "missing libraries:\n{}",
1670 missing
1671 .iter()
1672 .map(|(needed_by, missing)| format!(
1673 "\t{needed_by} needs {}",
1674 missing.join(", ")
1675 ))
1676 .collect::<Vec<_>>()
1677 .join("\n")
1678 );
1679 }
1680 }
1681
1682 let exporters = resolve_exporters(&metadata)?;
1683
1684 let cabi_realloc_exporter = exporters
1685 .get(&ExportKey {
1686 name: "cabi_realloc",
1687 ty: Type::Function(FunctionType {
1688 parameters: vec![ValueType::I32; 4],
1689 results: vec![ValueType::I32],
1690 }),
1691 })
1692 .map(|exporters| exporters.first().unwrap().0);
1693
1694 let (exporters, missing, _) = resolve_symbols(&metadata, &exporters);
1695
1696 if !missing.is_empty() {
1697 if missing
1698 .iter()
1699 .all(|(_, export)| matches!(&export.key.ty, Type::Function(_)))
1700 && (self.stub_missing_functions
1701 || missing
1702 .iter()
1703 .all(|(_, export)| export.flags.contains(SymbolFlags::BINDING_WEAK)))
1704 {
1705 self.stub_missing_functions = false;
1706 self.libraries
1707 .push((STUB_LIBRARY_NAME.into(), make_stubs_module(&missing), false));
1708 return self.encode();
1709 } else {
1710 bail!(
1711 "unresolved symbol(s):\n{}",
1712 missing
1713 .iter()
1714 .filter(|(_, export)| !export.flags.contains(SymbolFlags::BINDING_WEAK))
1715 .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) })
1716 .collect::<Vec<_>>()
1717 .join("\n")
1718 );
1719 }
1720 }
1721
1722 let dependencies = find_dependencies(&metadata, &exporters)?;
1723
1724 {
1725 let reachable = find_reachable(&metadata, &dependencies);
1726 let unreachable = self
1727 .libraries
1728 .iter()
1729 .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone()))
1730 .collect_unique::<HashSet<_>>();
1731
1732 if !unreachable.is_empty() {
1733 self.libraries
1734 .retain(|(name, ..)| !unreachable.contains(name));
1735 return self.encode();
1736 }
1737 }
1738
1739 let topo_sorted = topo_sort(metadata.len(), &dependencies)?;
1740
1741 let EnvExports {
1742 exports: env_exports,
1743 reexport_cabi_realloc,
1744 } = env_exports(&metadata, &exporters, &topo_sorted)?;
1745
1746 let (env_module, dl_openables, tls, table_base) = make_env_module(
1747 &metadata,
1748 &env_exports,
1749 if reexport_cabi_realloc {
1750 None
1753 } else {
1754 cabi_realloc_exporter
1755 },
1756 self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES),
1757 );
1758
1759 self.encoder.module(&env_module)?;
1760
1761 let default_env_items = [
1762 Item {
1763 alias: metadata::MEMORY.into(),
1764 kind: ExportKind::Memory,
1765 which: MainOrAdapter::Main,
1766 name: metadata::MEMORY.into(),
1767 },
1768 Item {
1769 alias: metadata::INDIRECT_FUNCTION_TABLE.into(),
1770 kind: ExportKind::Table,
1771 which: MainOrAdapter::Main,
1772 name: metadata::INDIRECT_FUNCTION_TABLE.into(),
1773 },
1774 Item {
1775 alias: metadata::STACK_POINTER.into(),
1776 kind: ExportKind::Global,
1777 which: MainOrAdapter::Main,
1778 name: metadata::STACK_POINTER.into(),
1779 },
1780 Item {
1781 alias: metadata::INIT_STACK_POINTER.into(),
1782 kind: ExportKind::Global,
1783 which: MainOrAdapter::Main,
1784 name: metadata::INIT_STACK_POINTER.into(),
1785 },
1786 ];
1787
1788 let mut seen = HashSet::new();
1789 for index in topo_sorted {
1790 let (name, module, _) = &self.libraries[index];
1791 let metadata = &metadata[index];
1792
1793 let env_items = default_env_items
1794 .iter()
1795 .cloned()
1796 .chain([
1797 Item {
1798 alias: metadata::MEMORY_BASE.into(),
1799 kind: ExportKind::Global,
1800 which: MainOrAdapter::Main,
1801 name: format!("{name}:memory_base"),
1802 },
1803 Item {
1804 alias: metadata::TABLE_BASE.into(),
1805 kind: ExportKind::Global,
1806 which: MainOrAdapter::Main,
1807 name: format!("{name}:table_base"),
1808 },
1809 ])
1810 .chain(
1811 [
1812 (metadata.needs_get_tls_base, metadata::GET_TLS_BASE),
1813 (metadata.needs_set_tls_base, metadata::SET_TLS_BASE),
1814 ]
1815 .into_iter()
1816 .filter(|(needed, _)| *needed)
1817 .map(|(_, intrinsic)| Item {
1818 alias: intrinsic.into(),
1819 kind: ExportKind::Func,
1820 which: MainOrAdapter::Main,
1821 name: format!("{name}:{intrinsic}"),
1822 }),
1823 )
1824 .chain(metadata.env_imports.iter().map(|(name, (ty, _))| {
1825 let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap();
1826
1827 Item {
1828 alias: (*name).into(),
1829 kind: ExportKind::Func,
1830 which: if seen.contains(exporter) {
1831 MainOrAdapter::Adapter(exporter.to_owned())
1832 } else {
1833 MainOrAdapter::Main
1834 },
1835 name: (*name).into(),
1836 }
1837 }))
1838 .chain(
1839 metadata
1840 .tag_imports
1841 .iter()
1842 .map(|(name, ty)| {
1843 let (exporter, _) = find_tag_exporter(name, ty, &exporters).unwrap();
1844
1845 Ok(Item {
1846 alias: (*name).into(),
1847 kind: ExportKind::Tag,
1848 which: if seen.contains(exporter) {
1849 MainOrAdapter::Adapter(exporter.to_owned())
1850 } else {
1851 bail!(
1863 "circular dependency prevents direct tag import from `{}`",
1864 exporter.to_owned()
1865 )
1866 },
1867 name: (*name).into(),
1868 })
1869 })
1870 .collect::<Result<Vec<_>>>()?,
1871 )
1872 .chain(if metadata.is_asyncified {
1873 vec![
1874 Item {
1875 alias: metadata::ASYNCIFY_STATE.into(),
1876 kind: ExportKind::Global,
1877 which: MainOrAdapter::Main,
1878 name: metadata::ASYNCIFY_STATE.into(),
1879 },
1880 Item {
1881 alias: metadata::ASYNCIFY_DATA.into(),
1882 kind: ExportKind::Global,
1883 which: MainOrAdapter::Main,
1884 name: metadata::ASYNCIFY_DATA.into(),
1885 },
1886 ]
1887 } else {
1888 vec![]
1889 })
1890 .collect();
1891
1892 let global_item = |address_name: &str| Item {
1893 alias: address_name.into(),
1894 kind: ExportKind::Global,
1895 which: MainOrAdapter::Main,
1896 name: format!("{name}:{address_name}"),
1897 };
1898
1899 let mem_items = metadata
1900 .memory_address_imports
1901 .iter()
1902 .copied()
1903 .map(global_item)
1904 .chain(
1905 [
1906 metadata::HEAP_BASE,
1907 metadata::HEAP_END,
1908 metadata::STACK_HIGH,
1909 metadata::STACK_LOW,
1910 metadata::LIBDL_LIBRARIES,
1911 metadata::PROGRAM_TLS_INFO,
1912 ]
1913 .into_iter()
1914 .map(|name| Item {
1915 alias: name.into(),
1916 kind: ExportKind::Global,
1917 which: MainOrAdapter::Main,
1918 name: name.into(),
1919 }),
1920 )
1921 .collect();
1922
1923 let func_items = metadata
1924 .table_address_imports
1925 .iter()
1926 .copied()
1927 .map(global_item)
1928 .collect();
1929
1930 let mut import_items = BTreeMap::<_, Vec<_>>::new();
1931 for import in &metadata.imports {
1932 import_items.entry(import.module).or_default().push(Item {
1933 alias: import.name.into(),
1934 kind: ExportKind::from(&import.ty),
1935 which: MainOrAdapter::Main,
1936 name: format!("{}:{}", import.module, import.name),
1937 });
1938 }
1939
1940 self.encoder.library(
1941 name,
1942 module,
1943 LibraryInfo {
1944 arguments: [
1945 (metadata::GOT_MEM.into(), Instance::Items(mem_items)),
1946 (metadata::GOT_FUNC.into(), Instance::Items(func_items)),
1947 (metadata::ENV.into(), Instance::Items(env_items)),
1948 ]
1949 .into_iter()
1950 .chain(
1951 import_items
1952 .into_iter()
1953 .map(|(k, v)| (k.into(), Instance::Items(v))),
1954 )
1955 .collect(),
1956 },
1957 )?;
1958
1959 seen.insert(name.as_str());
1960 }
1961
1962 self.encoder.encode_with_fixups(Some(&mut |fixups| {
1963 make_init_module(
1964 fixups,
1965 &metadata,
1966 &exporters,
1967 &env_exports,
1968 &dl_openables,
1969 &tls,
1970 table_base,
1971 )
1972 }))
1973 }
1974}