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