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";
52
53enum Address<'a> {
54 Function(u32),
55 Global(&'a str),
56}
57
58struct DlOpenables<'a> {
63 table_base: u32,
65
66 memory_base: u32,
68
69 buffer: Vec<u8>,
71
72 global_addresses: Vec<(&'a str, &'a str, u32)>,
76
77 function_count: u32,
79
80 libraries_address: u32,
85}
86
87impl<'a> DlOpenables<'a> {
88 fn new(table_base: u32, memory_base: u32, metadata: &'a [Metadata<'a>]) -> Self {
91 let mut function_count = 0;
92 let mut buffer = Vec::new();
93 let mut global_addresses = Vec::new();
94 let mut libraries = metadata
95 .iter()
96 .filter(|metadata| metadata.dl_openable)
97 .map(|metadata| {
98 let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
99 write_bytes_padded(&mut buffer, metadata.name.as_bytes());
100
101 let mut symbols = metadata
102 .exports
103 .iter()
104 .map(|export| {
105 let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
106 write_bytes_padded(&mut buffer, export.key.name.as_bytes());
107
108 let address = match &export.key.ty {
109 Type::Function(_) => Address::Function(
110 table_base + get_and_increment(&mut function_count),
111 ),
112 Type::Global(_) => Address::Global(export.key.name),
113 };
114
115 (export.key.name, name_address, address)
116 })
117 .collect::<Vec<_>>();
118
119 symbols.sort_by_key(|(name, ..)| *name);
120
121 let start = buffer.len();
122 for (name, name_address, address) in symbols {
123 write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
124 write_u32(&mut buffer, name_address);
125 match address {
126 Address::Function(address) => write_u32(&mut buffer, address),
127 Address::Global(name) => {
128 global_addresses.push((
129 metadata.name,
130 name,
131 memory_base + u32::try_from(buffer.len()).unwrap(),
132 ));
133
134 write_u32(&mut buffer, 0);
135 }
136 }
137 }
138
139 (
140 metadata.name,
141 name_address,
142 metadata.exports.len(),
143 memory_base + u32::try_from(start).unwrap(),
144 )
145 })
146 .collect::<Vec<_>>();
147
148 libraries.sort_by_key(|(name, ..)| *name);
149
150 let start = buffer.len();
151 for (name, name_address, count, symbols) in &libraries {
152 write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
153 write_u32(&mut buffer, *name_address);
154 write_u32(&mut buffer, u32::try_from(*count).unwrap());
155 write_u32(&mut buffer, *symbols);
156 }
157
158 let libraries_address = memory_base + u32::try_from(buffer.len()).unwrap();
159 write_u32(&mut buffer, u32::try_from(libraries.len()).unwrap());
160 write_u32(&mut buffer, memory_base + u32::try_from(start).unwrap());
161
162 Self {
163 table_base,
164 memory_base,
165 buffer,
166 global_addresses,
167 function_count,
168 libraries_address,
169 }
170 }
171}
172
173fn write_u32(buffer: &mut Vec<u8>, value: u32) {
174 buffer.extend(value.to_le_bytes());
175}
176
177fn write_bytes_padded(buffer: &mut Vec<u8>, bytes: &[u8]) {
178 buffer.extend(bytes);
179
180 let len = u32::try_from(bytes.len()).unwrap();
181 for _ in len..align(len, 4) {
182 buffer.push(0);
183 }
184}
185
186fn align(a: u32, b: u32) -> u32 {
187 assert!(b.is_power_of_two());
188 (a + (b - 1)) & !(b - 1)
189}
190
191fn get_and_increment(n: &mut u32) -> u32 {
192 let v = *n;
193 *n += 1;
194 v
195}
196
197fn const_u32(a: u32) -> ConstExpr {
198 ConstExpr::i32_const(a as i32)
199}
200
201trait Length {
203 fn len(&self) -> usize;
204}
205
206impl<T> Length for HashSet<T> {
207 fn len(&self) -> usize {
208 HashSet::len(self)
209 }
210}
211
212impl<K, V> Length for HashMap<K, V> {
213 fn len(&self) -> usize {
214 HashMap::len(self)
215 }
216}
217
218impl<T> Length for IndexSet<T> {
219 fn len(&self) -> usize {
220 IndexSet::len(self)
221 }
222}
223
224impl<K, V> Length for IndexMap<K, V> {
225 fn len(&self) -> usize {
226 IndexMap::len(self)
227 }
228}
229
230trait CollectUnique: Iterator + Sized {
233 fn collect_unique<T: FromIterator<Self::Item> + Length>(self) -> T {
234 let tmp = self.collect::<Vec<_>>();
235 let len = tmp.len();
236 let result = tmp.into_iter().collect::<T>();
237 assert!(
238 result.len() == len,
239 "one or more duplicate items detected when collecting into set or map"
240 );
241 result
242 }
243}
244
245impl<T: Iterator> CollectUnique for T {}
246
247trait InsertUnique {
249 type Key;
250 type Value;
251
252 fn insert_unique(&mut self, k: Self::Key, v: Self::Value);
253}
254
255impl<K: Hash + Eq + PartialEq + Debug, V: Debug> InsertUnique for HashMap<K, V> {
256 type Key = K;
257 type Value = V;
258
259 fn insert_unique(&mut self, k: Self::Key, v: Self::Value) {
260 if let Some(old_v) = self.get(&k) {
261 panic!(
262 "duplicate item inserted into map for key {k:?} (old value: {old_v:?}; new value: {v:?})"
263 );
264 }
265 self.insert(k, v);
266 }
267}
268
269fn make_env_module<'a>(
272 metadata: &'a [Metadata<'a>],
273 function_exports: &[(&str, &FunctionType, usize)],
274 cabi_realloc_exporter: Option<&str>,
275 stack_size_bytes: u32,
276) -> (Vec<u8>, DlOpenables<'a>, u32) {
277 let mut types = TypeSection::new();
279 let mut imports = ImportSection::new();
280 let mut import_map = IndexMap::new();
281 let mut function_count = 0;
282 let mut global_offset = 0;
283 let mut wasi_start = None;
284
285 for metadata in metadata {
286 for import in &metadata.imports {
287 if let Entry::Vacant(entry) = import_map.entry(import) {
288 imports.import(
289 import.module,
290 import.name,
291 match &import.ty {
292 Type::Function(ty) => {
293 let index = get_and_increment(&mut function_count);
294 entry.insert(index);
295 types.ty().function(
296 ty.parameters.iter().copied().map(ValType::from),
297 ty.results.iter().copied().map(ValType::from),
298 );
299 EntityType::Function(index)
300 }
301 Type::Global(ty) => {
302 entry.insert(get_and_increment(&mut global_offset));
303 EntityType::Global(wasm_encoder::GlobalType {
304 val_type: ty.ty.into(),
305 mutable: ty.mutable,
306 shared: ty.shared,
307 })
308 }
309 },
310 );
311 }
312 }
313
314 if metadata.has_wasi_start {
315 if wasi_start.is_some() {
316 panic!("multiple libraries export _start");
317 }
318 let index = get_and_increment(&mut function_count);
319
320 types.ty().function(vec![], vec![]);
321 imports.import(metadata.name, "_start", EntityType::Function(index));
322
323 wasi_start = Some(index);
324 }
325 }
326
327 let mut memory_offset = stack_size_bytes;
328
329 let mut table_offset = 1;
333 let mut globals = GlobalSection::new();
334 let mut exports = ExportSection::new();
335
336 if let Some(exporter) = cabi_realloc_exporter {
337 let index = get_and_increment(&mut function_count);
338 types.ty().function([ValType::I32; 4], [ValType::I32]);
339 imports.import(exporter, "cabi_realloc", EntityType::Function(index));
340 exports.export("cabi_realloc", ExportKind::Func, index);
341 }
342
343 let dl_openables = DlOpenables::new(table_offset, memory_offset, metadata);
344
345 table_offset += dl_openables.function_count;
346 memory_offset += u32::try_from(dl_openables.buffer.len()).unwrap();
347
348 let memory_size = {
349 let mut add_global_export = |name: &str, value, mutable| {
350 let index = globals.len();
351 globals.global(
352 wasm_encoder::GlobalType {
353 val_type: ValType::I32,
354 mutable,
355 shared: false,
356 },
357 &const_u32(value),
358 );
359 exports.export(name, ExportKind::Global, index);
360 };
361
362 add_global_export("__stack_pointer", stack_size_bytes, true);
363
364 let has_asyncified_module = metadata.iter().any(|m| m.is_asyncified);
367 if has_asyncified_module {
368 add_global_export("__asyncify_state", 0, true);
369 add_global_export("__asyncify_data", 0, true);
370 }
371
372 for metadata in metadata {
373 memory_offset = align(memory_offset, 1 << metadata.mem_info.memory_alignment);
374 table_offset = align(table_offset, 1 << metadata.mem_info.table_alignment);
375
376 add_global_export(
377 &format!("{}:memory_base", metadata.name),
378 memory_offset,
379 false,
380 );
381 add_global_export(
382 &format!("{}:table_base", metadata.name),
383 table_offset,
384 false,
385 );
386
387 memory_offset += metadata.mem_info.memory_size;
388 table_offset += metadata.mem_info.table_size;
389
390 for import in &metadata.memory_address_imports {
391 add_global_export(&format!("{}:{import}", metadata.name), 0, true);
394 }
395 }
396
397 {
398 let offsets = function_exports
399 .iter()
400 .enumerate()
401 .map(|(offset, (name, _, exporter))| {
402 (
403 *name,
404 (
405 table_offset + u32::try_from(offset).unwrap(),
406 metadata[*exporter].name == STUB_LIBRARY_NAME,
407 ),
408 )
409 })
410 .collect_unique::<HashMap<_, _>>();
411
412 for metadata in metadata {
413 for import in &metadata.table_address_imports {
414 let &(offset, is_stub) = offsets.get(import).unwrap();
415 if is_stub
416 && metadata
417 .env_imports
418 .iter()
419 .any(|e| e.0 == *import && e.1.1.contains(SymbolFlags::BINDING_WEAK))
420 {
421 add_global_export(&format!("{}:{import}", metadata.name), 0, true);
422 } else {
423 add_global_export(&format!("{}:{import}", metadata.name), offset, true);
424 }
425 }
426 }
427 }
428
429 memory_offset = align(memory_offset, HEAP_ALIGNMENT_BYTES);
430 add_global_export("__heap_base", memory_offset, true);
431
432 let heap_end = align(memory_offset, PAGE_SIZE_BYTES);
433 add_global_export("__heap_end", heap_end, true);
434 heap_end / PAGE_SIZE_BYTES
435 };
436
437 let indirection_table_base = table_offset;
438
439 let mut functions = FunctionSection::new();
440 let mut code = CodeSection::new();
441 for (name, ty, _) in function_exports {
442 let index = get_and_increment(&mut function_count);
443 types.ty().function(
444 ty.parameters.iter().copied().map(ValType::from),
445 ty.results.iter().copied().map(ValType::from),
446 );
447 functions.function(u32::try_from(index).unwrap());
448 let mut function = Function::new([]);
449 for local in 0..ty.parameters.len() {
450 function.instruction(&Ins::LocalGet(u32::try_from(local).unwrap()));
451 }
452 function.instruction(&Ins::I32Const(i32::try_from(table_offset).unwrap()));
453 function.instruction(&Ins::CallIndirect {
454 type_index: u32::try_from(index).unwrap(),
455 table_index: 0,
456 });
457 function.instruction(&Ins::End);
458 code.function(&function);
459 exports.export(name, ExportKind::Func, index);
460
461 table_offset += 1;
462 }
463
464 for (import, offset) in import_map {
465 exports.export(
466 &format!("{}:{}", import.module, import.name),
467 ExportKind::from(&import.ty),
468 offset,
469 );
470 }
471 if let Some(index) = wasi_start {
472 exports.export("_start", ExportKind::Func, index);
473 }
474
475 let mut module = Module::new();
476
477 module.section(&types);
478 module.section(&imports);
479 module.section(&functions);
480
481 {
482 let mut tables = TableSection::new();
483 tables.table(TableType {
484 element_type: RefType::FUNCREF,
485 minimum: table_offset.into(),
486 maximum: None,
487 table64: false,
488 shared: false,
489 });
490 exports.export("__indirect_function_table", ExportKind::Table, 0);
491 module.section(&tables);
492 }
493
494 {
495 let mut memories = MemorySection::new();
496 memories.memory(MemoryType {
497 minimum: u64::from(memory_size),
498 maximum: None,
499 memory64: false,
500 shared: false,
501 page_size_log2: None,
502 });
503 exports.export("memory", ExportKind::Memory, 0);
504 module.section(&memories);
505 }
506
507 module.section(&globals);
508 module.section(&exports);
509 module.section(&code);
510 module.section(&RawCustomSection(
511 &crate::base_producers().raw_custom_section(),
512 ));
513
514 let module = module.finish();
515 wasmparser::validate(&module).unwrap();
516
517 (module, dl_openables, indirection_table_base)
518}
519
520fn make_init_module(
525 metadata: &[Metadata],
526 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
527 function_exports: &[(&str, &FunctionType, usize)],
528 dl_openables: DlOpenables,
529 indirection_table_base: u32,
530) -> Result<Vec<u8>> {
531 let mut module = Module::new();
532
533 let mut types = TypeSection::new();
535 types.ty().function([], []);
536 let thunk_ty = 0;
537 types.ty().function([ValType::I32], []);
538 let one_i32_param_ty = 1;
539 let mut type_offset = 2;
540
541 for metadata in metadata {
542 if metadata.dl_openable {
543 for export in &metadata.exports {
544 if let Type::Function(ty) = &export.key.ty {
545 types.ty().function(
546 ty.parameters.iter().copied().map(ValType::from),
547 ty.results.iter().copied().map(ValType::from),
548 );
549 }
550 }
551 }
552 }
553 for (_, ty, _) in function_exports {
554 types.ty().function(
555 ty.parameters.iter().copied().map(ValType::from),
556 ty.results.iter().copied().map(ValType::from),
557 );
558 }
559 module.section(&types);
560
561 let mut imports = ImportSection::new();
562 imports.import(
563 "env",
564 "memory",
565 MemoryType {
566 minimum: 0,
567 maximum: None,
568 memory64: false,
569 shared: false,
570 page_size_log2: None,
571 },
572 );
573 imports.import(
574 "env",
575 "__indirect_function_table",
576 TableType {
577 element_type: RefType::FUNCREF,
578 minimum: 0,
579 maximum: None,
580 table64: false,
581 shared: false,
582 },
583 );
584
585 let mut global_count = 0;
586 let mut global_map = HashMap::new();
587 let mut add_global_import = |imports: &mut ImportSection, module: &str, name: &str, mutable| {
588 *global_map
589 .entry((module.to_owned(), name.to_owned()))
590 .or_insert_with(|| {
591 imports.import(
592 module,
593 name,
594 wasm_encoder::GlobalType {
595 val_type: ValType::I32,
596 mutable,
597 shared: false,
598 },
599 );
600 get_and_increment(&mut global_count)
601 })
602 };
603
604 let mut function_count = 0;
605 let mut function_map = HashMap::new();
606 let mut add_function_import = |imports: &mut ImportSection, module: &str, name: &str, ty| {
607 *function_map
608 .entry((module.to_owned(), name.to_owned()))
609 .or_insert_with(|| {
610 imports.import(module, name, EntityType::Function(ty));
611 get_and_increment(&mut function_count)
612 })
613 };
614
615 let mut memory_address_inits = Vec::new();
616 let mut reloc_calls = Vec::new();
617 let mut ctor_calls = Vec::new();
618 let mut names = HashMap::new();
619
620 for (exporter, export, address) in dl_openables.global_addresses.iter() {
621 memory_address_inits.push(Ins::I32Const(i32::try_from(*address).unwrap()));
622 memory_address_inits.push(Ins::GlobalGet(add_global_import(
623 &mut imports,
624 "env",
625 &format!("{exporter}:memory_base"),
626 false,
627 )));
628 memory_address_inits.push(Ins::GlobalGet(add_global_import(
629 &mut imports,
630 exporter,
631 export,
632 false,
633 )));
634 memory_address_inits.push(Ins::I32Add);
635 memory_address_inits.push(Ins::I32Store(MemArg {
636 offset: 0,
637 align: 2,
638 memory_index: 0,
639 }));
640 }
641
642 for (index, metadata) in metadata.iter().enumerate() {
643 names.insert_unique(index, metadata.name);
644
645 if metadata.has_data_relocs {
646 reloc_calls.push(Ins::Call(add_function_import(
647 &mut imports,
648 metadata.name,
649 "__wasm_apply_data_relocs",
650 thunk_ty,
651 )));
652 }
653
654 if metadata.has_ctors && metadata.has_initialize {
655 bail!(
656 "library {} exports both `__wasm_call_ctors` and `_initialize`; \
657 expected at most one of the two",
658 metadata.name
659 );
660 }
661
662 if metadata.has_ctors {
663 ctor_calls.push(Ins::Call(add_function_import(
664 &mut imports,
665 metadata.name,
666 "__wasm_call_ctors",
667 thunk_ty,
668 )));
669 }
670
671 if metadata.has_initialize {
672 ctor_calls.push(Ins::Call(add_function_import(
673 &mut imports,
674 metadata.name,
675 "_initialize",
676 thunk_ty,
677 )));
678 }
679
680 if metadata.has_set_libraries {
681 ctor_calls.push(Ins::I32Const(
682 i32::try_from(dl_openables.libraries_address).unwrap(),
683 ));
684 ctor_calls.push(Ins::Call(add_function_import(
685 &mut imports,
686 metadata.name,
687 "__wasm_set_libraries",
688 one_i32_param_ty,
689 )));
690 }
691
692 for import in &metadata.memory_address_imports {
693 let (exporter, _) = find_offset_exporter(import, exporters)?;
694
695 memory_address_inits.push(Ins::GlobalGet(add_global_import(
696 &mut imports,
697 "env",
698 &format!("{exporter}:memory_base"),
699 false,
700 )));
701 memory_address_inits.push(Ins::GlobalGet(add_global_import(
702 &mut imports,
703 exporter,
704 import,
705 false,
706 )));
707 memory_address_inits.push(Ins::I32Add);
708 memory_address_inits.push(Ins::GlobalSet(add_global_import(
709 &mut imports,
710 "env",
711 &format!("{}:{import}", metadata.name),
712 true,
713 )));
714 }
715 }
716
717 let mut dl_openable_functions = Vec::new();
718 for metadata in metadata {
719 if metadata.dl_openable {
720 for export in &metadata.exports {
721 if let Type::Function(_) = &export.key.ty {
722 dl_openable_functions.push(add_function_import(
723 &mut imports,
724 metadata.name,
725 export.key.name,
726 get_and_increment(&mut type_offset),
727 ));
728 }
729 }
730 }
731 }
732
733 let indirections = function_exports
734 .iter()
735 .map(|(name, _, index)| {
736 add_function_import(
737 &mut imports,
738 names[index],
739 name,
740 get_and_increment(&mut type_offset),
741 )
742 })
743 .collect::<Vec<_>>();
744
745 module.section(&imports);
746
747 {
748 let mut functions = FunctionSection::new();
749 functions.function(thunk_ty);
750 module.section(&functions);
751 }
752
753 module.section(&StartSection {
754 function_index: function_count,
755 });
756
757 {
758 let mut elements = ElementSection::new();
759 elements.active(
760 None,
761 &const_u32(dl_openables.table_base),
762 Elements::Functions(dl_openable_functions.into()),
763 );
764 elements.active(
765 None,
766 &const_u32(indirection_table_base),
767 Elements::Functions(indirections.into()),
768 );
769 module.section(&elements);
770 }
771
772 {
773 let mut code = CodeSection::new();
774 let mut function = Function::new([]);
775 for ins in memory_address_inits
776 .iter()
777 .chain(&reloc_calls)
778 .chain(&ctor_calls)
779 {
780 function.instruction(ins);
781 }
782 function.instruction(&Ins::End);
783 code.function(&function);
784 module.section(&code);
785 }
786
787 let mut data = DataSection::new();
788 data.active(0, &const_u32(dl_openables.memory_base), dl_openables.buffer);
789 module.section(&data);
790
791 module.section(&RawCustomSection(
792 &crate::base_producers().raw_custom_section(),
793 ));
794
795 let module = module.finish();
796 wasmparser::validate(&module)?;
797
798 Ok(module)
799}
800
801fn find_offset_exporter<'a>(
803 name: &str,
804 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
805) -> Result<(&'a str, &'a Export<'a>)> {
806 let export = ExportKey {
807 name,
808 ty: Type::Global(GlobalType {
809 ty: ValueType::I32,
810 mutable: false,
811 shared: false,
812 }),
813 };
814
815 exporters
816 .get(&export)
817 .copied()
818 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
819}
820
821fn find_function_exporter<'a>(
823 name: &str,
824 ty: &FunctionType,
825 exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
826) -> Result<(&'a str, &'a Export<'a>)> {
827 let export = ExportKey {
828 name,
829 ty: Type::Function(ty.clone()),
830 };
831
832 exporters
833 .get(&export)
834 .copied()
835 .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
836}
837
838fn resolve_exporters<'a>(
840 metadata: &'a [Metadata<'a>],
841) -> Result<IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>> {
842 let mut exporters = IndexMap::<_, Vec<_>>::new();
843 for metadata in metadata {
844 for export in &metadata.exports {
845 exporters
846 .entry(&export.key)
847 .or_default()
848 .push((metadata.name, export));
849 }
850 }
851 Ok(exporters)
852}
853
854fn resolve_symbols<'a>(
856 metadata: &'a [Metadata<'a>],
857 exporters: &'a IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>,
858) -> (
859 IndexMap<&'a ExportKey<'a>, (&'a str, &'a Export<'a>)>,
860 Vec<(&'a str, Export<'a>)>,
861 Vec<(&'a str, &'a ExportKey<'a>, &'a [(&'a str, &'a Export<'a>)])>,
862) {
863 let function_exporters = exporters
864 .iter()
865 .filter_map(|(export, exporters)| {
866 if let Type::Function(_) = &export.ty {
867 Some((export.name, (export, exporters)))
868 } else {
869 None
870 }
871 })
872 .collect_unique::<IndexMap<_, _>>();
873
874 let mut resolved = IndexMap::new();
875 let mut missing = Vec::new();
876 let mut duplicates = Vec::new();
877
878 let mut triage = |metadata: &'a Metadata, export: Export<'a>| {
879 if let Some((key, value)) = exporters.get_key_value(&export.key) {
880 match value.as_slice() {
881 [] => unreachable!(),
882 [exporter] => {
883 resolved.insert(*key, *exporter);
886 }
887 [exporter, ..] => {
888 resolved.insert(*key, *exporter);
889 duplicates.push((metadata.name, *key, value.as_slice()));
890 }
891 }
892 } else {
893 missing.push((metadata.name, export));
894 }
895 };
896
897 for metadata in metadata {
898 for (name, (ty, flags)) in &metadata.env_imports {
899 triage(
900 metadata,
901 Export {
902 key: ExportKey {
903 name,
904 ty: Type::Function(ty.clone()),
905 },
906 flags: *flags,
907 },
908 );
909 }
910
911 for name in &metadata.memory_address_imports {
912 triage(
913 metadata,
914 Export {
915 key: ExportKey {
916 name,
917 ty: Type::Global(GlobalType {
918 ty: ValueType::I32,
919 mutable: false,
920 shared: false,
921 }),
922 },
923 flags: SymbolFlags::empty(),
924 },
925 );
926 }
927 }
928
929 for metadata in metadata {
930 for name in &metadata.table_address_imports {
931 if let Some((key, value)) = function_exporters.get(name) {
932 match value.as_slice() {
935 [] => unreachable!(),
936 [exporter] => {
937 resolved.insert(key, *exporter);
938 }
939 [exporter, ..] => {
940 resolved.insert(key, *exporter);
941 duplicates.push((metadata.name, *key, value.as_slice()));
942 }
943 }
944 } else if metadata.env_imports.iter().any(|(n, _)| n == name) {
945 } else {
948 missing.push((
949 metadata.name,
950 Export {
951 key: ExportKey {
952 name,
953 ty: Type::Function(FunctionType {
954 parameters: Vec::new(),
955 results: Vec::new(),
956 }),
957 },
958 flags: SymbolFlags::empty(),
959 },
960 ));
961 }
962 }
963 }
964
965 (resolved, missing, duplicates)
966}
967
968fn topo_add(
971 sorted: &mut IndexSet<usize>,
972 dependencies: &IndexMap<usize, IndexSet<usize>>,
973 element: usize,
974) {
975 let empty = &IndexSet::new();
976 let deps = dependencies.get(&element).unwrap_or(empty);
977
978 for &dep in deps {
980 if !(sorted.contains(&dep) || dependencies.get(&dep).unwrap_or(empty).contains(&element)) {
981 topo_add(sorted, dependencies, dep);
982 }
983 }
984
985 sorted.insert(element);
987
988 for &dep in deps {
990 if !sorted.contains(&dep) && dependencies.get(&dep).unwrap_or(empty).contains(&element) {
991 topo_add(sorted, dependencies, dep);
992 }
993 }
994}
995
996fn topo_sort(count: usize, dependencies: &IndexMap<usize, IndexSet<usize>>) -> Result<Vec<usize>> {
999 let mut sorted = IndexSet::new();
1000 for index in 0..count {
1001 topo_add(&mut sorted, &dependencies, index);
1002 }
1003
1004 Ok(sorted.into_iter().collect())
1005}
1006
1007fn find_dependencies(
1010 metadata: &[Metadata],
1011 exporters: &IndexMap<&ExportKey, (&str, &Export)>,
1012) -> Result<IndexMap<usize, IndexSet<usize>>> {
1013 let mut dependencies = IndexMap::<_, IndexSet<_>>::new();
1015 let mut indexes = HashMap::new();
1016 for (index, metadata) in metadata.iter().enumerate() {
1017 indexes.insert_unique(metadata.name, index);
1018 for &needed in &metadata.needed_libs {
1019 dependencies
1020 .entry(metadata.name)
1021 .or_default()
1022 .insert(needed);
1023 }
1024 for (import_name, (ty, _)) in &metadata.env_imports {
1025 dependencies
1026 .entry(metadata.name)
1027 .or_default()
1028 .insert(find_function_exporter(import_name, ty, exporters)?.0);
1029 }
1030 }
1031
1032 let mut dependencies = dependencies
1034 .into_iter()
1035 .map(|(k, v)| {
1036 (
1037 indexes[k],
1038 v.into_iter()
1039 .map(|v| indexes[v])
1040 .collect_unique::<IndexSet<_>>(),
1041 )
1042 })
1043 .collect_unique::<IndexMap<_, _>>();
1044
1045 let empty = &IndexSet::new();
1048
1049 loop {
1050 let mut new = IndexMap::<_, IndexSet<_>>::new();
1051 for (index, exporters) in &dependencies {
1052 for exporter in exporters {
1053 for exporter in dependencies.get(exporter).unwrap_or(empty) {
1054 if !exporters.contains(exporter) {
1055 new.entry(*index).or_default().insert(*exporter);
1056 }
1057 }
1058 }
1059 }
1060
1061 if new.is_empty() {
1062 break Ok(dependencies);
1063 } else {
1064 for (index, exporters) in new {
1065 dependencies.entry(index).or_default().extend(exporters);
1066 }
1067 }
1068 }
1069}
1070
1071struct EnvFunctionExports<'a> {
1072 exports: Vec<(&'a str, &'a FunctionType, usize)>,
1073 reexport_cabi_realloc: bool,
1074}
1075
1076fn env_function_exports<'a>(
1080 metadata: &'a [Metadata<'a>],
1081 exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>,
1082 topo_sorted: &[usize],
1083) -> Result<EnvFunctionExports<'a>> {
1084 let function_exporters = exporters
1085 .iter()
1086 .filter_map(|(export, exporter)| {
1087 if let Type::Function(ty) = &export.ty {
1088 Some((export.name, (ty, *exporter)))
1089 } else {
1090 None
1091 }
1092 })
1093 .collect_unique::<HashMap<_, _>>();
1094
1095 let indexes = metadata
1096 .iter()
1097 .enumerate()
1098 .map(|(index, metadata)| (metadata.name, index))
1099 .collect_unique::<HashMap<_, _>>();
1100
1101 let mut result = Vec::new();
1102 let mut exported = HashSet::new();
1103 let mut seen = HashSet::new();
1104
1105 for &index in topo_sorted {
1106 let metadata = &metadata[index];
1107
1108 for name in &metadata.table_address_imports {
1109 if !exported.contains(name) {
1110 let (ty, (exporter, _)) = function_exporters
1111 .get(name)
1112 .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?;
1113
1114 result.push((*name, *ty, indexes[exporter]));
1115 exported.insert(*name);
1116 }
1117 }
1118
1119 for (import_name, (ty, _)) in &metadata.env_imports {
1120 if !exported.contains(import_name) {
1121 let exporter = indexes[find_function_exporter(import_name, ty, exporters)
1122 .unwrap()
1123 .0];
1124 if !seen.contains(&exporter) {
1125 result.push((*import_name, ty, exporter));
1126 exported.insert(*import_name);
1127 }
1128 }
1129 }
1130 seen.insert(index);
1131 }
1132
1133 let reexport_cabi_realloc = exported.contains("cabi_realloc");
1134
1135 Ok(EnvFunctionExports {
1136 exports: result,
1137 reexport_cabi_realloc,
1138 })
1139}
1140
1141fn make_stubs_module(missing: &[(&str, Export)]) -> Vec<u8> {
1143 let mut types = TypeSection::new();
1144 let mut exports = ExportSection::new();
1145 let mut functions = FunctionSection::new();
1146 let mut code = CodeSection::new();
1147 for (offset, (_, export)) in missing.iter().enumerate() {
1148 let offset = u32::try_from(offset).unwrap();
1149
1150 let Export {
1151 key:
1152 ExportKey {
1153 name,
1154 ty: Type::Function(ty),
1155 },
1156 ..
1157 } = export
1158 else {
1159 unreachable!();
1160 };
1161
1162 types.ty().function(
1163 ty.parameters.iter().copied().map(ValType::from),
1164 ty.results.iter().copied().map(ValType::from),
1165 );
1166 functions.function(offset);
1167 let mut function = Function::new([]);
1168 function.instruction(&Ins::Unreachable);
1169 function.instruction(&Ins::End);
1170 code.function(&function);
1171 exports.export(name, ExportKind::Func, offset);
1172 }
1173
1174 let mut module = Module::new();
1175
1176 module.section(&types);
1177 module.section(&functions);
1178 module.section(&exports);
1179 module.section(&code);
1180 module.section(&RawCustomSection(
1181 &crate::base_producers().raw_custom_section(),
1182 ));
1183
1184 let module = module.finish();
1185 wasmparser::validate(&module).unwrap();
1186
1187 module
1188}
1189
1190fn find_reachable<'a>(
1193 metadata: &'a [Metadata<'a>],
1194 dependencies: &IndexMap<usize, IndexSet<usize>>,
1195) -> IndexSet<&'a str> {
1196 let reachable = metadata
1197 .iter()
1198 .enumerate()
1199 .filter_map(|(index, metadata)| {
1200 if metadata.has_component_exports || metadata.dl_openable || metadata.has_wasi_start {
1201 Some(index)
1202 } else {
1203 None
1204 }
1205 })
1206 .collect_unique::<IndexSet<_>>();
1207
1208 let empty = &IndexSet::new();
1209
1210 reachable
1211 .iter()
1212 .chain(
1213 reachable
1214 .iter()
1215 .flat_map(|index| dependencies.get(index).unwrap_or(empty)),
1216 )
1217 .map(|&index| metadata[index].name)
1218 .collect()
1219}
1220
1221#[derive(Default)]
1223pub struct Linker {
1224 libraries: Vec<(String, Vec<u8>, bool)>,
1228
1229 adapters: Vec<(String, Vec<u8>)>,
1231
1232 validate: bool,
1234
1235 stub_missing_functions: bool,
1237
1238 use_built_in_libdl: bool,
1240
1241 stack_size: Option<u32>,
1245
1246 merge_imports_based_on_semver: Option<bool>,
1250}
1251
1252impl Linker {
1253 pub fn library(mut self, name: &str, module: &[u8], dl_openable: bool) -> Result<Self> {
1258 self.libraries
1259 .push((name.to_owned(), module.to_vec(), dl_openable));
1260
1261 Ok(self)
1262 }
1263
1264 pub fn adapter(mut self, name: &str, module: &[u8]) -> Result<Self> {
1268 self.adapters.push((name.to_owned(), module.to_vec()));
1269
1270 Ok(self)
1271 }
1272
1273 pub fn validate(mut self, validate: bool) -> Self {
1275 self.validate = validate;
1276 self
1277 }
1278
1279 pub fn stack_size(mut self, stack_size: u32) -> Self {
1281 self.stack_size = Some(stack_size);
1282 self
1283 }
1284
1285 pub fn stub_missing_functions(mut self, stub_missing_functions: bool) -> Self {
1287 self.stub_missing_functions = stub_missing_functions;
1288 self
1289 }
1290
1291 pub fn use_built_in_libdl(mut self, use_built_in_libdl: bool) -> Self {
1293 self.use_built_in_libdl = use_built_in_libdl;
1294 self
1295 }
1296
1297 pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
1303 self.merge_imports_based_on_semver = Some(merge);
1304 self
1305 }
1306
1307 pub fn encode(mut self) -> Result<Vec<u8>> {
1309 if self.use_built_in_libdl {
1310 self.use_built_in_libdl = false;
1311 self = self.library("libdl.so", include_bytes!("../libdl.so"), false)?;
1312 }
1313
1314 let adapter_names = self
1315 .adapters
1316 .iter()
1317 .map(|(name, _)| name.as_str())
1318 .collect_unique::<HashSet<_>>();
1319
1320 if adapter_names.len() != self.adapters.len() {
1321 bail!("duplicate adapter name");
1322 }
1323
1324 let metadata = self
1325 .libraries
1326 .iter()
1327 .map(|(name, module, dl_openable)| {
1328 Metadata::try_new(name, *dl_openable, module, &adapter_names)
1329 .with_context(|| format!("failed to extract linking metadata from {name}"))
1330 })
1331 .collect::<Result<Vec<_>>>()?;
1332
1333 {
1334 let names = self
1335 .libraries
1336 .iter()
1337 .map(|(name, ..)| name.as_str())
1338 .collect_unique::<HashSet<_>>();
1339
1340 let missing = metadata
1341 .iter()
1342 .filter_map(|metadata| {
1343 let missing = metadata
1344 .needed_libs
1345 .iter()
1346 .copied()
1347 .filter(|name| !names.contains(*name))
1348 .collect::<Vec<_>>();
1349
1350 if missing.is_empty() {
1351 None
1352 } else {
1353 Some((metadata.name, missing))
1354 }
1355 })
1356 .collect::<Vec<_>>();
1357
1358 if !missing.is_empty() {
1359 bail!(
1360 "missing libraries:\n{}",
1361 missing
1362 .iter()
1363 .map(|(needed_by, missing)| format!(
1364 "\t{needed_by} needs {}",
1365 missing.join(", ")
1366 ))
1367 .collect::<Vec<_>>()
1368 .join("\n")
1369 );
1370 }
1371 }
1372
1373 let exporters = resolve_exporters(&metadata)?;
1374
1375 let cabi_realloc_exporter = exporters
1376 .get(&ExportKey {
1377 name: "cabi_realloc",
1378 ty: Type::Function(FunctionType {
1379 parameters: vec![ValueType::I32; 4],
1380 results: vec![ValueType::I32],
1381 }),
1382 })
1383 .map(|exporters| exporters.first().unwrap().0);
1384
1385 let (exporters, missing, _) = resolve_symbols(&metadata, &exporters);
1386
1387 if !missing.is_empty() {
1388 if missing
1389 .iter()
1390 .all(|(_, export)| matches!(&export.key.ty, Type::Function(_)))
1391 && (self.stub_missing_functions
1392 || missing
1393 .iter()
1394 .all(|(_, export)| export.flags.contains(SymbolFlags::BINDING_WEAK)))
1395 {
1396 self.stub_missing_functions = false;
1397 self.libraries
1398 .push((STUB_LIBRARY_NAME.into(), make_stubs_module(&missing), false));
1399 return self.encode();
1400 } else {
1401 bail!(
1402 "unresolved symbol(s):\n{}",
1403 missing
1404 .iter()
1405 .filter(|(_, export)| !export.flags.contains(SymbolFlags::BINDING_WEAK))
1406 .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) })
1407 .collect::<Vec<_>>()
1408 .join("\n")
1409 );
1410 }
1411 }
1412
1413 let dependencies = find_dependencies(&metadata, &exporters)?;
1414
1415 {
1416 let reachable = find_reachable(&metadata, &dependencies);
1417 let unreachable = self
1418 .libraries
1419 .iter()
1420 .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone()))
1421 .collect_unique::<HashSet<_>>();
1422
1423 if !unreachable.is_empty() {
1424 self.libraries
1425 .retain(|(name, ..)| !unreachable.contains(name));
1426 return self.encode();
1427 }
1428 }
1429
1430 let topo_sorted = topo_sort(metadata.len(), &dependencies)?;
1431
1432 let EnvFunctionExports {
1433 exports: env_function_exports,
1434 reexport_cabi_realloc,
1435 } = env_function_exports(&metadata, &exporters, &topo_sorted)?;
1436
1437 let (env_module, dl_openables, table_base) = make_env_module(
1438 &metadata,
1439 &env_function_exports,
1440 if reexport_cabi_realloc {
1441 None
1444 } else {
1445 cabi_realloc_exporter
1446 },
1447 self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES),
1448 );
1449
1450 let mut encoder = ComponentEncoder::default().validate(self.validate);
1451 if let Some(merge) = self.merge_imports_based_on_semver {
1452 encoder = encoder.merge_imports_based_on_semver(merge);
1453 };
1454 encoder = encoder.module(&env_module)?;
1455
1456 for (name, module) in &self.adapters {
1457 encoder = encoder.adapter(name, module)?;
1458 }
1459
1460 let default_env_items = [
1461 Item {
1462 alias: "memory".into(),
1463 kind: ExportKind::Memory,
1464 which: MainOrAdapter::Main,
1465 name: "memory".into(),
1466 },
1467 Item {
1468 alias: "__indirect_function_table".into(),
1469 kind: ExportKind::Table,
1470 which: MainOrAdapter::Main,
1471 name: "__indirect_function_table".into(),
1472 },
1473 Item {
1474 alias: "__stack_pointer".into(),
1475 kind: ExportKind::Global,
1476 which: MainOrAdapter::Main,
1477 name: "__stack_pointer".into(),
1478 },
1479 ];
1480
1481 let mut seen = HashSet::new();
1482 for index in topo_sorted {
1483 let (name, module, _) = &self.libraries[index];
1484 let metadata = &metadata[index];
1485
1486 let env_items = default_env_items
1487 .iter()
1488 .cloned()
1489 .chain([
1490 Item {
1491 alias: "__memory_base".into(),
1492 kind: ExportKind::Global,
1493 which: MainOrAdapter::Main,
1494 name: format!("{name}:memory_base"),
1495 },
1496 Item {
1497 alias: "__table_base".into(),
1498 kind: ExportKind::Global,
1499 which: MainOrAdapter::Main,
1500 name: format!("{name}:table_base"),
1501 },
1502 ])
1503 .chain(metadata.env_imports.iter().map(|(name, (ty, _))| {
1504 let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap();
1505
1506 Item {
1507 alias: (*name).into(),
1508 kind: ExportKind::Func,
1509 which: if seen.contains(exporter) {
1510 MainOrAdapter::Adapter(exporter.to_owned())
1511 } else {
1512 MainOrAdapter::Main
1513 },
1514 name: (*name).into(),
1515 }
1516 }))
1517 .chain(if metadata.is_asyncified {
1518 vec![
1519 Item {
1520 alias: "__asyncify_state".into(),
1521 kind: ExportKind::Global,
1522 which: MainOrAdapter::Main,
1523 name: "__asyncify_state".into(),
1524 },
1525 Item {
1526 alias: "__asyncify_data".into(),
1527 kind: ExportKind::Global,
1528 which: MainOrAdapter::Main,
1529 name: "__asyncify_data".into(),
1530 },
1531 ]
1532 } else {
1533 vec![]
1534 })
1535 .collect();
1536
1537 let global_item = |address_name: &str| Item {
1538 alias: address_name.into(),
1539 kind: ExportKind::Global,
1540 which: MainOrAdapter::Main,
1541 name: format!("{name}:{address_name}"),
1542 };
1543
1544 let mem_items = metadata
1545 .memory_address_imports
1546 .iter()
1547 .copied()
1548 .map(global_item)
1549 .chain(["__heap_base", "__heap_end"].into_iter().map(|name| Item {
1550 alias: name.into(),
1551 kind: ExportKind::Global,
1552 which: MainOrAdapter::Main,
1553 name: name.into(),
1554 }))
1555 .collect();
1556
1557 let func_items = metadata
1558 .table_address_imports
1559 .iter()
1560 .copied()
1561 .map(global_item)
1562 .collect();
1563
1564 let mut import_items = BTreeMap::<_, Vec<_>>::new();
1565 for import in &metadata.imports {
1566 import_items.entry(import.module).or_default().push(Item {
1567 alias: import.name.into(),
1568 kind: ExportKind::from(&import.ty),
1569 which: MainOrAdapter::Main,
1570 name: format!("{}:{}", import.module, import.name),
1571 });
1572 }
1573
1574 encoder = encoder.library(
1575 name,
1576 module,
1577 LibraryInfo {
1578 instantiate_after_shims: false,
1579 arguments: [
1580 ("GOT.mem".into(), Instance::Items(mem_items)),
1581 ("GOT.func".into(), Instance::Items(func_items)),
1582 ("env".into(), Instance::Items(env_items)),
1583 ]
1584 .into_iter()
1585 .chain(
1586 import_items
1587 .into_iter()
1588 .map(|(k, v)| (k.into(), Instance::Items(v))),
1589 )
1590 .collect(),
1591 },
1592 )?;
1593
1594 seen.insert(name.as_str());
1595 }
1596
1597 encoder
1598 .library(
1599 "__init",
1600 &make_init_module(
1601 &metadata,
1602 &exporters,
1603 &env_function_exports,
1604 dl_openables,
1605 table_base,
1606 )?,
1607 LibraryInfo {
1608 instantiate_after_shims: true,
1609 arguments: iter::once((
1610 "env".into(),
1611 Instance::MainOrAdapter(MainOrAdapter::Main),
1612 ))
1613 .chain(self.libraries.iter().map(|(name, ..)| {
1614 (
1615 name.clone(),
1616 Instance::MainOrAdapter(MainOrAdapter::Adapter(name.clone())),
1617 )
1618 }))
1619 .collect(),
1620 },
1621 )?
1622 .encode()
1623 }
1624}