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 collections::{BTreeMap, HashMap, HashSet},
32 fmt::Debug,
33 hash::Hash,
34 iter,
35 },
36 wasm_encoder::{
37 CodeSection, ConstExpr, DataSection, ElementSection, Elements, EntityType, ExportKind,
38 ExportSection, Function, FunctionSection, GlobalSection, ImportSection, Instruction as Ins,
39 MemArg, MemorySection, MemoryType, Module, RawCustomSection, RefType, StartSection,
40 TableSection, TableType, TypeSection, ValType,
41 },
42 wasmparser::SymbolFlags,
43};
44
45mod 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 EMPTY_FUNCTION_TYPE: FunctionType = FunctionType {
55 parameters: Vec::new(),
56 results: Vec::new(),
57};
58
59static ENV_REEXPORTS: &[&str] = &[metadata::INIT_TASK, metadata::INIT_ASYNC_TASK];
64
65enum Address<'a> {
66 Function(u32),
67 Global(&'a str),
68}
69
70struct DlOpenables<'a> {
75 table_base: u32,
77
78 memory_base: u32,
80
81 buffer: Vec<u8>,
83
84 global_addresses: Vec<(&'a str, &'a str, u32)>,
88
89 function_count: u32,
91
92 libraries_address: u32,
97}
98
99impl<'a> DlOpenables<'a> {
100 fn new(table_base: u32, memory_base: u32, metadata: &'a [Metadata<'a>]) -> Self {
103 let mut function_count = 0;
104 let mut buffer = Vec::new();
105 let mut global_addresses = Vec::new();
106 let mut libraries = metadata
107 .iter()
108 .filter(|metadata| metadata.dl_openable)
109 .map(|metadata| {
110 let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
111 write_bytes_padded(&mut buffer, metadata.name.as_bytes());
112
113 let mut symbols = metadata
114 .exports
115 .iter()
116 .filter_map(|export| {
117 let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
118 write_bytes_padded(&mut buffer, export.key.name.as_bytes());
119
120 let address = match &export.key.ty {
121 Type::Function(_) => Address::Function(
122 table_base + get_and_increment(&mut function_count),
123 ),
124 Type::Global(_) => Address::Global(export.key.name),
125 Type::Tag(_) => return None,
126 };
127
128 Some((export.key.name, name_address, address))
129 })
130 .collect::<Vec<_>>();
131
132 symbols.sort_by_key(|(name, ..)| *name);
133
134 let start = buffer.len();
135 for (name, name_address, address) in symbols {
136 write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
137 write_u32(&mut buffer, name_address);
138 match address {
139 Address::Function(address) => write_u32(&mut buffer, address),
140 Address::Global(name) => {
141 global_addresses.push((
142 metadata.name,
143 name,
144 memory_base + u32::try_from(buffer.len()).unwrap(),
145 ));
146
147 write_u32(&mut buffer, 0);
148 }
149 }
150 }
151
152 (
153 metadata.name,
154 name_address,
155 metadata.exports.len(),
156 memory_base + u32::try_from(start).unwrap(),
157 )
158 })
159 .collect::<Vec<_>>();
160
161 libraries.sort_by_key(|(name, ..)| *name);
162
163 let start = buffer.len();
164 for (name, name_address, count, symbols) in &libraries {
165 write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
166 write_u32(&mut buffer, *name_address);
167 write_u32(&mut buffer, u32::try_from(*count).unwrap());
168 write_u32(&mut buffer, *symbols);
169 }
170
171 let libraries_address = memory_base + u32::try_from(buffer.len()).unwrap();
172 write_u32(&mut buffer, u32::try_from(libraries.len()).unwrap());
173 write_u32(&mut buffer, memory_base + u32::try_from(start).unwrap());
174
175 Self {
176 table_base,
177 memory_base,
178 buffer,
179 global_addresses,
180 function_count,
181 libraries_address,
182 }
183 }
184}
185
186fn write_u32(buffer: &mut Vec<u8>, value: u32) {
187 buffer.extend(value.to_le_bytes());
188}
189
190fn write_bytes_padded(buffer: &mut Vec<u8>, bytes: &[u8]) {
191 buffer.extend(bytes);
192
193 let len = u32::try_from(bytes.len()).unwrap();
194 for _ in len..align(len, 4) {
195 buffer.push(0);
196 }
197}
198
199fn align(a: u32, b: u32) -> u32 {
200 assert!(b.is_power_of_two());
201 (a + (b - 1)) & !(b - 1)
202}
203
204fn get_and_increment(n: &mut u32) -> u32 {
205 let v = *n;
206 *n += 1;
207 v
208}
209
210fn const_u32(a: u32) -> ConstExpr {
211 ConstExpr::i32_const(a as i32)
212}
213
214trait Length {
216 fn len(&self) -> usize;
217}
218
219impl<T> Length for HashSet<T> {
220 fn len(&self) -> usize {
221 HashSet::len(self)
222 }
223}
224
225impl<K, V> Length for HashMap<K, V> {
226 fn len(&self) -> usize {
227 HashMap::len(self)
228 }
229}
230
231impl<T> Length for IndexSet<T> {
232 fn len(&self) -> usize {
233 IndexSet::len(self)
234 }
235}
236
237impl<K, V> Length for IndexMap<K, V> {
238 fn len(&self) -> usize {
239 IndexMap::len(self)
240 }
241}
242
243trait CollectUnique: Iterator + Sized {
246 fn collect_unique<T: FromIterator<Self::Item> + Length>(self) -> T {
247 let tmp = self.collect::<Vec<_>>();
248 let len = tmp.len();
249 let result = tmp.into_iter().collect::<T>();
250 assert!(
251 result.len() == len,
252 "one or more duplicate items detected when collecting into set or map"
253 );
254 result
255 }
256}
257
258impl<T: Iterator> CollectUnique for T {}
259
260trait InsertUnique {
262 type Key;
263 type Value;
264
265 fn insert_unique(&mut self, k: Self::Key, v: Self::Value);
266}
267
268impl<K: Hash + Eq + PartialEq + Debug, V: Debug> InsertUnique for HashMap<K, V> {
269 type Key = K;
270 type Value = V;
271
272 fn insert_unique(&mut self, k: Self::Key, v: Self::Value) {
273 if let Some(old_v) = self.get(&k) {
274 panic!(
275 "duplicate item inserted into map for key {k:?} (old value: {old_v:?}; new value: {v:?})"
276 );
277 }
278 self.insert(k, v);
279 }
280}
281
282fn make_env_module<'a>(
285 metadata: &'a [Metadata<'a>],
286 env_exports: &[EnvExport<'_>],
287 cabi_realloc_exporter: Option<&str>,
288 stack_size_bytes: u32,
289) -> (Vec<u8>, DlOpenables<'a>, u32) {
290 let mut types = TypeSection::new();
292 let mut imports = ImportSection::new();
293 let mut import_map = IndexMap::new();
294 let mut function_count = 0;
295 let mut global_offset = 0;
296 let mut wasi_start = None;
297
298 for metadata in metadata {
299 for import in &metadata.imports {
300 if let Entry::Vacant(entry) = import_map.entry(import) {
301 imports.import(
302 import.module,
303 import.name,
304 match &import.ty {
305 Type::Function(ty) => {
306 let index = get_and_increment(&mut function_count);
307 entry.insert(index);
308 types.ty().function(
309 ty.parameters.iter().copied().map(ValType::from),
310 ty.results.iter().copied().map(ValType::from),
311 );
312 EntityType::Function(index)
313 }
314 Type::Global(ty) => {
315 entry.insert(get_and_increment(&mut global_offset));
316 EntityType::Global(wasm_encoder::GlobalType {
317 val_type: ty.ty.into(),
318 mutable: ty.mutable,
319 shared: ty.shared,
320 })
321 }
322 Type::Tag(_) => continue,
323 },
324 );
325 }
326 }
327
328 if metadata.has_wasi_start {
329 if wasi_start.is_some() {
330 panic!("multiple libraries export {}", metadata::START);
331 }
332 let index = get_and_increment(&mut function_count);
333
334 types.ty().function(vec![], vec![]);
335 imports.import(metadata.name, metadata::START, EntityType::Function(index));
336
337 wasi_start = Some(index);
338 }
339 }
340
341 let mut memory_offset = stack_size_bytes;
342
343 let mut table_offset = 1;
347 let mut globals = GlobalSection::new();
348 let mut exports = ExportSection::new();
349
350 if let Some(exporter) = cabi_realloc_exporter {
351 let index = get_and_increment(&mut function_count);
352 types.ty().function([ValType::I32; 4], [ValType::I32]);
353 imports.import(exporter, CABI_REALLOC, EntityType::Function(index));
354 exports.export(CABI_REALLOC, ExportKind::Func, index);
355 }
356
357 let dl_openables = DlOpenables::new(table_offset, memory_offset, metadata);
358
359 table_offset += dl_openables.function_count;
360 memory_offset += u32::try_from(dl_openables.buffer.len()).unwrap();
361
362 let memory_size = {
363 let mut add_global_export = |name: &str, value, mutable| {
364 let index = globals.len();
365 globals.global(
366 wasm_encoder::GlobalType {
367 val_type: ValType::I32,
368 mutable,
369 shared: false,
370 },
371 &const_u32(value),
372 );
373 exports.export(name, ExportKind::Global, index);
374 };
375
376 if metadata.iter().any(|m| m.needs_stack_pointer) {
377 add_global_export(metadata::STACK_POINTER, stack_size_bytes, true);
378 }
379 if metadata.iter().any(|m| m.needs_init_stack_pointer) {
380 add_global_export(metadata::INIT_STACK_POINTER, stack_size_bytes, false);
381 }
382
383 let has_asyncified_module = metadata.iter().any(|m| m.is_asyncified);
386 if has_asyncified_module {
387 add_global_export(metadata::ASYNCIFY_STATE, 0, true);
388 add_global_export(metadata::ASYNCIFY_DATA, 0, true);
389 }
390
391 if metadata.iter().any(|m| m.needs_stack_high) {
393 add_global_export(metadata::STACK_HIGH, stack_size_bytes, true);
394 }
395 if metadata.iter().any(|m| m.needs_stack_low) {
396 add_global_export(metadata::STACK_LOW, 0, true);
397 }
398
399 for metadata in metadata {
400 memory_offset = align(memory_offset, 1 << metadata.mem_info.memory_alignment);
401 table_offset = align(table_offset, 1 << metadata.mem_info.table_alignment);
402
403 add_global_export(
404 &format!("{}:memory_base", metadata.name),
405 memory_offset,
406 false,
407 );
408 add_global_export(
409 &format!("{}:table_base", metadata.name),
410 table_offset,
411 false,
412 );
413
414 memory_offset += metadata.mem_info.memory_size;
415 table_offset += metadata.mem_info.table_size;
416
417 for import in &metadata.memory_address_imports {
418 add_global_export(&format!("{}:{import}", metadata.name), 0, true);
421 }
422 }
423
424 {
425 let offsets = env_exports
426 .iter()
427 .enumerate()
428 .map(|(offset, EnvExport { name, exporter, .. })| {
429 (
430 *name,
431 (
432 table_offset + u32::try_from(offset).unwrap(),
433 metadata[*exporter].name == STUB_LIBRARY_NAME,
434 ),
435 )
436 })
437 .collect_unique::<HashMap<_, _>>();
438
439 for metadata in metadata {
440 for import in &metadata.table_address_imports {
441 let &(offset, is_stub) = offsets.get(import).unwrap();
442 if is_stub
443 && metadata
444 .env_imports
445 .iter()
446 .any(|e| e.0 == *import && e.1.1.contains(SymbolFlags::BINDING_WEAK))
447 {
448 add_global_export(&format!("{}:{import}", metadata.name), 0, true);
449 } else {
450 add_global_export(&format!("{}:{import}", metadata.name), offset, true);
451 }
452 }
453 }
454 }
455
456 memory_offset = align(memory_offset, HEAP_ALIGNMENT_BYTES);
457 if metadata.iter().any(|m| m.needs_heap_base) {
458 add_global_export(metadata::HEAP_BASE, memory_offset, true);
459 }
460
461 let heap_end = align(memory_offset, PAGE_SIZE_BYTES);
462 if metadata.iter().any(|m| m.needs_heap_end) {
463 add_global_export(metadata::HEAP_END, heap_end, true);
464 }
465 heap_end / PAGE_SIZE_BYTES
466 };
467
468 let indirection_table_base = table_offset;
469
470 let mut functions = FunctionSection::new();
471 let mut code = CodeSection::new();
472 for export in env_exports {
473 let index = get_and_increment(&mut function_count);
474 types.ty().function(
475 export.ty.parameters.iter().copied().map(ValType::from),
476 export.ty.results.iter().copied().map(ValType::from),
477 );
478 functions.function(u32::try_from(index).unwrap());
479 let mut function = Function::new([]);
480 for local in 0..export.ty.parameters.len() {
481 function.instruction(&Ins::LocalGet(u32::try_from(local).unwrap()));
482 }
483 function.instruction(&Ins::I32Const(i32::try_from(table_offset).unwrap()));
484 function.instruction(&Ins::CallIndirect {
485 type_index: u32::try_from(index).unwrap(),
486 table_index: 0,
487 });
488 function.instruction(&Ins::End);
489 code.function(&function);
490 exports.export(export.name, ExportKind::Func, index);
491
492 table_offset += 1;
493 }
494
495 for (import, offset) in import_map {
496 exports.export(
497 &format!("{}:{}", import.module, import.name),
498 ExportKind::from(&import.ty),
499 offset,
500 );
501 }
502 if let Some(index) = wasi_start {
503 exports.export(metadata::START, ExportKind::Func, index);
504 }
505
506 let mut module = Module::new();
507
508 module.section(&types);
509 module.section(&imports);
510 module.section(&functions);
511
512 {
513 let mut tables = TableSection::new();
514 tables.table(TableType {
515 element_type: RefType::FUNCREF,
516 minimum: table_offset.into(),
517 maximum: None,
518 table64: false,
519 shared: false,
520 });
521 exports.export(metadata::INDIRECT_FUNCTION_TABLE, ExportKind::Table, 0);
522 module.section(&tables);
523 }
524
525 {
526 let mut memories = MemorySection::new();
527 memories.memory(MemoryType {
528 minimum: u64::from(memory_size),
529 maximum: None,
530 memory64: false,
531 shared: false,
532 page_size_log2: None,
533 });
534 exports.export(metadata::MEMORY, ExportKind::Memory, 0);
535 module.section(&memories);
536 }
537
538 module.section(&globals);
539 module.section(&exports);
540 module.section(&code);
541 module.section(&RawCustomSection(
542 &crate::base_producers().raw_custom_section(),
543 ));
544
545 let module = module.finish();
546 wasmparser::validate(&module).unwrap();
547
548 (module, dl_openables, indirection_table_base)
549}
550
551fn make_init_module(
556 metadata: &[Metadata],
557 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
558 env_exports: &[EnvExport<'_>],
559 dl_openables: DlOpenables,
560 indirection_table_base: u32,
561) -> Result<Vec<u8>> {
562 let mut module = Module::new();
563
564 let mut types = TypeSection::new();
566 types.ty().function([], []);
567 let thunk_ty = 0;
568 types.ty().function([ValType::I32], []);
569 let one_i32_param_ty = 1;
570 let mut type_offset = 2;
571
572 for metadata in metadata {
573 if metadata.dl_openable {
574 for export in &metadata.exports {
575 if let Type::Function(ty) = &export.key.ty {
576 types.ty().function(
577 ty.parameters.iter().copied().map(ValType::from),
578 ty.results.iter().copied().map(ValType::from),
579 );
580 }
581 }
582 }
583 }
584 for export in env_exports {
585 types.ty().function(
586 export.ty.parameters.iter().copied().map(ValType::from),
587 export.ty.results.iter().copied().map(ValType::from),
588 );
589 }
590 module.section(&types);
591
592 let mut imports = ImportSection::new();
593 imports.import(
594 metadata::ENV,
595 metadata::MEMORY,
596 MemoryType {
597 minimum: 0,
598 maximum: None,
599 memory64: false,
600 shared: false,
601 page_size_log2: None,
602 },
603 );
604 imports.import(
605 metadata::ENV,
606 metadata::INDIRECT_FUNCTION_TABLE,
607 TableType {
608 element_type: RefType::FUNCREF,
609 minimum: 0,
610 maximum: None,
611 table64: false,
612 shared: false,
613 },
614 );
615
616 let mut global_count = 0;
617 let mut global_map = HashMap::new();
618 let mut add_global_import = |imports: &mut ImportSection, module: &str, name: &str, mutable| {
619 *global_map
620 .entry((module.to_owned(), name.to_owned()))
621 .or_insert_with(|| {
622 imports.import(
623 module,
624 name,
625 wasm_encoder::GlobalType {
626 val_type: ValType::I32,
627 mutable,
628 shared: false,
629 },
630 );
631 get_and_increment(&mut global_count)
632 })
633 };
634
635 let mut function_count = 0;
636 let mut function_map = HashMap::new();
637 let mut add_function_import = |imports: &mut ImportSection, module: &str, name: &str, ty| {
638 *function_map
639 .entry((module.to_owned(), name.to_owned()))
640 .or_insert_with(|| {
641 imports.import(module, name, EntityType::Function(ty));
642 get_and_increment(&mut function_count)
643 })
644 };
645
646 let mut memory_address_inits = Vec::new();
647 let mut reloc_calls = Vec::new();
648 let mut ctor_calls = Vec::new();
649 let mut names = HashMap::new();
650
651 for (exporter, export, address) in dl_openables.global_addresses.iter() {
652 memory_address_inits.push(Ins::I32Const(i32::try_from(*address).unwrap()));
653 memory_address_inits.push(Ins::GlobalGet(add_global_import(
654 &mut imports,
655 metadata::ENV,
656 &format!("{exporter}:memory_base"),
657 false,
658 )));
659 memory_address_inits.push(Ins::GlobalGet(add_global_import(
660 &mut imports,
661 exporter,
662 export,
663 false,
664 )));
665 memory_address_inits.push(Ins::I32Add);
666 memory_address_inits.push(Ins::I32Store(MemArg {
667 offset: 0,
668 align: 2,
669 memory_index: 0,
670 }));
671 }
672
673 let mut init_task_exporter = exporters
674 .get(&ExportKey {
675 name: metadata::INIT_TASK,
676 ty: Type::Function(EMPTY_FUNCTION_TYPE.clone()),
677 })
678 .map(|(name, _)| name);
679
680 for (index, metadata) in metadata.iter().enumerate() {
681 names.insert_unique(index, metadata.name);
682
683 if metadata.has_data_relocs {
684 reloc_calls.push(Ins::Call(add_function_import(
685 &mut imports,
686 metadata.name,
687 metadata::APPLY_DATA_RELOCS,
688 thunk_ty,
689 )));
690 }
691
692 if metadata.has_ctors && metadata.has_initialize {
693 bail!(
694 "library {} exports both `{}` and `{}`; \
695 expected at most one of the two",
696 metadata.name,
697 metadata::CALL_CTORS,
698 metadata::INITIALIZE
699 );
700 }
701
702 if let (Some(exporter), true) = (
706 init_task_exporter,
707 metadata.has_ctors || metadata.has_initialize,
708 ) {
709 init_task_exporter = None;
712
713 ctor_calls.push(Ins::Call(add_function_import(
714 &mut imports,
715 exporter,
716 metadata::INIT_TASK,
717 thunk_ty,
718 )));
719 }
720
721 if metadata.has_ctors {
722 ctor_calls.push(Ins::Call(add_function_import(
723 &mut imports,
724 metadata.name,
725 metadata::CALL_CTORS,
726 thunk_ty,
727 )));
728 }
729
730 if metadata.has_initialize {
731 ctor_calls.push(Ins::Call(add_function_import(
732 &mut imports,
733 metadata.name,
734 metadata::INITIALIZE,
735 thunk_ty,
736 )));
737 }
738
739 if metadata.has_set_libraries {
740 ctor_calls.push(Ins::I32Const(
741 i32::try_from(dl_openables.libraries_address).unwrap(),
742 ));
743 ctor_calls.push(Ins::Call(add_function_import(
744 &mut imports,
745 metadata.name,
746 metadata::SET_LIBRARIES,
747 one_i32_param_ty,
748 )));
749 }
750
751 for import in &metadata.memory_address_imports {
752 let (exporter, _) = find_offset_exporter(import, exporters)?;
753
754 memory_address_inits.push(Ins::GlobalGet(add_global_import(
755 &mut imports,
756 metadata::ENV,
757 &format!("{exporter}:memory_base"),
758 false,
759 )));
760 memory_address_inits.push(Ins::GlobalGet(add_global_import(
761 &mut imports,
762 exporter,
763 import,
764 false,
765 )));
766 memory_address_inits.push(Ins::I32Add);
767 memory_address_inits.push(Ins::GlobalSet(add_global_import(
768 &mut imports,
769 metadata::ENV,
770 &format!("{}:{import}", metadata.name),
771 true,
772 )));
773 }
774 }
775
776 let mut dl_openable_functions = Vec::new();
777 for metadata in metadata {
778 if metadata.dl_openable {
779 for export in &metadata.exports {
780 if let Type::Function(_) = &export.key.ty {
781 dl_openable_functions.push(add_function_import(
782 &mut imports,
783 metadata.name,
784 export.key.name,
785 get_and_increment(&mut type_offset),
786 ));
787 }
788 }
789 }
790 }
791
792 let indirections = env_exports
793 .iter()
794 .map(|EnvExport { name, exporter, .. }| {
795 add_function_import(
796 &mut imports,
797 names[exporter],
798 name,
799 get_and_increment(&mut type_offset),
800 )
801 })
802 .collect::<Vec<_>>();
803
804 module.section(&imports);
805
806 {
807 let mut functions = FunctionSection::new();
808 functions.function(thunk_ty);
809 module.section(&functions);
810 }
811
812 module.section(&StartSection {
813 function_index: function_count,
814 });
815
816 {
817 let mut elements = ElementSection::new();
818 elements.active(
819 None,
820 &const_u32(dl_openables.table_base),
821 Elements::Functions(dl_openable_functions.into()),
822 );
823 elements.active(
824 None,
825 &const_u32(indirection_table_base),
826 Elements::Functions(indirections.into()),
827 );
828 module.section(&elements);
829 }
830
831 {
832 let mut code = CodeSection::new();
833 let mut function = Function::new([]);
834 for ins in memory_address_inits
835 .iter()
836 .chain(&reloc_calls)
837 .chain(&ctor_calls)
838 {
839 function.instruction(ins);
840 }
841 function.instruction(&Ins::End);
842 code.function(&function);
843 module.section(&code);
844 }
845
846 let mut data = DataSection::new();
847 data.active(0, &const_u32(dl_openables.memory_base), dl_openables.buffer);
848 module.section(&data);
849
850 module.section(&RawCustomSection(
851 &crate::base_producers().raw_custom_section(),
852 ));
853
854 let module = module.finish();
855 wasmparser::validate(&module)?;
856
857 Ok(module)
858}
859
860fn find_offset_exporter<'a>(
862 name: &str,
863 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
864) -> Result<(&'a str, &'a Export<'a>)> {
865 let export = ExportKey {
866 name,
867 ty: Type::Global(GlobalType {
868 ty: ValueType::I32,
869 mutable: false,
870 shared: false,
871 }),
872 };
873
874 exporters
875 .get(&export)
876 .copied()
877 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
878}
879
880fn find_function_exporter<'a>(
882 name: &str,
883 ty: &FunctionType,
884 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
885) -> Result<(&'a str, &'a Export<'a>)> {
886 let export = ExportKey {
887 name,
888 ty: Type::Function(ty.clone()),
889 };
890
891 exporters
892 .get(&export)
893 .copied()
894 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
895}
896
897fn find_tag_exporter<'a>(
899 name: &str,
900 ty: &FunctionType,
901 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
902) -> Result<(&'a str, &'a Export<'a>)> {
903 let export = ExportKey {
904 name,
905 ty: Type::Tag(ty.clone()),
906 };
907
908 exporters
909 .get(&export)
910 .copied()
911 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
912}
913
914fn resolve_exporters<'a>(
916 metadata: &'a [Metadata<'a>],
917) -> Result<IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>> {
918 let mut exporters = IndexMap::<_, Vec<_>>::new();
919 for metadata in metadata {
920 for export in &metadata.exports {
921 exporters
922 .entry(&export.key)
923 .or_default()
924 .push((metadata.name, export));
925 }
926 }
927 Ok(exporters)
928}
929
930fn resolve_symbols<'a>(
932 metadata: &'a [Metadata<'a>],
933 exporters: &'a IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>,
934) -> (
935 IndexMap<&'a ExportKey<'a>, (&'a str, &'a Export<'a>)>,
936 Vec<(&'a str, Export<'a>)>,
937 Vec<(&'a str, &'a ExportKey<'a>, &'a [(&'a str, &'a Export<'a>)])>,
938) {
939 let function_exporters = exporters
940 .iter()
941 .filter_map(|(export, exporters)| match &export.ty {
942 Type::Function(_) => Some((export.name, (export, exporters))),
943 Type::Global(_) | Type::Tag(_) => None,
944 })
945 .collect_unique::<IndexMap<_, _>>();
946
947 let mut resolved = IndexMap::new();
948 let mut missing = Vec::new();
949 let mut duplicates = Vec::new();
950
951 let mut triage = |metadata: &'a Metadata, export: Export<'a>| {
952 if let Some((key, value)) = exporters.get_key_value(&export.key) {
953 match value.as_slice() {
956 [] => unreachable!(),
957 [exporter] => {
958 resolved.insert(*key, *exporter);
959 }
960 [exporter, ..] => {
961 resolved.insert(*key, *exporter);
962 duplicates.push((metadata.name, *key, value.as_slice()));
963 }
964 }
965 } else {
966 missing.push((metadata.name, export));
967 }
968 };
969
970 for metadata in metadata {
971 for (name, (ty, flags)) in &metadata.env_imports {
972 triage(
973 metadata,
974 Export {
975 key: ExportKey {
976 name,
977 ty: Type::Function(ty.clone()),
978 },
979 flags: *flags,
980 },
981 );
982 }
983
984 for name in &metadata.memory_address_imports {
985 triage(
986 metadata,
987 Export {
988 key: ExportKey {
989 name,
990 ty: Type::Global(GlobalType {
991 ty: ValueType::I32,
992 mutable: false,
993 shared: false,
994 }),
995 },
996 flags: SymbolFlags::empty(),
997 },
998 );
999 }
1000
1001 for (name, ty) in &metadata.tag_imports {
1002 triage(
1003 metadata,
1004 Export {
1005 key: ExportKey {
1006 name,
1007 ty: Type::Tag(ty.clone()),
1008 },
1009 flags: SymbolFlags::empty(),
1010 },
1011 );
1012 }
1013 }
1014
1015 for metadata in metadata {
1016 for name in &metadata.table_address_imports {
1017 if let Some((key, value)) = function_exporters.get(name) {
1018 match value.as_slice() {
1021 [] => unreachable!(),
1022 [exporter] => {
1023 resolved.insert(key, *exporter);
1024 }
1025 [exporter, ..] => {
1026 resolved.insert(key, *exporter);
1027 duplicates.push((metadata.name, *key, value.as_slice()));
1028 }
1029 }
1030 } else if metadata.env_imports.iter().any(|(n, _)| n == name) {
1031 } else {
1034 missing.push((
1035 metadata.name,
1036 Export {
1037 key: ExportKey {
1038 name,
1039 ty: Type::Function(FunctionType {
1040 parameters: Vec::new(),
1041 results: Vec::new(),
1042 }),
1043 },
1044 flags: SymbolFlags::empty(),
1045 },
1046 ));
1047 }
1048 }
1049 }
1050
1051 for &name in ENV_REEXPORTS {
1056 let export = Export {
1057 key: ExportKey {
1058 name,
1059 ty: Type::Function(EMPTY_FUNCTION_TYPE.clone()),
1060 },
1061 flags: SymbolFlags::empty(),
1062 };
1063
1064 if let Some((key, value)) = exporters.get_key_value(&export.key) {
1065 match value.as_slice() {
1069 [] => unreachable!(),
1070 [exporter] | [exporter, ..] => {
1071 resolved.insert(*key, *exporter);
1072 }
1073 }
1074 }
1075 }
1076
1077 (resolved, missing, duplicates)
1078}
1079
1080fn topo_add(
1083 sorted: &mut IndexSet<usize>,
1084 dependencies: &IndexMap<usize, IndexSet<usize>>,
1085 element: usize,
1086) {
1087 let empty = &IndexSet::new();
1088 let deps = dependencies.get(&element).unwrap_or(empty);
1089
1090 for &dep in deps {
1092 if !(sorted.contains(&dep) || dependencies.get(&dep).unwrap_or(empty).contains(&element)) {
1093 topo_add(sorted, dependencies, dep);
1094 }
1095 }
1096
1097 sorted.insert(element);
1099
1100 for &dep in deps {
1102 if !sorted.contains(&dep) && dependencies.get(&dep).unwrap_or(empty).contains(&element) {
1103 topo_add(sorted, dependencies, dep);
1104 }
1105 }
1106}
1107
1108fn topo_sort(count: usize, dependencies: &IndexMap<usize, IndexSet<usize>>) -> Result<Vec<usize>> {
1111 let mut sorted = IndexSet::new();
1112 for index in 0..count {
1113 topo_add(&mut sorted, &dependencies, index);
1114 }
1115
1116 Ok(sorted.into_iter().collect())
1117}
1118
1119fn find_dependencies(
1122 metadata: &[Metadata],
1123 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
1124) -> Result<IndexMap<usize, IndexSet<usize>>> {
1125 let mut dependencies = IndexMap::<_, IndexSet<_>>::new();
1127 let mut indexes = HashMap::new();
1128 for (index, metadata) in metadata.iter().enumerate() {
1129 indexes.insert_unique(metadata.name, index);
1130 for &needed in &metadata.needed_libs {
1131 dependencies
1132 .entry(metadata.name)
1133 .or_default()
1134 .insert(needed);
1135 }
1136 for (import_name, (ty, _)) in &metadata.env_imports {
1137 dependencies
1138 .entry(metadata.name)
1139 .or_default()
1140 .insert(find_function_exporter(import_name, ty, exporters)?.0);
1141 }
1142 }
1143
1144 let mut dependencies = dependencies
1146 .into_iter()
1147 .map(|(k, v)| {
1148 (
1149 indexes[k],
1150 v.into_iter()
1151 .map(|v| indexes[v])
1152 .collect_unique::<IndexSet<_>>(),
1153 )
1154 })
1155 .collect_unique::<IndexMap<_, _>>();
1156
1157 let empty = &IndexSet::new();
1160
1161 loop {
1162 let mut new = IndexMap::<_, IndexSet<_>>::new();
1163 for (index, exporters) in &dependencies {
1164 for exporter in exporters {
1165 for exporter in dependencies.get(exporter).unwrap_or(empty) {
1166 if !exporters.contains(exporter) {
1167 new.entry(*index).or_default().insert(*exporter);
1168 }
1169 }
1170 }
1171 }
1172
1173 if new.is_empty() {
1174 break Ok(dependencies);
1175 } else {
1176 for (index, exporters) in new {
1177 dependencies.entry(index).or_default().extend(exporters);
1178 }
1179 }
1180 }
1181}
1182
1183struct EnvExports<'a> {
1184 exports: Vec<EnvExport<'a>>,
1185 reexport_cabi_realloc: bool,
1186}
1187
1188struct EnvExport<'a> {
1189 name: &'a str,
1190 ty: &'a FunctionType,
1191 exporter: usize,
1192}
1193
1194fn env_exports<'a>(
1204 metadata: &'a [Metadata<'a>],
1205 exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>,
1206 topo_sorted: &[usize],
1207) -> Result<EnvExports<'a>> {
1208 let function_exporters = exporters
1209 .iter()
1210 .filter_map(|(export, exporter)| {
1211 if let Type::Function(ty) = &export.ty {
1212 Some((export.name, (ty, *exporter)))
1213 } else {
1214 None
1215 }
1216 })
1217 .collect_unique::<HashMap<_, _>>();
1218
1219 let indexes = metadata
1220 .iter()
1221 .enumerate()
1222 .map(|(index, metadata)| (metadata.name, index))
1223 .collect_unique::<HashMap<_, _>>();
1224
1225 let mut result = Vec::new();
1226 let mut exported = HashSet::new();
1227 let mut seen = HashSet::new();
1228
1229 for &index in topo_sorted {
1230 let metadata = &metadata[index];
1231
1232 for name in &metadata.table_address_imports {
1233 if !exported.contains(name) {
1234 let (ty, (exporter, _)) = function_exporters
1235 .get(name)
1236 .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?;
1237
1238 result.push(EnvExport {
1239 name: *name,
1240 ty: *ty,
1241 exporter: indexes[exporter],
1242 });
1243 exported.insert(*name);
1244 }
1245 }
1246
1247 for (import_name, (ty, _)) in &metadata.env_imports {
1248 if !exported.contains(import_name) {
1249 let exporter = indexes[find_function_exporter(import_name, ty, exporters)
1250 .unwrap()
1251 .0];
1252 if !seen.contains(&exporter) {
1253 result.push(EnvExport {
1254 name: *import_name,
1255 ty,
1256 exporter,
1257 });
1258 exported.insert(*import_name);
1259 }
1260 }
1261 }
1262
1263 seen.insert(index);
1264 }
1265
1266 for &name in ENV_REEXPORTS {
1271 if !exported.contains(name) {
1272 if let Some(exporter) = exporters.get(&ExportKey {
1273 name,
1274 ty: Type::Function(EMPTY_FUNCTION_TYPE.clone()),
1275 }) {
1276 result.push(EnvExport {
1277 name,
1278 ty: &EMPTY_FUNCTION_TYPE,
1279 exporter: indexes[exporter.0],
1280 });
1281 exported.insert(name);
1282 }
1283 }
1284 }
1285
1286 let reexport_cabi_realloc = exported.contains(CABI_REALLOC);
1287
1288 Ok(EnvExports {
1289 exports: result,
1290 reexport_cabi_realloc,
1291 })
1292}
1293
1294fn make_stubs_module(missing: &[(&str, Export)]) -> Vec<u8> {
1296 let mut types = TypeSection::new();
1297 let mut exports = ExportSection::new();
1298 let mut functions = FunctionSection::new();
1299 let mut code = CodeSection::new();
1300 for (offset, (_, export)) in missing.iter().enumerate() {
1301 let offset = u32::try_from(offset).unwrap();
1302
1303 let Export {
1304 key:
1305 ExportKey {
1306 name,
1307 ty: Type::Function(ty),
1308 },
1309 ..
1310 } = export
1311 else {
1312 unreachable!();
1313 };
1314
1315 types.ty().function(
1316 ty.parameters.iter().copied().map(ValType::from),
1317 ty.results.iter().copied().map(ValType::from),
1318 );
1319 functions.function(offset);
1320 let mut function = Function::new([]);
1321 function.instruction(&Ins::Unreachable);
1322 function.instruction(&Ins::End);
1323 code.function(&function);
1324 exports.export(name, ExportKind::Func, offset);
1325 }
1326
1327 let mut module = Module::new();
1328
1329 module.section(&types);
1330 module.section(&functions);
1331 module.section(&exports);
1332 module.section(&code);
1333 module.section(&RawCustomSection(
1334 &crate::base_producers().raw_custom_section(),
1335 ));
1336
1337 let module = module.finish();
1338 wasmparser::validate(&module).unwrap();
1339
1340 module
1341}
1342
1343fn find_reachable<'a>(
1346 metadata: &'a [Metadata<'a>],
1347 dependencies: &IndexMap<usize, IndexSet<usize>>,
1348) -> IndexSet<&'a str> {
1349 let reachable = metadata
1350 .iter()
1351 .enumerate()
1352 .filter_map(|(index, metadata)| {
1353 if metadata.has_component_exports || metadata.dl_openable || metadata.has_wasi_start {
1354 Some(index)
1355 } else {
1356 None
1357 }
1358 })
1359 .collect_unique::<IndexSet<_>>();
1360
1361 let empty = &IndexSet::new();
1362
1363 reachable
1364 .iter()
1365 .chain(
1366 reachable
1367 .iter()
1368 .flat_map(|index| dependencies.get(index).unwrap_or(empty)),
1369 )
1370 .map(|&index| metadata[index].name)
1371 .collect()
1372}
1373
1374#[derive(Default)]
1376pub struct Linker {
1377 libraries: Vec<(String, Vec<u8>, bool)>,
1381
1382 adapters: Vec<(String, Vec<u8>)>,
1384
1385 validate: bool,
1387
1388 stub_missing_functions: bool,
1390
1391 use_built_in_libdl: bool,
1393
1394 debug_names: bool,
1396
1397 stack_size: Option<u32>,
1401
1402 merge_imports_based_on_semver: Option<bool>,
1406}
1407
1408impl Linker {
1409 pub fn library(mut self, name: &str, module: &[u8], dl_openable: bool) -> Result<Self> {
1414 self.libraries
1415 .push((name.to_owned(), module.to_vec(), dl_openable));
1416
1417 Ok(self)
1418 }
1419
1420 pub fn adapter(mut self, name: &str, module: &[u8]) -> Result<Self> {
1424 self.adapters.push((name.to_owned(), module.to_vec()));
1425
1426 Ok(self)
1427 }
1428
1429 pub fn validate(mut self, validate: bool) -> Self {
1431 self.validate = validate;
1432 self
1433 }
1434
1435 pub fn stack_size(mut self, stack_size: u32) -> Self {
1437 self.stack_size = Some(stack_size);
1438 self
1439 }
1440
1441 pub fn stub_missing_functions(mut self, stub_missing_functions: bool) -> Self {
1443 self.stub_missing_functions = stub_missing_functions;
1444 self
1445 }
1446
1447 pub fn use_built_in_libdl(mut self, use_built_in_libdl: bool) -> Self {
1449 self.use_built_in_libdl = use_built_in_libdl;
1450 self
1451 }
1452
1453 pub fn debug_names(mut self, enable: bool) -> Self {
1455 self.debug_names = enable;
1456 self
1457 }
1458
1459 pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
1465 self.merge_imports_based_on_semver = Some(merge);
1466 self
1467 }
1468
1469 pub fn encode(mut self) -> Result<Vec<u8>> {
1471 if self.use_built_in_libdl {
1472 self.use_built_in_libdl = false;
1473 self = self.library("libdl.so", include_bytes!("../libdl.so"), false)?;
1474 }
1475
1476 let adapter_names = self
1477 .adapters
1478 .iter()
1479 .map(|(name, _)| name.as_str())
1480 .collect_unique::<HashSet<_>>();
1481
1482 if adapter_names.len() != self.adapters.len() {
1483 bail!("duplicate adapter name");
1484 }
1485
1486 let metadata = self
1487 .libraries
1488 .iter()
1489 .map(|(name, module, dl_openable)| {
1490 Metadata::try_new(name, *dl_openable, module, &adapter_names)
1491 .with_context(|| format!("failed to extract linking metadata from {name}"))
1492 })
1493 .collect::<Result<Vec<_>>>()?;
1494
1495 {
1496 let names = self
1497 .libraries
1498 .iter()
1499 .map(|(name, ..)| name.as_str())
1500 .collect_unique::<HashSet<_>>();
1501
1502 let missing = metadata
1503 .iter()
1504 .filter_map(|metadata| {
1505 let missing = metadata
1506 .needed_libs
1507 .iter()
1508 .copied()
1509 .filter(|name| !names.contains(*name))
1510 .collect::<Vec<_>>();
1511
1512 if missing.is_empty() {
1513 None
1514 } else {
1515 Some((metadata.name, missing))
1516 }
1517 })
1518 .collect::<Vec<_>>();
1519
1520 if !missing.is_empty() {
1521 bail!(
1522 "missing libraries:\n{}",
1523 missing
1524 .iter()
1525 .map(|(needed_by, missing)| format!(
1526 "\t{needed_by} needs {}",
1527 missing.join(", ")
1528 ))
1529 .collect::<Vec<_>>()
1530 .join("\n")
1531 );
1532 }
1533 }
1534
1535 let exporters = resolve_exporters(&metadata)?;
1536
1537 let cabi_realloc_exporter = exporters
1538 .get(&ExportKey {
1539 name: "cabi_realloc",
1540 ty: Type::Function(FunctionType {
1541 parameters: vec![ValueType::I32; 4],
1542 results: vec![ValueType::I32],
1543 }),
1544 })
1545 .map(|exporters| exporters.first().unwrap().0);
1546
1547 let (exporters, missing, _) = resolve_symbols(&metadata, &exporters);
1548
1549 if !missing.is_empty() {
1550 if missing
1551 .iter()
1552 .all(|(_, export)| matches!(&export.key.ty, Type::Function(_)))
1553 && (self.stub_missing_functions
1554 || missing
1555 .iter()
1556 .all(|(_, export)| export.flags.contains(SymbolFlags::BINDING_WEAK)))
1557 {
1558 self.stub_missing_functions = false;
1559 self.libraries
1560 .push((STUB_LIBRARY_NAME.into(), make_stubs_module(&missing), false));
1561 return self.encode();
1562 } else {
1563 bail!(
1564 "unresolved symbol(s):\n{}",
1565 missing
1566 .iter()
1567 .filter(|(_, export)| !export.flags.contains(SymbolFlags::BINDING_WEAK))
1568 .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) })
1569 .collect::<Vec<_>>()
1570 .join("\n")
1571 );
1572 }
1573 }
1574
1575 let dependencies = find_dependencies(&metadata, &exporters)?;
1576
1577 {
1578 let reachable = find_reachable(&metadata, &dependencies);
1579 let unreachable = self
1580 .libraries
1581 .iter()
1582 .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone()))
1583 .collect_unique::<HashSet<_>>();
1584
1585 if !unreachable.is_empty() {
1586 self.libraries
1587 .retain(|(name, ..)| !unreachable.contains(name));
1588 return self.encode();
1589 }
1590 }
1591
1592 let topo_sorted = topo_sort(metadata.len(), &dependencies)?;
1593
1594 let EnvExports {
1595 exports: env_exports,
1596 reexport_cabi_realloc,
1597 } = env_exports(&metadata, &exporters, &topo_sorted)?;
1598
1599 let (env_module, dl_openables, table_base) = make_env_module(
1600 &metadata,
1601 &env_exports,
1602 if reexport_cabi_realloc {
1603 None
1606 } else {
1607 cabi_realloc_exporter
1608 },
1609 self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES),
1610 );
1611
1612 let mut encoder = ComponentEncoder::default()
1613 .validate(self.validate)
1614 .debug_names(self.debug_names);
1615 if let Some(merge) = self.merge_imports_based_on_semver {
1616 encoder = encoder.merge_imports_based_on_semver(merge);
1617 };
1618 encoder = encoder.module(&env_module)?;
1619
1620 for (name, module) in &self.adapters {
1621 encoder = encoder.adapter(name, module)?;
1622 }
1623
1624 let default_env_items = [
1625 Item {
1626 alias: metadata::MEMORY.into(),
1627 kind: ExportKind::Memory,
1628 which: MainOrAdapter::Main,
1629 name: metadata::MEMORY.into(),
1630 },
1631 Item {
1632 alias: metadata::INDIRECT_FUNCTION_TABLE.into(),
1633 kind: ExportKind::Table,
1634 which: MainOrAdapter::Main,
1635 name: metadata::INDIRECT_FUNCTION_TABLE.into(),
1636 },
1637 Item {
1638 alias: metadata::STACK_POINTER.into(),
1639 kind: ExportKind::Global,
1640 which: MainOrAdapter::Main,
1641 name: metadata::STACK_POINTER.into(),
1642 },
1643 Item {
1644 alias: metadata::INIT_STACK_POINTER.into(),
1645 kind: ExportKind::Global,
1646 which: MainOrAdapter::Main,
1647 name: metadata::INIT_STACK_POINTER.into(),
1648 },
1649 ];
1650
1651 let mut seen = HashSet::new();
1652 for index in topo_sorted {
1653 let (name, module, _) = &self.libraries[index];
1654 let metadata = &metadata[index];
1655
1656 let env_items = default_env_items
1657 .iter()
1658 .cloned()
1659 .chain([
1660 Item {
1661 alias: metadata::MEMORY_BASE.into(),
1662 kind: ExportKind::Global,
1663 which: MainOrAdapter::Main,
1664 name: format!("{name}:memory_base"),
1665 },
1666 Item {
1667 alias: metadata::TABLE_BASE.into(),
1668 kind: ExportKind::Global,
1669 which: MainOrAdapter::Main,
1670 name: format!("{name}:table_base"),
1671 },
1672 ])
1673 .chain(metadata.env_imports.iter().map(|(name, (ty, _))| {
1674 let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap();
1675
1676 Item {
1677 alias: (*name).into(),
1678 kind: ExportKind::Func,
1679 which: if seen.contains(exporter) {
1680 MainOrAdapter::Adapter(exporter.to_owned())
1681 } else {
1682 MainOrAdapter::Main
1683 },
1684 name: (*name).into(),
1685 }
1686 }))
1687 .chain(
1688 metadata
1689 .tag_imports
1690 .iter()
1691 .map(|(name, ty)| {
1692 let (exporter, _) = find_tag_exporter(name, ty, &exporters).unwrap();
1693
1694 Ok(Item {
1695 alias: (*name).into(),
1696 kind: ExportKind::Tag,
1697 which: if seen.contains(exporter) {
1698 MainOrAdapter::Adapter(exporter.to_owned())
1699 } else {
1700 bail!(
1712 "circular dependency prevents direct tag import from `{}`",
1713 exporter.to_owned()
1714 )
1715 },
1716 name: (*name).into(),
1717 })
1718 })
1719 .collect::<Result<Vec<_>>>()?,
1720 )
1721 .chain(if metadata.is_asyncified {
1722 vec![
1723 Item {
1724 alias: metadata::ASYNCIFY_STATE.into(),
1725 kind: ExportKind::Global,
1726 which: MainOrAdapter::Main,
1727 name: metadata::ASYNCIFY_STATE.into(),
1728 },
1729 Item {
1730 alias: metadata::ASYNCIFY_DATA.into(),
1731 kind: ExportKind::Global,
1732 which: MainOrAdapter::Main,
1733 name: metadata::ASYNCIFY_DATA.into(),
1734 },
1735 ]
1736 } else {
1737 vec![]
1738 })
1739 .collect();
1740
1741 let global_item = |address_name: &str| Item {
1742 alias: address_name.into(),
1743 kind: ExportKind::Global,
1744 which: MainOrAdapter::Main,
1745 name: format!("{name}:{address_name}"),
1746 };
1747
1748 let mem_items = metadata
1749 .memory_address_imports
1750 .iter()
1751 .copied()
1752 .map(global_item)
1753 .chain(
1754 [
1755 metadata::HEAP_BASE,
1756 metadata::HEAP_END,
1757 metadata::STACK_HIGH,
1758 metadata::STACK_LOW,
1759 ]
1760 .into_iter()
1761 .map(|name| Item {
1762 alias: name.into(),
1763 kind: ExportKind::Global,
1764 which: MainOrAdapter::Main,
1765 name: name.into(),
1766 }),
1767 )
1768 .collect();
1769
1770 let func_items = metadata
1771 .table_address_imports
1772 .iter()
1773 .copied()
1774 .map(global_item)
1775 .collect();
1776
1777 let mut import_items = BTreeMap::<_, Vec<_>>::new();
1778 for import in &metadata.imports {
1779 import_items.entry(import.module).or_default().push(Item {
1780 alias: import.name.into(),
1781 kind: ExportKind::from(&import.ty),
1782 which: MainOrAdapter::Main,
1783 name: format!("{}:{}", import.module, import.name),
1784 });
1785 }
1786
1787 encoder = encoder.library(
1788 name,
1789 module,
1790 LibraryInfo {
1791 instantiate_after_shims: false,
1792 arguments: [
1793 (metadata::GOT_MEM.into(), Instance::Items(mem_items)),
1794 (metadata::GOT_FUNC.into(), Instance::Items(func_items)),
1795 (metadata::ENV.into(), Instance::Items(env_items)),
1796 ]
1797 .into_iter()
1798 .chain(
1799 import_items
1800 .into_iter()
1801 .map(|(k, v)| (k.into(), Instance::Items(v))),
1802 )
1803 .collect(),
1804 },
1805 )?;
1806
1807 seen.insert(name.as_str());
1808 }
1809
1810 encoder
1811 .library(
1812 "__init",
1813 &make_init_module(
1814 &metadata,
1815 &exporters,
1816 &env_exports,
1817 dl_openables,
1818 table_base,
1819 )?,
1820 LibraryInfo {
1821 instantiate_after_shims: true,
1822 arguments: iter::once((
1823 metadata::ENV.into(),
1824 Instance::MainOrAdapter(MainOrAdapter::Main),
1825 ))
1826 .chain(self.libraries.iter().map(|(name, ..)| {
1827 (
1828 name.clone(),
1829 Instance::MainOrAdapter(MainOrAdapter::Adapter(name.clone())),
1830 )
1831 }))
1832 .collect(),
1833 },
1834 )?
1835 .encode()
1836 }
1837}