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 target: Default::default(),
667 ordering: None,
668 };
669
670 if metadata.needs_get_tls_base {
671 let func = get_and_increment(&mut function_count);
672 types.ty().function([], [ValType::I32]);
673 functions.function(func);
674 let mut function = Function::new([]);
675 match tls_context_get {
678 Some(get) => {
679 function.instructions().call(get);
680 }
681 None => {
682 function
683 .instructions()
684 .i32_const(i32::try_from(tls.main_thread_tls_base).unwrap());
685 }
686 }
687 function.instructions().i32_load(mem_arg).end();
688 code.function(&function);
689 exports.export(
690 &format!("{}:{}", metadata.name, metadata::GET_TLS_BASE),
691 ExportKind::Func,
692 func,
693 );
694 }
695
696 if metadata.needs_set_tls_base {
697 let func = get_and_increment(&mut function_count);
698 types.ty().function([ValType::I32], []);
699 functions.function(func);
700 let mut function = Function::new_with_locals_types(if tls_context_get.is_some() {
701 vec![ValType::I32]
702 } else {
703 vec![]
704 });
705 match tls_context_get {
711 Some(get) => {
712 function
713 .instructions()
714 .call(get)
715 .local_tee(1)
716 .i32_eqz()
717 .if_(wasm_encoder::BlockType::Empty)
718 .i32_const(i32::try_from(tls.main_thread_tls_base).unwrap())
719 .local_get(0)
720 .i32_store(mem_arg)
721 .else_()
722 .local_get(1)
723 .local_get(0)
724 .i32_store(mem_arg)
725 .end()
726 .end();
727 }
728 None => {
729 function
730 .instructions()
731 .i32_const(i32::try_from(tls.main_thread_tls_base).unwrap())
732 .local_get(0)
733 .i32_store(mem_arg)
734 .end();
735 }
736 }
737 code.function(&function);
738 exports.export(
739 &format!("{}:{}", metadata.name, metadata::SET_TLS_BASE),
740 ExportKind::Func,
741 func,
742 );
743 }
744 }
745
746 for (import, offset) in import_map {
747 exports.export(
748 &format!("{}:{}", import.module, import.name),
749 ExportKind::from(&import.ty),
750 offset,
751 );
752 }
753 if let Some(index) = wasi_start {
754 exports.export(metadata::START, ExportKind::Func, index);
755 }
756
757 let mut module = Module::new();
758
759 module.section(&types);
760 module.section(&imports);
761 module.section(&functions);
762
763 {
764 let mut tables = TableSection::new();
765 tables.table(TableType {
766 element_type: RefType::FUNCREF,
767 minimum: table_offset.into(),
768 maximum: None,
769 table64: false,
770 shared: false,
771 });
772 exports.export(metadata::INDIRECT_FUNCTION_TABLE, ExportKind::Table, 0);
773 module.section(&tables);
774 }
775
776 {
777 let mut memories = MemorySection::new();
778 memories.memory(MemoryType {
779 minimum: u64::from(memory_size),
780 maximum: None,
781 memory64: false,
782 shared: false,
783 page_size_log2: None,
784 });
785 exports.export(metadata::MEMORY, ExportKind::Memory, 0);
786 module.section(&memories);
787 }
788
789 module.section(&globals);
790 module.section(&exports);
791 module.section(&code);
792 module.section(&RawCustomSection(
793 &crate::base_producers().raw_custom_section(),
794 ));
795
796 let module = module.finish();
797 wasmparser::validate(&module).unwrap();
798
799 (module, dl_openables, tls, indirection_table_base)
800}
801
802fn make_init_module(
807 fixups: &mut FixupModule,
808 metadata: &[Metadata],
809 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
810 env_exports: &[EnvExport<'_>],
811 dl_openables: &DlOpenables,
812 tls: &TlsLayout,
813 indirection_table_base: u32,
814) -> Result<()> {
815 let thunk_ty = fixups.type_thunk();
816 let memory = fixups.import(
817 &ImportedInstance::Main,
818 metadata::MEMORY,
819 MemoryType {
820 minimum: 0,
821 maximum: None,
822 memory64: false,
823 shared: false,
824 page_size_log2: None,
825 }
826 .into(),
827 )?;
828 let table = fixups.import(
829 &ImportedInstance::Main,
830 metadata::INDIRECT_FUNCTION_TABLE,
831 TableType {
832 element_type: RefType::FUNCREF,
833 minimum: 0,
834 maximum: None,
835 table64: false,
836 shared: false,
837 }
838 .into(),
839 )?;
840
841 let module_name_to_instance = |module: &str| match module {
842 metadata::ENV => ImportedInstance::Main,
843 other => ImportedInstance::Adapter(other.to_string()),
844 };
845
846 let mut global_map = HashMap::new();
847 let mut add_global_import = |fixups: &mut FixupModule, module: &str, name: &str, mutable| {
848 *global_map
849 .entry((module.to_owned(), name.to_owned()))
850 .or_insert_with(|| {
851 fixups
852 .import_global(
853 &module_name_to_instance(module),
854 name,
855 wasm_encoder::GlobalType {
856 val_type: ValType::I32,
857 mutable,
858 shared: false,
859 },
860 )
861 .unwrap()
862 })
863 };
864
865 let mut function_map = HashMap::new();
866 let mut add_function_import = |fixups: &mut FixupModule, module: &str, name: &str, ty| {
867 *function_map
868 .entry((module.to_owned(), name.to_owned()))
869 .or_insert_with(|| {
870 fixups
871 .import_func(&module_name_to_instance(module), name, ty)
872 .unwrap()
873 })
874 };
875
876 let mut names = HashMap::new();
877 for (index, metadata) in metadata.iter().enumerate() {
878 names.insert_unique(index, metadata.name);
879 }
880
881 for (exporter, export, address) in dl_openables.global_addresses.iter() {
882 let memory_base = add_global_import(
883 fixups,
884 metadata::ENV,
885 &format!("{exporter}:memory_base"),
886 false,
887 );
888 let export = add_global_import(fixups, exporter, export, false);
889
890 fixups.add_start_abi_detail(StartAction::InitializeAddress {
891 memory_base,
892 export,
893 dest: AddressDest::LinearMemory {
894 address: *address,
895 memory,
896 },
897 });
898 }
899
900 for metadata in metadata {
901 for import in &metadata.memory_address_imports {
902 let (exporter, _) = find_offset_exporter(import, exporters)?;
903
904 let memory_base = add_global_import(
905 fixups,
906 metadata::ENV,
907 &format!("{exporter}:memory_base"),
908 false,
909 );
910 let offset = add_global_import(fixups, exporter, import, false);
911 let address = add_global_import(
912 fixups,
913 metadata::ENV,
914 &format!("{}:{import}", metadata.name),
915 true,
916 );
917 fixups.add_start_abi_detail(StartAction::InitializeAddress {
918 memory_base,
919 export: offset,
920 dest: AddressDest::Global(address),
921 });
922 }
923 }
924
925 for metadata in metadata {
926 if metadata.has_data_relocs {
927 let func =
928 add_function_import(fixups, metadata.name, metadata::APPLY_DATA_RELOCS, thunk_ty);
929 fixups.add_start_abi_detail(StartAction::Call(func));
930 }
931 }
932
933 for metadata in metadata {
934 if metadata.has_ctors && metadata.has_initialize {
935 bail!(
936 "library {} exports both `{}` and `{}`; \
937 expected at most one of the two",
938 metadata.name,
939 metadata::CALL_CTORS,
940 metadata::INITIALIZE
941 );
942 }
943
944 if metadata.has_ctors {
945 let func = add_function_import(fixups, metadata.name, metadata::CALL_CTORS, thunk_ty);
946 fixups.add_start_user_func(StartAction::Call(func));
947 }
948
949 if metadata.has_initialize {
950 let func = add_function_import(fixups, metadata.name, metadata::INITIALIZE, thunk_ty);
951 fixups.add_start_user_func(StartAction::Call(func));
952 }
953 }
954
955 let intern_type = |fixups: &mut FixupModule, ty: &FunctionType| {
956 fixups.type_intern(
957 ty.parameters.iter().copied().map(|t| t.into()).collect(),
958 ty.results.iter().copied().map(|t| t.into()).collect(),
959 )
960 };
961
962 let mut dl_openable_functions = Vec::new();
963 for metadata in metadata {
964 if metadata.dl_openable {
965 for export in &metadata.exports {
966 if let Type::Function(fty) = &export.key.ty {
967 let ty = intern_type(fixups, fty);
968 dl_openable_functions.push(add_function_import(
969 fixups,
970 metadata.name,
971 export.key.name,
972 ty,
973 ));
974 }
975 }
976 }
977 }
978
979 let indirections = env_exports
980 .iter()
981 .map(|EnvExport { name, exporter, ty }| {
982 let ty = intern_type(fixups, ty);
983 add_function_import(fixups, names[exporter], name, ty)
984 })
985 .collect::<Vec<_>>();
986
987 if tls.library_info != 0 {
992 for (lib_index, tls_index) in tls
993 .slots
994 .iter()
995 .enumerate()
996 .filter_map(|(i, slot)| slot.map(|j| (i, j)))
997 {
998 let metadata = &metadata[lib_index];
999 let memory_base = add_global_import(
1000 fixups,
1001 metadata::ENV,
1002 &format!("{}:memory_base", metadata.name),
1003 false,
1004 );
1005 let i = add_global_import(fixups, metadata.name, metadata::LIBRARY_TLS_INFO, false);
1006
1007 fixups.add_start_abi_detail(StartAction::InitializeAddress {
1008 memory_base,
1009 export: i,
1010 dest: AddressDest::LinearMemory {
1011 address: tls.library_info + tls_index * 4,
1012 memory,
1013 },
1014 });
1015 }
1016 }
1017
1018 fixups.elements().active(
1019 if table == 0 { None } else { Some(table) },
1020 &const_u32(dl_openables.table_base),
1021 Elements::Functions(dl_openable_functions.into()),
1022 );
1023 fixups.elements().active(
1024 if table == 0 { None } else { Some(table) },
1025 &const_u32(indirection_table_base),
1026 Elements::Functions(indirections.into()),
1027 );
1028
1029 let data = fixups.data();
1030 data.active(
1031 memory,
1032 &const_u32(dl_openables.memory_base),
1033 dl_openables.buffer.clone(),
1034 );
1035 if !tls.buffer.is_empty() {
1036 data.active(memory, &const_u32(tls.program_info), tls.buffer.clone());
1037 }
1038
1039 Ok(())
1040}
1041
1042fn find_offset_exporter<'a>(
1044 name: &str,
1045 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
1046) -> Result<(&'a str, &'a Export<'a>)> {
1047 let export = ExportKey {
1048 name,
1049 ty: Type::Global(GlobalType {
1050 ty: ValueType::I32,
1051 mutable: false,
1052 shared: false,
1053 }),
1054 };
1055
1056 exporters
1057 .get(&export)
1058 .copied()
1059 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
1060}
1061
1062fn find_function_exporter<'a>(
1064 name: &str,
1065 ty: &FunctionType,
1066 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
1067) -> Result<(&'a str, &'a Export<'a>)> {
1068 let export = ExportKey {
1069 name,
1070 ty: Type::Function(ty.clone()),
1071 };
1072
1073 exporters
1074 .get(&export)
1075 .copied()
1076 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
1077}
1078
1079fn find_tag_exporter<'a>(
1081 name: &str,
1082 ty: &FunctionType,
1083 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
1084) -> Result<(&'a str, &'a Export<'a>)> {
1085 let export = ExportKey {
1086 name,
1087 ty: Type::Tag(ty.clone()),
1088 };
1089
1090 exporters
1091 .get(&export)
1092 .copied()
1093 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
1094}
1095
1096fn resolve_exporters<'a>(
1098 metadata: &'a [Metadata<'a>],
1099) -> Result<IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>> {
1100 let mut exporters = IndexMap::<_, Vec<_>>::new();
1101 for metadata in metadata {
1102 for export in &metadata.exports {
1103 exporters
1104 .entry(&export.key)
1105 .or_default()
1106 .push((metadata.name, export));
1107 }
1108 }
1109 Ok(exporters)
1110}
1111
1112fn resolve_symbols<'a>(
1114 metadata: &'a [Metadata<'a>],
1115 exporters: &'a IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>,
1116) -> (
1117 IndexMap<&'a ExportKey<'a>, (&'a str, &'a Export<'a>)>,
1118 Vec<(&'a str, Export<'a>)>,
1119 Vec<(&'a str, &'a ExportKey<'a>, &'a [(&'a str, &'a Export<'a>)])>,
1120) {
1121 let function_exporters = exporters
1122 .iter()
1123 .filter_map(|(export, exporters)| match &export.ty {
1124 Type::Function(_) => Some((export.name, (export, exporters))),
1125 Type::Global(_) | Type::Tag(_) => None,
1126 })
1127 .collect_unique::<IndexMap<_, _>>();
1128
1129 let mut resolved = IndexMap::new();
1130 let mut missing = Vec::new();
1131 let mut duplicates = Vec::new();
1132
1133 let mut triage = |metadata: &'a Metadata, export: Export<'a>| {
1134 if let Some((key, value)) = exporters.get_key_value(&export.key) {
1135 match value.as_slice() {
1138 [] => unreachable!(),
1139 [exporter] => {
1140 resolved.insert(*key, *exporter);
1141 }
1142 [exporter, ..] => {
1143 resolved.insert(*key, *exporter);
1144 duplicates.push((metadata.name, *key, value.as_slice()));
1145 }
1146 }
1147 } else {
1148 missing.push((metadata.name, export));
1149 }
1150 };
1151
1152 for metadata in metadata {
1153 for (name, (ty, flags)) in &metadata.env_imports {
1154 triage(
1155 metadata,
1156 Export {
1157 key: ExportKey {
1158 name,
1159 ty: Type::Function(ty.clone()),
1160 },
1161 flags: *flags,
1162 },
1163 );
1164 }
1165
1166 for name in &metadata.memory_address_imports {
1167 triage(
1168 metadata,
1169 Export {
1170 key: ExportKey {
1171 name,
1172 ty: Type::Global(GlobalType {
1173 ty: ValueType::I32,
1174 mutable: false,
1175 shared: false,
1176 }),
1177 },
1178 flags: SymbolFlags::empty(),
1179 },
1180 );
1181 }
1182
1183 for (name, ty) in &metadata.tag_imports {
1184 triage(
1185 metadata,
1186 Export {
1187 key: ExportKey {
1188 name,
1189 ty: Type::Tag(ty.clone()),
1190 },
1191 flags: SymbolFlags::empty(),
1192 },
1193 );
1194 }
1195 }
1196
1197 for metadata in metadata {
1198 for name in &metadata.table_address_imports {
1199 if let Some((key, value)) = function_exporters.get(name) {
1200 match value.as_slice() {
1203 [] => unreachable!(),
1204 [exporter] => {
1205 resolved.insert(key, *exporter);
1206 }
1207 [exporter, ..] => {
1208 resolved.insert(key, *exporter);
1209 duplicates.push((metadata.name, *key, value.as_slice()));
1210 }
1211 }
1212 } else if metadata.env_imports.iter().any(|(n, _)| n == name) {
1213 } else {
1216 missing.push((
1217 metadata.name,
1218 Export {
1219 key: ExportKey {
1220 name,
1221 ty: Type::Function(FunctionType {
1222 parameters: Vec::new(),
1223 results: Vec::new(),
1224 }),
1225 },
1226 flags: SymbolFlags::empty(),
1227 },
1228 ));
1229 }
1230 }
1231 }
1232
1233 for (name, params, results) in ENV_REEXPORTS {
1238 let export = Export {
1239 key: ExportKey {
1240 name,
1241 ty: Type::Function(FunctionType {
1242 parameters: params.to_vec(),
1243 results: results.to_vec(),
1244 }),
1245 },
1246 flags: SymbolFlags::empty(),
1247 };
1248
1249 if let Some((key, value)) = exporters.get_key_value(&export.key) {
1250 match value.as_slice() {
1254 [] => unreachable!(),
1255 [exporter] | [exporter, ..] => {
1256 resolved.insert(*key, *exporter);
1257 }
1258 }
1259 }
1260 }
1261
1262 (resolved, missing, duplicates)
1263}
1264
1265fn topo_add(
1268 sorted: &mut IndexSet<usize>,
1269 dependencies: &IndexMap<usize, IndexSet<usize>>,
1270 element: usize,
1271) {
1272 let empty = &IndexSet::new();
1273 let deps = dependencies.get(&element).unwrap_or(empty);
1274
1275 for &dep in deps {
1277 if !(sorted.contains(&dep) || dependencies.get(&dep).unwrap_or(empty).contains(&element)) {
1278 topo_add(sorted, dependencies, dep);
1279 }
1280 }
1281
1282 sorted.insert(element);
1284
1285 for &dep in deps {
1287 if !sorted.contains(&dep) && dependencies.get(&dep).unwrap_or(empty).contains(&element) {
1288 topo_add(sorted, dependencies, dep);
1289 }
1290 }
1291}
1292
1293fn topo_sort(count: usize, dependencies: &IndexMap<usize, IndexSet<usize>>) -> Result<Vec<usize>> {
1296 let mut sorted = IndexSet::new();
1297 for index in 0..count {
1298 topo_add(&mut sorted, &dependencies, index);
1299 }
1300
1301 Ok(sorted.into_iter().collect())
1302}
1303
1304fn find_dependencies(
1307 metadata: &[Metadata],
1308 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
1309) -> Result<IndexMap<usize, IndexSet<usize>>> {
1310 let mut dependencies = IndexMap::<_, IndexSet<_>>::new();
1312 let mut indexes = HashMap::new();
1313 for (index, metadata) in metadata.iter().enumerate() {
1314 indexes.insert_unique(metadata.name, index);
1315 for &needed in &metadata.needed_libs {
1316 dependencies
1317 .entry(metadata.name)
1318 .or_default()
1319 .insert(needed);
1320 }
1321 for (import_name, (ty, _)) in &metadata.env_imports {
1322 dependencies
1323 .entry(metadata.name)
1324 .or_default()
1325 .insert(find_function_exporter(import_name, ty, exporters)?.0);
1326 }
1327 }
1328
1329 let mut dependencies = dependencies
1331 .into_iter()
1332 .map(|(k, v)| {
1333 (
1334 indexes[k],
1335 v.into_iter()
1336 .map(|v| indexes[v])
1337 .collect_unique::<IndexSet<_>>(),
1338 )
1339 })
1340 .collect_unique::<IndexMap<_, _>>();
1341
1342 let empty = &IndexSet::new();
1345
1346 loop {
1347 let mut new = IndexMap::<_, IndexSet<_>>::new();
1348 for (index, exporters) in &dependencies {
1349 for exporter in exporters {
1350 for exporter in dependencies.get(exporter).unwrap_or(empty) {
1351 if !exporters.contains(exporter) {
1352 new.entry(*index).or_default().insert(*exporter);
1353 }
1354 }
1355 }
1356 }
1357
1358 if new.is_empty() {
1359 break Ok(dependencies);
1360 } else {
1361 for (index, exporters) in new {
1362 dependencies.entry(index).or_default().extend(exporters);
1363 }
1364 }
1365 }
1366}
1367
1368struct EnvExports<'a> {
1369 exports: Vec<EnvExport<'a>>,
1370 reexport_cabi_realloc: bool,
1371}
1372
1373struct EnvExport<'a> {
1374 name: &'a str,
1375 ty: Cow<'a, FunctionType>,
1376 exporter: usize,
1377}
1378
1379fn env_exports<'a>(
1389 metadata: &'a [Metadata<'a>],
1390 exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>,
1391 topo_sorted: &[usize],
1392) -> Result<EnvExports<'a>> {
1393 let function_exporters = exporters
1394 .iter()
1395 .filter_map(|(export, exporter)| {
1396 if let Type::Function(ty) = &export.ty {
1397 Some((export.name, (ty, *exporter)))
1398 } else {
1399 None
1400 }
1401 })
1402 .collect_unique::<HashMap<_, _>>();
1403
1404 let indexes = metadata
1405 .iter()
1406 .enumerate()
1407 .map(|(index, metadata)| (metadata.name, index))
1408 .collect_unique::<HashMap<_, _>>();
1409
1410 let mut result = Vec::new();
1411 let mut exported = HashSet::new();
1412 let mut seen = HashSet::new();
1413
1414 for &index in topo_sorted {
1415 let metadata = &metadata[index];
1416
1417 for name in &metadata.table_address_imports {
1418 if !exported.contains(name) {
1419 let (ty, (exporter, _)) = function_exporters
1420 .get(name)
1421 .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?;
1422
1423 result.push(EnvExport {
1424 name: *name,
1425 ty: Cow::Borrowed(*ty),
1426 exporter: indexes[exporter],
1427 });
1428 exported.insert(*name);
1429 }
1430 }
1431
1432 for (import_name, (ty, _)) in &metadata.env_imports {
1433 if !exported.contains(import_name) {
1434 let exporter = indexes[find_function_exporter(import_name, ty, exporters)
1435 .unwrap()
1436 .0];
1437 if !seen.contains(&exporter) {
1438 result.push(EnvExport {
1439 name: *import_name,
1440 ty: Cow::Borrowed(ty),
1441 exporter,
1442 });
1443 exported.insert(*import_name);
1444 }
1445 }
1446 }
1447
1448 seen.insert(index);
1449 }
1450
1451 for (name, params, results) in ENV_REEXPORTS {
1456 if !exported.contains(name) {
1457 let ty = FunctionType {
1458 parameters: params.to_vec(),
1459 results: results.to_vec(),
1460 };
1461 if let Some(exporter) = exporters.get(&ExportKey {
1462 name,
1463 ty: Type::Function(ty.clone()),
1464 }) {
1465 result.push(EnvExport {
1466 name,
1467 ty: Cow::Owned(ty),
1468 exporter: indexes[exporter.0],
1469 });
1470 exported.insert(name);
1471 }
1472 }
1473 }
1474
1475 let reexport_cabi_realloc = exported.contains(CABI_REALLOC);
1476
1477 Ok(EnvExports {
1478 exports: result,
1479 reexport_cabi_realloc,
1480 })
1481}
1482
1483fn make_stubs_module(missing: &[(&str, Export)]) -> Vec<u8> {
1485 let mut types = TypeSection::new();
1486 let mut exports = ExportSection::new();
1487 let mut functions = FunctionSection::new();
1488 let mut code = CodeSection::new();
1489 for (offset, (_, export)) in missing.iter().enumerate() {
1490 let offset = u32::try_from(offset).unwrap();
1491
1492 let Export {
1493 key:
1494 ExportKey {
1495 name,
1496 ty: Type::Function(ty),
1497 },
1498 ..
1499 } = export
1500 else {
1501 unreachable!();
1502 };
1503
1504 types.ty().function(
1505 ty.parameters.iter().copied().map(ValType::from),
1506 ty.results.iter().copied().map(ValType::from),
1507 );
1508 functions.function(offset);
1509 let mut function = Function::new([]);
1510 function.instructions().unreachable().end();
1511 code.function(&function);
1512 exports.export(name, ExportKind::Func, offset);
1513 }
1514
1515 let mut module = Module::new();
1516
1517 module.section(&types);
1518 module.section(&functions);
1519 module.section(&exports);
1520 module.section(&code);
1521 module.section(&RawCustomSection(
1522 &crate::base_producers().raw_custom_section(),
1523 ));
1524
1525 let module = module.finish();
1526 wasmparser::validate(&module).unwrap();
1527
1528 module
1529}
1530
1531fn find_reachable<'a>(
1534 metadata: &'a [Metadata<'a>],
1535 dependencies: &IndexMap<usize, IndexSet<usize>>,
1536) -> IndexSet<&'a str> {
1537 let reachable = metadata
1538 .iter()
1539 .enumerate()
1540 .filter_map(|(index, metadata)| {
1541 if metadata.has_component_exports || metadata.dl_openable || metadata.has_wasi_start {
1542 Some(index)
1543 } else {
1544 None
1545 }
1546 })
1547 .collect_unique::<IndexSet<_>>();
1548
1549 let empty = &IndexSet::new();
1550
1551 reachable
1552 .iter()
1553 .chain(
1554 reachable
1555 .iter()
1556 .flat_map(|index| dependencies.get(index).unwrap_or(empty)),
1557 )
1558 .map(|&index| metadata[index].name)
1559 .collect()
1560}
1561
1562#[derive(Default)]
1564pub struct Linker {
1565 libraries: Vec<(String, Vec<u8>, bool)>,
1569
1570 stub_missing_functions: bool,
1572
1573 use_built_in_libdl: bool,
1575
1576 stack_size: Option<u32>,
1580
1581 encoder: ComponentEncoder,
1582}
1583
1584impl Linker {
1585 pub fn library(&mut self, name: &str, module: &[u8], dl_openable: bool) -> Result<&mut Self> {
1590 self.libraries
1591 .push((name.to_owned(), module.to_vec(), dl_openable));
1592
1593 Ok(self)
1594 }
1595
1596 pub fn stack_size(&mut self, stack_size: u32) -> &mut Self {
1598 self.stack_size = Some(stack_size);
1599 self
1600 }
1601
1602 pub fn stub_missing_functions(&mut self, stub_missing_functions: bool) -> &mut Self {
1604 self.stub_missing_functions = stub_missing_functions;
1605 self
1606 }
1607
1608 pub fn use_built_in_libdl(&mut self, use_built_in_libdl: bool) -> &mut Self {
1610 self.use_built_in_libdl = use_built_in_libdl;
1611 self
1612 }
1613
1614 pub fn encoder(&mut self) -> &mut ComponentEncoder {
1617 &mut self.encoder
1618 }
1619
1620 pub fn encode(mut self) -> Result<Vec<u8>> {
1622 if self.use_built_in_libdl {
1623 self.use_built_in_libdl = false;
1624 self.library("libdl.so", include_bytes!("../libdl.so"), false)?;
1625 }
1626
1627 let adapter_names = self
1628 .encoder
1629 .adapters
1630 .keys()
1631 .map(|name| name.as_str())
1632 .collect::<HashSet<_>>();
1633
1634 let metadata = self
1635 .libraries
1636 .iter()
1637 .map(|(name, module, dl_openable)| {
1638 Metadata::try_new(name, *dl_openable, module, &adapter_names)
1639 .with_context(|| format!("failed to extract linking metadata from {name}"))
1640 })
1641 .collect::<Result<Vec<_>>>()?;
1642
1643 {
1644 let names = self
1645 .libraries
1646 .iter()
1647 .map(|(name, ..)| name.as_str())
1648 .collect_unique::<HashSet<_>>();
1649
1650 let missing = metadata
1651 .iter()
1652 .filter_map(|metadata| {
1653 let missing = metadata
1654 .needed_libs
1655 .iter()
1656 .copied()
1657 .filter(|name| !names.contains(*name))
1658 .collect::<Vec<_>>();
1659
1660 if missing.is_empty() {
1661 None
1662 } else {
1663 Some((metadata.name, missing))
1664 }
1665 })
1666 .collect::<Vec<_>>();
1667
1668 if !missing.is_empty() {
1669 bail!(
1670 "missing libraries:\n{}",
1671 missing
1672 .iter()
1673 .map(|(needed_by, missing)| format!(
1674 "\t{needed_by} needs {}",
1675 missing.join(", ")
1676 ))
1677 .collect::<Vec<_>>()
1678 .join("\n")
1679 );
1680 }
1681 }
1682
1683 let exporters = resolve_exporters(&metadata)?;
1684
1685 let cabi_realloc_exporter = exporters
1686 .get(&ExportKey {
1687 name: "cabi_realloc",
1688 ty: Type::Function(FunctionType {
1689 parameters: vec![ValueType::I32; 4],
1690 results: vec![ValueType::I32],
1691 }),
1692 })
1693 .map(|exporters| exporters.first().unwrap().0);
1694
1695 let (exporters, missing, _) = resolve_symbols(&metadata, &exporters);
1696
1697 if !missing.is_empty() {
1698 if missing
1699 .iter()
1700 .all(|(_, export)| matches!(&export.key.ty, Type::Function(_)))
1701 && (self.stub_missing_functions
1702 || missing
1703 .iter()
1704 .all(|(_, export)| export.flags.contains(SymbolFlags::BINDING_WEAK)))
1705 {
1706 self.stub_missing_functions = false;
1707 self.libraries
1708 .push((STUB_LIBRARY_NAME.into(), make_stubs_module(&missing), false));
1709 return self.encode();
1710 } else {
1711 bail!(
1712 "unresolved symbol(s):\n{}",
1713 missing
1714 .iter()
1715 .filter(|(_, export)| !export.flags.contains(SymbolFlags::BINDING_WEAK))
1716 .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) })
1717 .collect::<Vec<_>>()
1718 .join("\n")
1719 );
1720 }
1721 }
1722
1723 let dependencies = find_dependencies(&metadata, &exporters)?;
1724
1725 {
1726 let reachable = find_reachable(&metadata, &dependencies);
1727 let unreachable = self
1728 .libraries
1729 .iter()
1730 .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone()))
1731 .collect_unique::<HashSet<_>>();
1732
1733 if !unreachable.is_empty() {
1734 self.libraries
1735 .retain(|(name, ..)| !unreachable.contains(name));
1736 return self.encode();
1737 }
1738 }
1739
1740 let topo_sorted = topo_sort(metadata.len(), &dependencies)?;
1741
1742 let EnvExports {
1743 exports: env_exports,
1744 reexport_cabi_realloc,
1745 } = env_exports(&metadata, &exporters, &topo_sorted)?;
1746
1747 let (env_module, dl_openables, tls, table_base) = make_env_module(
1748 &metadata,
1749 &env_exports,
1750 if reexport_cabi_realloc {
1751 None
1754 } else {
1755 cabi_realloc_exporter
1756 },
1757 self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES),
1758 );
1759
1760 self.encoder.module(&env_module)?;
1761
1762 let default_env_items = [
1763 Item {
1764 alias: metadata::MEMORY.into(),
1765 kind: ExportKind::Memory,
1766 which: MainOrAdapter::Main,
1767 name: metadata::MEMORY.into(),
1768 },
1769 Item {
1770 alias: metadata::INDIRECT_FUNCTION_TABLE.into(),
1771 kind: ExportKind::Table,
1772 which: MainOrAdapter::Main,
1773 name: metadata::INDIRECT_FUNCTION_TABLE.into(),
1774 },
1775 Item {
1776 alias: metadata::STACK_POINTER.into(),
1777 kind: ExportKind::Global,
1778 which: MainOrAdapter::Main,
1779 name: metadata::STACK_POINTER.into(),
1780 },
1781 Item {
1782 alias: metadata::INIT_STACK_POINTER.into(),
1783 kind: ExportKind::Global,
1784 which: MainOrAdapter::Main,
1785 name: metadata::INIT_STACK_POINTER.into(),
1786 },
1787 ];
1788
1789 let mut seen = HashSet::new();
1790 for index in topo_sorted {
1791 let (name, module, _) = &self.libraries[index];
1792 let metadata = &metadata[index];
1793
1794 let env_items = default_env_items
1795 .iter()
1796 .cloned()
1797 .chain([
1798 Item {
1799 alias: metadata::MEMORY_BASE.into(),
1800 kind: ExportKind::Global,
1801 which: MainOrAdapter::Main,
1802 name: format!("{name}:memory_base"),
1803 },
1804 Item {
1805 alias: metadata::TABLE_BASE.into(),
1806 kind: ExportKind::Global,
1807 which: MainOrAdapter::Main,
1808 name: format!("{name}:table_base"),
1809 },
1810 ])
1811 .chain(
1812 [
1813 (metadata.needs_get_tls_base, metadata::GET_TLS_BASE),
1814 (metadata.needs_set_tls_base, metadata::SET_TLS_BASE),
1815 ]
1816 .into_iter()
1817 .filter(|(needed, _)| *needed)
1818 .map(|(_, intrinsic)| Item {
1819 alias: intrinsic.into(),
1820 kind: ExportKind::Func,
1821 which: MainOrAdapter::Main,
1822 name: format!("{name}:{intrinsic}"),
1823 }),
1824 )
1825 .chain(metadata.env_imports.iter().map(|(name, (ty, _))| {
1826 let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap();
1827
1828 Item {
1829 alias: (*name).into(),
1830 kind: ExportKind::Func,
1831 which: if seen.contains(exporter) {
1832 MainOrAdapter::Adapter(exporter.to_owned())
1833 } else {
1834 MainOrAdapter::Main
1835 },
1836 name: (*name).into(),
1837 }
1838 }))
1839 .chain(
1840 metadata
1841 .tag_imports
1842 .iter()
1843 .map(|(name, ty)| {
1844 let (exporter, _) = find_tag_exporter(name, ty, &exporters).unwrap();
1845
1846 Ok(Item {
1847 alias: (*name).into(),
1848 kind: ExportKind::Tag,
1849 which: if seen.contains(exporter) {
1850 MainOrAdapter::Adapter(exporter.to_owned())
1851 } else {
1852 bail!(
1864 "circular dependency prevents direct tag import from `{}`",
1865 exporter.to_owned()
1866 )
1867 },
1868 name: (*name).into(),
1869 })
1870 })
1871 .collect::<Result<Vec<_>>>()?,
1872 )
1873 .chain(if metadata.is_asyncified {
1874 vec![
1875 Item {
1876 alias: metadata::ASYNCIFY_STATE.into(),
1877 kind: ExportKind::Global,
1878 which: MainOrAdapter::Main,
1879 name: metadata::ASYNCIFY_STATE.into(),
1880 },
1881 Item {
1882 alias: metadata::ASYNCIFY_DATA.into(),
1883 kind: ExportKind::Global,
1884 which: MainOrAdapter::Main,
1885 name: metadata::ASYNCIFY_DATA.into(),
1886 },
1887 ]
1888 } else {
1889 vec![]
1890 })
1891 .collect();
1892
1893 let global_item = |address_name: &str| Item {
1894 alias: address_name.into(),
1895 kind: ExportKind::Global,
1896 which: MainOrAdapter::Main,
1897 name: format!("{name}:{address_name}"),
1898 };
1899
1900 let mem_items = metadata
1901 .memory_address_imports
1902 .iter()
1903 .copied()
1904 .map(global_item)
1905 .chain(
1906 [
1907 metadata::HEAP_BASE,
1908 metadata::HEAP_END,
1909 metadata::STACK_HIGH,
1910 metadata::STACK_LOW,
1911 metadata::LIBDL_LIBRARIES,
1912 metadata::PROGRAM_TLS_INFO,
1913 ]
1914 .into_iter()
1915 .map(|name| Item {
1916 alias: name.into(),
1917 kind: ExportKind::Global,
1918 which: MainOrAdapter::Main,
1919 name: name.into(),
1920 }),
1921 )
1922 .collect();
1923
1924 let func_items = metadata
1925 .table_address_imports
1926 .iter()
1927 .copied()
1928 .map(global_item)
1929 .collect();
1930
1931 let mut import_items = BTreeMap::<_, Vec<_>>::new();
1932 for import in &metadata.imports {
1933 import_items.entry(import.module).or_default().push(Item {
1934 alias: import.name.into(),
1935 kind: ExportKind::from(&import.ty),
1936 which: MainOrAdapter::Main,
1937 name: format!("{}:{}", import.module, import.name),
1938 });
1939 }
1940
1941 self.encoder.library(
1942 name,
1943 module,
1944 LibraryInfo {
1945 arguments: [
1946 (metadata::GOT_MEM.into(), Instance::Items(mem_items)),
1947 (metadata::GOT_FUNC.into(), Instance::Items(func_items)),
1948 (metadata::ENV.into(), Instance::Items(env_items)),
1949 ]
1950 .into_iter()
1951 .chain(
1952 import_items
1953 .into_iter()
1954 .map(|(k, v)| (k.into(), Instance::Items(v))),
1955 )
1956 .collect(),
1957 },
1958 )?;
1959
1960 seen.insert(name.as_str());
1961 }
1962
1963 self.encoder.encode_with_fixups(Some(&mut |fixups| {
1964 make_init_module(
1965 fixups,
1966 &metadata,
1967 &exporters,
1968 &env_exports,
1969 &dl_openables,
1970 &tls,
1971 table_base,
1972 )
1973 }))
1974 }
1975}