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