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