Skip to main content

wit_component/
linking.rs

1//! Support for "pseudo-dynamic", shared-everything linking of Wasm modules into a component.
2//!
3//! This implements [shared-everything
4//! linking](https://github.com/WebAssembly/component-model/blob/main/design/mvp/examples/SharedEverythingDynamicLinking.md),
5//! taking as input one or more [dynamic
6//! library](https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md) modules and producing a
7//! component whose type is the union of any `component-type*` custom sections found in the input modules.
8//!
9//! The entry point into this process is `Linker::encode`, which analyzes and topologically sorts the input
10//! modules, then synthesizes two additional modules:
11//!
12//! - `main` AKA `env`: hosts the component's single memory and function table and exports any functions needed to
13//! break dependency cycles discovered in the input modules. Those functions use `call.indirect` to invoke the real
14//! functions, references to which are placed in the table by the `init` module.
15//!
16//! - `init`: populates the function table as described above, initializes global variables per the dynamic linking
17//! tool convention, and calls any static constructors and/or link-time fixup functions
18//!
19//! `Linker` also supports synthesizing `dlopen`/`dlsym` lookup tables which allow symbols to be resolved at
20//! runtime.  Note that this is not true dynamic linking, since all the code is baked into the component ahead of
21//! time -- we simply allow runtime resolution of already-resident definitions.  This is sufficient to support
22//! dynamic language FFI features such as Python native extensions, provided the required libraries are linked
23//! ahead-of-time.
24
25use {
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;
48// This matches the default stack size LLVM produces:
49pub const DEFAULT_STACK_SIZE_BYTES: u32 = 16 * PAGE_SIZE_BYTES;
50const HEAP_ALIGNMENT_BYTES: u32 = 16;
51const STUB_LIBRARY_NAME: &str = "wit-component:stubs";
52const CABI_REALLOC: &str = "cabi_realloc";
53
54static EMPTY_FUNCTION_TYPE: FunctionType = FunctionType {
55    parameters: Vec::new(),
56    results: Vec::new(),
57};
58
59/// Symbols to re-export from the `env` module regardless of whether any
60/// libraries import them, since
61/// `EncodingState::create_export_task_initialization_wrappers` needs to be able
62/// to call them.
63static ENV_REEXPORTS: &[&str] = &[metadata::INIT_TASK, metadata::INIT_ASYNC_TASK];
64
65enum Address<'a> {
66    Function(u32),
67    Global(&'a str),
68}
69
70/// Represents a `dlopen`/`dlsym` lookup table enabling runtime symbol resolution
71///
72/// The top level of this table is a sorted list of library names and offsets, each pointing to a sorted list of
73/// symbol names and offsets.  See ../dl/src/lib.rs for how this is used at runtime.
74struct DlOpenables<'a> {
75    /// Offset into the main module's table where function references will be stored
76    table_base: u32,
77
78    /// Offset into the main module's memory where the lookup table will be stored
79    memory_base: u32,
80
81    /// The lookup table itself
82    buffer: Vec<u8>,
83
84    /// Linear memory addresses where global variable addresses will live
85    ///
86    /// The init module will fill in the correct values at instantiation time.
87    global_addresses: Vec<(&'a str, &'a str, u32)>,
88
89    /// Number of function references to be stored in the main module's table
90    function_count: u32,
91
92    /// Linear memory address where the root of the lookup table will reside
93    ///
94    /// This can be different from `memory_base` depending on how the tree of libraries and symbols is laid out in
95    /// memory.
96    libraries_address: u32,
97}
98
99impl<'a> DlOpenables<'a> {
100    /// Construct a lookup table containing all "dlopen-able" libraries and their symbols using the specified table
101    /// and memory offsets.
102    fn new(table_base: u32, memory_base: u32, metadata: &'a [Metadata<'a>]) -> Self {
103        let mut function_count = 0;
104        let mut buffer = Vec::new();
105        let mut global_addresses = Vec::new();
106        let mut libraries = metadata
107            .iter()
108            .filter(|metadata| metadata.dl_openable)
109            .map(|metadata| {
110                let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
111                write_bytes_padded(&mut buffer, metadata.name.as_bytes());
112
113                let mut symbols = metadata
114                    .exports
115                    .iter()
116                    .filter_map(|export| {
117                        let name_address = memory_base + u32::try_from(buffer.len()).unwrap();
118                        write_bytes_padded(&mut buffer, export.key.name.as_bytes());
119
120                        let address = match &export.key.ty {
121                            Type::Function(_) => Address::Function(
122                                table_base + get_and_increment(&mut function_count),
123                            ),
124                            Type::Global(_) => Address::Global(export.key.name),
125                            Type::Tag(_) => return None,
126                        };
127
128                        Some((export.key.name, name_address, address))
129                    })
130                    .collect::<Vec<_>>();
131
132                symbols.sort_by_key(|(name, ..)| *name);
133
134                let start = buffer.len();
135                for (name, name_address, address) in symbols {
136                    write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
137                    write_u32(&mut buffer, name_address);
138                    match address {
139                        Address::Function(address) => write_u32(&mut buffer, address),
140                        Address::Global(name) => {
141                            global_addresses.push((
142                                metadata.name,
143                                name,
144                                memory_base + u32::try_from(buffer.len()).unwrap(),
145                            ));
146
147                            write_u32(&mut buffer, 0);
148                        }
149                    }
150                }
151
152                (
153                    metadata.name,
154                    name_address,
155                    metadata.exports.len(),
156                    memory_base + u32::try_from(start).unwrap(),
157                )
158            })
159            .collect::<Vec<_>>();
160
161        libraries.sort_by_key(|(name, ..)| *name);
162
163        let start = buffer.len();
164        for (name, name_address, count, symbols) in &libraries {
165            write_u32(&mut buffer, u32::try_from(name.len()).unwrap());
166            write_u32(&mut buffer, *name_address);
167            write_u32(&mut buffer, u32::try_from(*count).unwrap());
168            write_u32(&mut buffer, *symbols);
169        }
170
171        let libraries_address = memory_base + u32::try_from(buffer.len()).unwrap();
172        write_u32(&mut buffer, u32::try_from(libraries.len()).unwrap());
173        write_u32(&mut buffer, memory_base + u32::try_from(start).unwrap());
174
175        Self {
176            table_base,
177            memory_base,
178            buffer,
179            global_addresses,
180            function_count,
181            libraries_address,
182        }
183    }
184}
185
186fn write_u32(buffer: &mut Vec<u8>, value: u32) {
187    buffer.extend(value.to_le_bytes());
188}
189
190fn write_bytes_padded(buffer: &mut Vec<u8>, bytes: &[u8]) {
191    buffer.extend(bytes);
192
193    let len = u32::try_from(bytes.len()).unwrap();
194    for _ in len..align(len, 4) {
195        buffer.push(0);
196    }
197}
198
199fn align(a: u32, b: u32) -> u32 {
200    assert!(b.is_power_of_two());
201    (a + (b - 1)) & !(b - 1)
202}
203
204fn get_and_increment(n: &mut u32) -> u32 {
205    let v = *n;
206    *n += 1;
207    v
208}
209
210fn const_u32(a: u32) -> ConstExpr {
211    ConstExpr::i32_const(a as i32)
212}
213
214/// Helper trait for determining the size of a set or map
215trait Length {
216    fn len(&self) -> usize;
217}
218
219impl<T> Length for HashSet<T> {
220    fn len(&self) -> usize {
221        HashSet::len(self)
222    }
223}
224
225impl<K, V> Length for HashMap<K, V> {
226    fn len(&self) -> usize {
227        HashMap::len(self)
228    }
229}
230
231impl<T> Length for IndexSet<T> {
232    fn len(&self) -> usize {
233        IndexSet::len(self)
234    }
235}
236
237impl<K, V> Length for IndexMap<K, V> {
238    fn len(&self) -> usize {
239        IndexMap::len(self)
240    }
241}
242
243/// Extension trait for collecting into a set or map and asserting that there were no duplicate entries in the
244/// source iterator.
245trait CollectUnique: Iterator + Sized {
246    fn collect_unique<T: FromIterator<Self::Item> + Length>(self) -> T {
247        let tmp = self.collect::<Vec<_>>();
248        let len = tmp.len();
249        let result = tmp.into_iter().collect::<T>();
250        assert!(
251            result.len() == len,
252            "one or more duplicate items detected when collecting into set or map"
253        );
254        result
255    }
256}
257
258impl<T: Iterator> CollectUnique for T {}
259
260/// Extension trait for inserting into a map and asserting that an entry did not already exist for the key
261trait InsertUnique {
262    type Key;
263    type Value;
264
265    fn insert_unique(&mut self, k: Self::Key, v: Self::Value);
266}
267
268impl<K: Hash + Eq + PartialEq + Debug, V: Debug> InsertUnique for HashMap<K, V> {
269    type Key = K;
270    type Value = V;
271
272    fn insert_unique(&mut self, k: Self::Key, v: Self::Value) {
273        if let Some(old_v) = self.get(&k) {
274            panic!(
275                "duplicate item inserted into map for key {k:?} (old value: {old_v:?}; new value: {v:?})"
276            );
277        }
278        self.insert(k, v);
279    }
280}
281
282/// Synthesize the "main" module for the component, responsible for exporting functions which break cyclic
283/// dependencies, as well as hosting the memory and function table.
284fn make_env_module<'a>(
285    metadata: &'a [Metadata<'a>],
286    env_exports: &[EnvExport<'_>],
287    cabi_realloc_exporter: Option<&str>,
288    stack_size_bytes: u32,
289) -> (Vec<u8>, DlOpenables<'a>, u32) {
290    // TODO: deduplicate types
291    let mut types = TypeSection::new();
292    let mut imports = ImportSection::new();
293    let mut import_map = IndexMap::new();
294    let mut function_count = 0;
295    let mut global_offset = 0;
296    let mut wasi_start = None;
297
298    for metadata in metadata {
299        for import in &metadata.imports {
300            if let Entry::Vacant(entry) = import_map.entry(import) {
301                imports.import(
302                    import.module,
303                    import.name,
304                    match &import.ty {
305                        Type::Function(ty) => {
306                            let index = get_and_increment(&mut function_count);
307                            entry.insert(index);
308                            types.ty().function(
309                                ty.parameters.iter().copied().map(ValType::from),
310                                ty.results.iter().copied().map(ValType::from),
311                            );
312                            EntityType::Function(index)
313                        }
314                        Type::Global(ty) => {
315                            entry.insert(get_and_increment(&mut global_offset));
316                            EntityType::Global(wasm_encoder::GlobalType {
317                                val_type: ty.ty.into(),
318                                mutable: ty.mutable,
319                                shared: ty.shared,
320                            })
321                        }
322                        Type::Tag(_) => continue,
323                    },
324                );
325            }
326        }
327
328        if metadata.has_wasi_start {
329            if wasi_start.is_some() {
330                panic!("multiple libraries export {}", metadata::START);
331            }
332            let index = get_and_increment(&mut function_count);
333
334            types.ty().function(vec![], vec![]);
335            imports.import(metadata.name, metadata::START, EntityType::Function(index));
336
337            wasi_start = Some(index);
338        }
339    }
340
341    let mut memory_offset = stack_size_bytes;
342
343    // Table offset 0 is reserved for the null function pointer.
344    // This convention follows wasm-ld's table layout:
345    // https://github.com/llvm/llvm-project/blob/913622d012f72edb5ac3a501cef8639d0ebe471b/lld/wasm/Driver.cpp#L581-L584
346    let mut table_offset = 1;
347    let mut globals = GlobalSection::new();
348    let mut exports = ExportSection::new();
349
350    if let Some(exporter) = cabi_realloc_exporter {
351        let index = get_and_increment(&mut function_count);
352        types.ty().function([ValType::I32; 4], [ValType::I32]);
353        imports.import(exporter, CABI_REALLOC, EntityType::Function(index));
354        exports.export(CABI_REALLOC, ExportKind::Func, index);
355    }
356
357    let dl_openables = DlOpenables::new(table_offset, memory_offset, metadata);
358
359    table_offset += dl_openables.function_count;
360    memory_offset += u32::try_from(dl_openables.buffer.len()).unwrap();
361
362    let memory_size = {
363        let mut add_global_export = |name: &str, value, mutable| {
364            let index = globals.len();
365            globals.global(
366                wasm_encoder::GlobalType {
367                    val_type: ValType::I32,
368                    mutable,
369                    shared: false,
370                },
371                &const_u32(value),
372            );
373            exports.export(name, ExportKind::Global, index);
374        };
375
376        if metadata.iter().any(|m| m.needs_stack_pointer) {
377            add_global_export(metadata::STACK_POINTER, stack_size_bytes, true);
378        }
379        if metadata.iter().any(|m| m.needs_init_stack_pointer) {
380            add_global_export(metadata::INIT_STACK_POINTER, stack_size_bytes, false);
381        }
382
383        // Binaryen's Asyncify transform for shared everything linking requires these globals
384        // to be provided from env module
385        let has_asyncified_module = metadata.iter().any(|m| m.is_asyncified);
386        if has_asyncified_module {
387            add_global_export(metadata::ASYNCIFY_STATE, 0, true);
388            add_global_export(metadata::ASYNCIFY_DATA, 0, true);
389        }
390
391        // The libc.so in WASI-SDK 28+ requires these:
392        if metadata.iter().any(|m| m.needs_stack_high) {
393            add_global_export(metadata::STACK_HIGH, stack_size_bytes, true);
394        }
395        if metadata.iter().any(|m| m.needs_stack_low) {
396            add_global_export(metadata::STACK_LOW, 0, true);
397        }
398
399        for metadata in metadata {
400            memory_offset = align(memory_offset, 1 << metadata.mem_info.memory_alignment);
401            table_offset = align(table_offset, 1 << metadata.mem_info.table_alignment);
402
403            add_global_export(
404                &format!("{}:memory_base", metadata.name),
405                memory_offset,
406                false,
407            );
408            add_global_export(
409                &format!("{}:table_base", metadata.name),
410                table_offset,
411                false,
412            );
413
414            memory_offset += metadata.mem_info.memory_size;
415            table_offset += metadata.mem_info.table_size;
416
417            for import in &metadata.memory_address_imports {
418                // Note that we initialize this to zero and let the init module compute the real value at
419                // instantiation time.
420                add_global_export(&format!("{}:{import}", metadata.name), 0, true);
421            }
422        }
423
424        {
425            let offsets = env_exports
426                .iter()
427                .enumerate()
428                .map(|(offset, EnvExport { name, exporter, .. })| {
429                    (
430                        *name,
431                        (
432                            table_offset + u32::try_from(offset).unwrap(),
433                            metadata[*exporter].name == STUB_LIBRARY_NAME,
434                        ),
435                    )
436                })
437                .collect_unique::<HashMap<_, _>>();
438
439            for metadata in metadata {
440                for import in &metadata.table_address_imports {
441                    let &(offset, is_stub) = offsets.get(import).unwrap();
442                    if is_stub
443                        && metadata
444                            .env_imports
445                            .iter()
446                            .any(|e| e.0 == *import && e.1.1.contains(SymbolFlags::BINDING_WEAK))
447                    {
448                        add_global_export(&format!("{}:{import}", metadata.name), 0, true);
449                    } else {
450                        add_global_export(&format!("{}:{import}", metadata.name), offset, true);
451                    }
452                }
453            }
454        }
455
456        memory_offset = align(memory_offset, HEAP_ALIGNMENT_BYTES);
457        if metadata.iter().any(|m| m.needs_heap_base) {
458            add_global_export(metadata::HEAP_BASE, memory_offset, true);
459        }
460
461        let heap_end = align(memory_offset, PAGE_SIZE_BYTES);
462        if metadata.iter().any(|m| m.needs_heap_end) {
463            add_global_export(metadata::HEAP_END, heap_end, true);
464        }
465        heap_end / PAGE_SIZE_BYTES
466    };
467
468    let indirection_table_base = table_offset;
469
470    let mut functions = FunctionSection::new();
471    let mut code = CodeSection::new();
472    for export in env_exports {
473        let index = get_and_increment(&mut function_count);
474        types.ty().function(
475            export.ty.parameters.iter().copied().map(ValType::from),
476            export.ty.results.iter().copied().map(ValType::from),
477        );
478        functions.function(u32::try_from(index).unwrap());
479        let mut function = Function::new([]);
480        for local in 0..export.ty.parameters.len() {
481            function.instruction(&Ins::LocalGet(u32::try_from(local).unwrap()));
482        }
483        function.instruction(&Ins::I32Const(i32::try_from(table_offset).unwrap()));
484        function.instruction(&Ins::CallIndirect {
485            type_index: u32::try_from(index).unwrap(),
486            table_index: 0,
487        });
488        function.instruction(&Ins::End);
489        code.function(&function);
490        exports.export(export.name, ExportKind::Func, index);
491
492        table_offset += 1;
493    }
494
495    for (import, offset) in import_map {
496        exports.export(
497            &format!("{}:{}", import.module, import.name),
498            ExportKind::from(&import.ty),
499            offset,
500        );
501    }
502    if let Some(index) = wasi_start {
503        exports.export(metadata::START, ExportKind::Func, index);
504    }
505
506    let mut module = Module::new();
507
508    module.section(&types);
509    module.section(&imports);
510    module.section(&functions);
511
512    {
513        let mut tables = TableSection::new();
514        tables.table(TableType {
515            element_type: RefType::FUNCREF,
516            minimum: table_offset.into(),
517            maximum: None,
518            table64: false,
519            shared: false,
520        });
521        exports.export(metadata::INDIRECT_FUNCTION_TABLE, ExportKind::Table, 0);
522        module.section(&tables);
523    }
524
525    {
526        let mut memories = MemorySection::new();
527        memories.memory(MemoryType {
528            minimum: u64::from(memory_size),
529            maximum: None,
530            memory64: false,
531            shared: false,
532            page_size_log2: None,
533        });
534        exports.export(metadata::MEMORY, ExportKind::Memory, 0);
535        module.section(&memories);
536    }
537
538    module.section(&globals);
539    module.section(&exports);
540    module.section(&code);
541    module.section(&RawCustomSection(
542        &crate::base_producers().raw_custom_section(),
543    ));
544
545    let module = module.finish();
546    wasmparser::validate(&module).unwrap();
547
548    (module, dl_openables, indirection_table_base)
549}
550
551/// Synthesize the "init" module, responsible for initializing global variables per the dynamic linking tool
552/// convention and calling any static constructors and/or link-time fixup functions.
553///
554/// This module also contains the data segment for the `dlopen`/`dlsym` lookup table.
555fn make_init_module(
556    metadata: &[Metadata],
557    exporters: &IndexMap<&ExportKey, (&str, &Export)>,
558    env_exports: &[EnvExport<'_>],
559    dl_openables: DlOpenables,
560    indirection_table_base: u32,
561) -> Result<Vec<u8>> {
562    let mut module = Module::new();
563
564    // TODO: deduplicate types
565    let mut types = TypeSection::new();
566    types.ty().function([], []);
567    let thunk_ty = 0;
568    types.ty().function([ValType::I32], []);
569    let one_i32_param_ty = 1;
570    let mut type_offset = 2;
571
572    for metadata in metadata {
573        if metadata.dl_openable {
574            for export in &metadata.exports {
575                if let Type::Function(ty) = &export.key.ty {
576                    types.ty().function(
577                        ty.parameters.iter().copied().map(ValType::from),
578                        ty.results.iter().copied().map(ValType::from),
579                    );
580                }
581            }
582        }
583    }
584    for export in env_exports {
585        types.ty().function(
586            export.ty.parameters.iter().copied().map(ValType::from),
587            export.ty.results.iter().copied().map(ValType::from),
588        );
589    }
590    module.section(&types);
591
592    let mut imports = ImportSection::new();
593    imports.import(
594        metadata::ENV,
595        metadata::MEMORY,
596        MemoryType {
597            minimum: 0,
598            maximum: None,
599            memory64: false,
600            shared: false,
601            page_size_log2: None,
602        },
603    );
604    imports.import(
605        metadata::ENV,
606        metadata::INDIRECT_FUNCTION_TABLE,
607        TableType {
608            element_type: RefType::FUNCREF,
609            minimum: 0,
610            maximum: None,
611            table64: false,
612            shared: false,
613        },
614    );
615
616    let mut global_count = 0;
617    let mut global_map = HashMap::new();
618    let mut add_global_import = |imports: &mut ImportSection, module: &str, name: &str, mutable| {
619        *global_map
620            .entry((module.to_owned(), name.to_owned()))
621            .or_insert_with(|| {
622                imports.import(
623                    module,
624                    name,
625                    wasm_encoder::GlobalType {
626                        val_type: ValType::I32,
627                        mutable,
628                        shared: false,
629                    },
630                );
631                get_and_increment(&mut global_count)
632            })
633    };
634
635    let mut function_count = 0;
636    let mut function_map = HashMap::new();
637    let mut add_function_import = |imports: &mut ImportSection, module: &str, name: &str, ty| {
638        *function_map
639            .entry((module.to_owned(), name.to_owned()))
640            .or_insert_with(|| {
641                imports.import(module, name, EntityType::Function(ty));
642                get_and_increment(&mut function_count)
643            })
644    };
645
646    let mut memory_address_inits = Vec::new();
647    let mut reloc_calls = Vec::new();
648    let mut ctor_calls = Vec::new();
649    let mut names = HashMap::new();
650
651    for (exporter, export, address) in dl_openables.global_addresses.iter() {
652        memory_address_inits.push(Ins::I32Const(i32::try_from(*address).unwrap()));
653        memory_address_inits.push(Ins::GlobalGet(add_global_import(
654            &mut imports,
655            metadata::ENV,
656            &format!("{exporter}:memory_base"),
657            false,
658        )));
659        memory_address_inits.push(Ins::GlobalGet(add_global_import(
660            &mut imports,
661            exporter,
662            export,
663            false,
664        )));
665        memory_address_inits.push(Ins::I32Add);
666        memory_address_inits.push(Ins::I32Store(MemArg {
667            offset: 0,
668            align: 2,
669            memory_index: 0,
670        }));
671    }
672
673    let mut init_task_exporter = exporters
674        .get(&ExportKey {
675            name: metadata::INIT_TASK,
676            ty: Type::Function(EMPTY_FUNCTION_TYPE.clone()),
677        })
678        .map(|(name, _)| name);
679
680    for (index, metadata) in metadata.iter().enumerate() {
681        names.insert_unique(index, metadata.name);
682
683        if metadata.has_data_relocs {
684            reloc_calls.push(Ins::Call(add_function_import(
685                &mut imports,
686                metadata.name,
687                metadata::APPLY_DATA_RELOCS,
688                thunk_ty,
689            )));
690        }
691
692        if metadata.has_ctors && metadata.has_initialize {
693            bail!(
694                "library {} exports both `{}` and `{}`; \
695                 expected at most one of the two",
696                metadata.name,
697                metadata::CALL_CTORS,
698                metadata::INITIALIZE
699            );
700        }
701
702        // Before calling either `__wasm_call_ctors` or `_initialize`, we need
703        // to call `__wasm_init_task` if present to set up the shadow stack when
704        // using the cooperative multithreading ABI.
705        if let (Some(exporter), true) = (
706            init_task_exporter,
707            metadata.has_ctors || metadata.has_initialize,
708        ) {
709            // We only need to call it at most once, so we set
710            // `init_task_exporter` to `None` to avoid calling it again:
711            init_task_exporter = None;
712
713            ctor_calls.push(Ins::Call(add_function_import(
714                &mut imports,
715                exporter,
716                metadata::INIT_TASK,
717                thunk_ty,
718            )));
719        }
720
721        if metadata.has_ctors {
722            ctor_calls.push(Ins::Call(add_function_import(
723                &mut imports,
724                metadata.name,
725                metadata::CALL_CTORS,
726                thunk_ty,
727            )));
728        }
729
730        if metadata.has_initialize {
731            ctor_calls.push(Ins::Call(add_function_import(
732                &mut imports,
733                metadata.name,
734                metadata::INITIALIZE,
735                thunk_ty,
736            )));
737        }
738
739        if metadata.has_set_libraries {
740            ctor_calls.push(Ins::I32Const(
741                i32::try_from(dl_openables.libraries_address).unwrap(),
742            ));
743            ctor_calls.push(Ins::Call(add_function_import(
744                &mut imports,
745                metadata.name,
746                metadata::SET_LIBRARIES,
747                one_i32_param_ty,
748            )));
749        }
750
751        for import in &metadata.memory_address_imports {
752            let (exporter, _) = find_offset_exporter(import, exporters)?;
753
754            memory_address_inits.push(Ins::GlobalGet(add_global_import(
755                &mut imports,
756                metadata::ENV,
757                &format!("{exporter}:memory_base"),
758                false,
759            )));
760            memory_address_inits.push(Ins::GlobalGet(add_global_import(
761                &mut imports,
762                exporter,
763                import,
764                false,
765            )));
766            memory_address_inits.push(Ins::I32Add);
767            memory_address_inits.push(Ins::GlobalSet(add_global_import(
768                &mut imports,
769                metadata::ENV,
770                &format!("{}:{import}", metadata.name),
771                true,
772            )));
773        }
774    }
775
776    let mut dl_openable_functions = Vec::new();
777    for metadata in metadata {
778        if metadata.dl_openable {
779            for export in &metadata.exports {
780                if let Type::Function(_) = &export.key.ty {
781                    dl_openable_functions.push(add_function_import(
782                        &mut imports,
783                        metadata.name,
784                        export.key.name,
785                        get_and_increment(&mut type_offset),
786                    ));
787                }
788            }
789        }
790    }
791
792    let indirections = env_exports
793        .iter()
794        .map(|EnvExport { name, exporter, .. }| {
795            add_function_import(
796                &mut imports,
797                names[exporter],
798                name,
799                get_and_increment(&mut type_offset),
800            )
801        })
802        .collect::<Vec<_>>();
803
804    module.section(&imports);
805
806    {
807        let mut functions = FunctionSection::new();
808        functions.function(thunk_ty);
809        module.section(&functions);
810    }
811
812    module.section(&StartSection {
813        function_index: function_count,
814    });
815
816    {
817        let mut elements = ElementSection::new();
818        elements.active(
819            None,
820            &const_u32(dl_openables.table_base),
821            Elements::Functions(dl_openable_functions.into()),
822        );
823        elements.active(
824            None,
825            &const_u32(indirection_table_base),
826            Elements::Functions(indirections.into()),
827        );
828        module.section(&elements);
829    }
830
831    {
832        let mut code = CodeSection::new();
833        let mut function = Function::new([]);
834        for ins in memory_address_inits
835            .iter()
836            .chain(&reloc_calls)
837            .chain(&ctor_calls)
838        {
839            function.instruction(ins);
840        }
841        function.instruction(&Ins::End);
842        code.function(&function);
843        module.section(&code);
844    }
845
846    let mut data = DataSection::new();
847    data.active(0, &const_u32(dl_openables.memory_base), dl_openables.buffer);
848    module.section(&data);
849
850    module.section(&RawCustomSection(
851        &crate::base_producers().raw_custom_section(),
852    ));
853
854    let module = module.finish();
855    wasmparser::validate(&module)?;
856
857    Ok(module)
858}
859
860/// Find the library which exports the specified function or global address.
861fn find_offset_exporter<'a>(
862    name: &str,
863    exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
864) -> Result<(&'a str, &'a Export<'a>)> {
865    let export = ExportKey {
866        name,
867        ty: Type::Global(GlobalType {
868            ty: ValueType::I32,
869            mutable: false,
870            shared: false,
871        }),
872    };
873
874    exporters
875        .get(&export)
876        .copied()
877        .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
878}
879
880/// Find the library which exports the specified function.
881fn find_function_exporter<'a>(
882    name: &str,
883    ty: &FunctionType,
884    exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
885) -> Result<(&'a str, &'a Export<'a>)> {
886    let export = ExportKey {
887        name,
888        ty: Type::Function(ty.clone()),
889    };
890
891    exporters
892        .get(&export)
893        .copied()
894        .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
895}
896
897/// Find the library which exports the specified tag.
898fn find_tag_exporter<'a>(
899    name: &str,
900    ty: &FunctionType,
901    exporters: &IndexMap<&ExportKey, (&'a str, &'a Export<'a>)>,
902) -> Result<(&'a str, &'a Export<'a>)> {
903    let export = ExportKey {
904        name,
905        ty: Type::Tag(ty.clone()),
906    };
907
908    exporters
909        .get(&export)
910        .copied()
911        .ok_or_else(|| anyhow!("unable to find {export:?} in any library"))
912}
913
914/// Analyze the specified library metadata, producing a symbol-to-library-name map of exports.
915fn resolve_exporters<'a>(
916    metadata: &'a [Metadata<'a>],
917) -> Result<IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>> {
918    let mut exporters = IndexMap::<_, Vec<_>>::new();
919    for metadata in metadata {
920        for export in &metadata.exports {
921            exporters
922                .entry(&export.key)
923                .or_default()
924                .push((metadata.name, export));
925        }
926    }
927    Ok(exporters)
928}
929
930/// Match up all imported symbols to their corresponding exports, reporting any missing or duplicate symbols.
931fn resolve_symbols<'a>(
932    metadata: &'a [Metadata<'a>],
933    exporters: &'a IndexMap<&'a ExportKey<'a>, Vec<(&'a str, &'a Export<'a>)>>,
934) -> (
935    IndexMap<&'a ExportKey<'a>, (&'a str, &'a Export<'a>)>,
936    Vec<(&'a str, Export<'a>)>,
937    Vec<(&'a str, &'a ExportKey<'a>, &'a [(&'a str, &'a Export<'a>)])>,
938) {
939    let function_exporters = exporters
940        .iter()
941        .filter_map(|(export, exporters)| match &export.ty {
942            Type::Function(_) => Some((export.name, (export, exporters))),
943            Type::Global(_) | Type::Tag(_) => None,
944        })
945        .collect_unique::<IndexMap<_, _>>();
946
947    let mut resolved = IndexMap::new();
948    let mut missing = Vec::new();
949    let mut duplicates = Vec::new();
950
951    let mut triage = |metadata: &'a Metadata, export: Export<'a>| {
952        if let Some((key, value)) = exporters.get_key_value(&export.key) {
953            // Note that we do not use `insert_unique` here since multiple libraries may import the same
954            // symbol, in which case we may redundantly insert the same value.
955            match value.as_slice() {
956                [] => unreachable!(),
957                [exporter] => {
958                    resolved.insert(*key, *exporter);
959                }
960                [exporter, ..] => {
961                    resolved.insert(*key, *exporter);
962                    duplicates.push((metadata.name, *key, value.as_slice()));
963                }
964            }
965        } else {
966            missing.push((metadata.name, export));
967        }
968    };
969
970    for metadata in metadata {
971        for (name, (ty, flags)) in &metadata.env_imports {
972            triage(
973                metadata,
974                Export {
975                    key: ExportKey {
976                        name,
977                        ty: Type::Function(ty.clone()),
978                    },
979                    flags: *flags,
980                },
981            );
982        }
983
984        for name in &metadata.memory_address_imports {
985            triage(
986                metadata,
987                Export {
988                    key: ExportKey {
989                        name,
990                        ty: Type::Global(GlobalType {
991                            ty: ValueType::I32,
992                            mutable: false,
993                            shared: false,
994                        }),
995                    },
996                    flags: SymbolFlags::empty(),
997                },
998            );
999        }
1000
1001        for (name, ty) in &metadata.tag_imports {
1002            triage(
1003                metadata,
1004                Export {
1005                    key: ExportKey {
1006                        name,
1007                        ty: Type::Tag(ty.clone()),
1008                    },
1009                    flags: SymbolFlags::empty(),
1010                },
1011            );
1012        }
1013    }
1014
1015    for metadata in metadata {
1016        for name in &metadata.table_address_imports {
1017            if let Some((key, value)) = function_exporters.get(name) {
1018                // Note that we do not use `insert_unique` here since multiple libraries may import the same
1019                // symbol, in which case we may redundantly insert the same value.
1020                match value.as_slice() {
1021                    [] => unreachable!(),
1022                    [exporter] => {
1023                        resolved.insert(key, *exporter);
1024                    }
1025                    [exporter, ..] => {
1026                        resolved.insert(key, *exporter);
1027                        duplicates.push((metadata.name, *key, value.as_slice()));
1028                    }
1029                }
1030            } else if metadata.env_imports.iter().any(|(n, _)| n == name) {
1031                // GOT entry for a function which is imported from the env module, but not exported by any library,
1032                // already handled above.
1033            } else {
1034                missing.push((
1035                    metadata.name,
1036                    Export {
1037                        key: ExportKey {
1038                            name,
1039                            ty: Type::Function(FunctionType {
1040                                parameters: Vec::new(),
1041                                results: Vec::new(),
1042                            }),
1043                        },
1044                        flags: SymbolFlags::empty(),
1045                    },
1046                ));
1047            }
1048        }
1049    }
1050
1051    // Even if no library imports these symbols, we re-export them from the
1052    // `env` module so that
1053    // `EncodingState::create_export_task_initialization_wrappers` can find
1054    // and use them:
1055    for &name in ENV_REEXPORTS {
1056        let export = Export {
1057            key: ExportKey {
1058                name,
1059                ty: Type::Function(EMPTY_FUNCTION_TYPE.clone()),
1060            },
1061            flags: SymbolFlags::empty(),
1062        };
1063
1064        if let Some((key, value)) = exporters.get_key_value(&export.key) {
1065            // Note that we do not use `insert_unique` here since multiple
1066            // libraries may import the same symbol, in which case we may
1067            // redundantly insert the same value.
1068            match value.as_slice() {
1069                [] => unreachable!(),
1070                [exporter] | [exporter, ..] => {
1071                    resolved.insert(*key, *exporter);
1072                }
1073            }
1074        }
1075    }
1076
1077    (resolved, missing, duplicates)
1078}
1079
1080/// Recursively add a library (represented by its offset) and its dependency to the specified set, maintaining
1081/// topological order (modulo cycles).
1082fn topo_add(
1083    sorted: &mut IndexSet<usize>,
1084    dependencies: &IndexMap<usize, IndexSet<usize>>,
1085    element: usize,
1086) {
1087    let empty = &IndexSet::new();
1088    let deps = dependencies.get(&element).unwrap_or(empty);
1089
1090    // First, add any dependencies which do not depend on `element`
1091    for &dep in deps {
1092        if !(sorted.contains(&dep) || dependencies.get(&dep).unwrap_or(empty).contains(&element)) {
1093            topo_add(sorted, dependencies, dep);
1094        }
1095    }
1096
1097    // Next, add the element
1098    sorted.insert(element);
1099
1100    // Finally, add any dependencies which depend on `element`
1101    for &dep in deps {
1102        if !sorted.contains(&dep) && dependencies.get(&dep).unwrap_or(empty).contains(&element) {
1103            topo_add(sorted, dependencies, dep);
1104        }
1105    }
1106}
1107
1108/// Topologically sort a set of libraries (represented by their offsets) according to their dependencies, modulo
1109/// cycles.
1110fn topo_sort(count: usize, dependencies: &IndexMap<usize, IndexSet<usize>>) -> Result<Vec<usize>> {
1111    let mut sorted = IndexSet::new();
1112    for index in 0..count {
1113        topo_add(&mut sorted, &dependencies, index);
1114    }
1115
1116    Ok(sorted.into_iter().collect())
1117}
1118
1119/// Analyze the specified library metadata, producing a map of transitive dependencies, where each library is
1120/// represented by its offset in the original metadata slice.
1121fn find_dependencies(
1122    metadata: &[Metadata],
1123    exporters: &IndexMap<&ExportKey, (&str, &Export)>,
1124) -> Result<IndexMap<usize, IndexSet<usize>>> {
1125    // First, generate a map of direct dependencies (i.e. depender to dependees)
1126    let mut dependencies = IndexMap::<_, IndexSet<_>>::new();
1127    let mut indexes = HashMap::new();
1128    for (index, metadata) in metadata.iter().enumerate() {
1129        indexes.insert_unique(metadata.name, index);
1130        for &needed in &metadata.needed_libs {
1131            dependencies
1132                .entry(metadata.name)
1133                .or_default()
1134                .insert(needed);
1135        }
1136        for (import_name, (ty, _)) in &metadata.env_imports {
1137            dependencies
1138                .entry(metadata.name)
1139                .or_default()
1140                .insert(find_function_exporter(import_name, ty, exporters)?.0);
1141        }
1142    }
1143
1144    // Next, convert the map from names to offsets
1145    let mut dependencies = dependencies
1146        .into_iter()
1147        .map(|(k, v)| {
1148            (
1149                indexes[k],
1150                v.into_iter()
1151                    .map(|v| indexes[v])
1152                    .collect_unique::<IndexSet<_>>(),
1153            )
1154        })
1155        .collect_unique::<IndexMap<_, _>>();
1156
1157    // Finally, add all transitive dependencies to the map in a fixpoint loop, exiting when no new dependencies are
1158    // discovered.
1159    let empty = &IndexSet::new();
1160
1161    loop {
1162        let mut new = IndexMap::<_, IndexSet<_>>::new();
1163        for (index, exporters) in &dependencies {
1164            for exporter in exporters {
1165                for exporter in dependencies.get(exporter).unwrap_or(empty) {
1166                    if !exporters.contains(exporter) {
1167                        new.entry(*index).or_default().insert(*exporter);
1168                    }
1169                }
1170            }
1171        }
1172
1173        if new.is_empty() {
1174            break Ok(dependencies);
1175        } else {
1176            for (index, exporters) in new {
1177                dependencies.entry(index).or_default().extend(exporters);
1178            }
1179        }
1180    }
1181}
1182
1183struct EnvExports<'a> {
1184    exports: Vec<EnvExport<'a>>,
1185    reexport_cabi_realloc: bool,
1186}
1187
1188struct EnvExport<'a> {
1189    name: &'a str,
1190    ty: &'a FunctionType,
1191    exporter: usize,
1192}
1193
1194/// Analyze the specified metadata and generate what needs to be exported from
1195/// the main (aka "env") module.
1196///
1197/// This includes a list of functions which should be re-exported as a
1198/// `call.indirect`-based function including the offset of the library
1199/// containing the original export.
1200///
1201/// Additionally this includes any tags necessary that are shared amongst
1202/// modules.
1203fn env_exports<'a>(
1204    metadata: &'a [Metadata<'a>],
1205    exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>,
1206    topo_sorted: &[usize],
1207) -> Result<EnvExports<'a>> {
1208    let function_exporters = exporters
1209        .iter()
1210        .filter_map(|(export, exporter)| {
1211            if let Type::Function(ty) = &export.ty {
1212                Some((export.name, (ty, *exporter)))
1213            } else {
1214                None
1215            }
1216        })
1217        .collect_unique::<HashMap<_, _>>();
1218
1219    let indexes = metadata
1220        .iter()
1221        .enumerate()
1222        .map(|(index, metadata)| (metadata.name, index))
1223        .collect_unique::<HashMap<_, _>>();
1224
1225    let mut result = Vec::new();
1226    let mut exported = HashSet::new();
1227    let mut seen = HashSet::new();
1228
1229    for &index in topo_sorted {
1230        let metadata = &metadata[index];
1231
1232        for name in &metadata.table_address_imports {
1233            if !exported.contains(name) {
1234                let (ty, (exporter, _)) = function_exporters
1235                    .get(name)
1236                    .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?;
1237
1238                result.push(EnvExport {
1239                    name: *name,
1240                    ty: *ty,
1241                    exporter: indexes[exporter],
1242                });
1243                exported.insert(*name);
1244            }
1245        }
1246
1247        for (import_name, (ty, _)) in &metadata.env_imports {
1248            if !exported.contains(import_name) {
1249                let exporter = indexes[find_function_exporter(import_name, ty, exporters)
1250                    .unwrap()
1251                    .0];
1252                if !seen.contains(&exporter) {
1253                    result.push(EnvExport {
1254                        name: *import_name,
1255                        ty,
1256                        exporter,
1257                    });
1258                    exported.insert(*import_name);
1259                }
1260            }
1261        }
1262
1263        seen.insert(index);
1264    }
1265
1266    // Even if no library imports these symbols, we re-export them from the
1267    // `env` module so that
1268    // `EncodingState::create_export_task_initialization_wrappers` can find
1269    // and use them:
1270    for &name in ENV_REEXPORTS {
1271        if !exported.contains(name) {
1272            if let Some(exporter) = exporters.get(&ExportKey {
1273                name,
1274                ty: Type::Function(EMPTY_FUNCTION_TYPE.clone()),
1275            }) {
1276                result.push(EnvExport {
1277                    name,
1278                    ty: &EMPTY_FUNCTION_TYPE,
1279                    exporter: indexes[exporter.0],
1280                });
1281                exported.insert(name);
1282            }
1283        }
1284    }
1285
1286    let reexport_cabi_realloc = exported.contains(CABI_REALLOC);
1287
1288    Ok(EnvExports {
1289        exports: result,
1290        reexport_cabi_realloc,
1291    })
1292}
1293
1294/// Synthesize a module which contains trapping stub exports for the specified functions.
1295fn make_stubs_module(missing: &[(&str, Export)]) -> Vec<u8> {
1296    let mut types = TypeSection::new();
1297    let mut exports = ExportSection::new();
1298    let mut functions = FunctionSection::new();
1299    let mut code = CodeSection::new();
1300    for (offset, (_, export)) in missing.iter().enumerate() {
1301        let offset = u32::try_from(offset).unwrap();
1302
1303        let Export {
1304            key:
1305                ExportKey {
1306                    name,
1307                    ty: Type::Function(ty),
1308                },
1309            ..
1310        } = export
1311        else {
1312            unreachable!();
1313        };
1314
1315        types.ty().function(
1316            ty.parameters.iter().copied().map(ValType::from),
1317            ty.results.iter().copied().map(ValType::from),
1318        );
1319        functions.function(offset);
1320        let mut function = Function::new([]);
1321        function.instruction(&Ins::Unreachable);
1322        function.instruction(&Ins::End);
1323        code.function(&function);
1324        exports.export(name, ExportKind::Func, offset);
1325    }
1326
1327    let mut module = Module::new();
1328
1329    module.section(&types);
1330    module.section(&functions);
1331    module.section(&exports);
1332    module.section(&code);
1333    module.section(&RawCustomSection(
1334        &crate::base_producers().raw_custom_section(),
1335    ));
1336
1337    let module = module.finish();
1338    wasmparser::validate(&module).unwrap();
1339
1340    module
1341}
1342
1343/// Determine which of the specified libraries are transitively reachable at runtime, i.e. reachable from a
1344/// component export or via `dlopen`.
1345fn find_reachable<'a>(
1346    metadata: &'a [Metadata<'a>],
1347    dependencies: &IndexMap<usize, IndexSet<usize>>,
1348) -> IndexSet<&'a str> {
1349    let reachable = metadata
1350        .iter()
1351        .enumerate()
1352        .filter_map(|(index, metadata)| {
1353            if metadata.has_component_exports || metadata.dl_openable || metadata.has_wasi_start {
1354                Some(index)
1355            } else {
1356                None
1357            }
1358        })
1359        .collect_unique::<IndexSet<_>>();
1360
1361    let empty = &IndexSet::new();
1362
1363    reachable
1364        .iter()
1365        .chain(
1366            reachable
1367                .iter()
1368                .flat_map(|index| dependencies.get(index).unwrap_or(empty)),
1369        )
1370        .map(|&index| metadata[index].name)
1371        .collect()
1372}
1373
1374/// Builder type for composing dynamic library modules into a component
1375#[derive(Default)]
1376pub struct Linker {
1377    /// The `(name, module, dl_openable)` triple representing the libraries to be composed
1378    ///
1379    /// The order of this list determines priority in cases where more than one library exports the same symbol.
1380    libraries: Vec<(String, Vec<u8>, bool)>,
1381
1382    /// The set of adapters to use when generating the component
1383    adapters: Vec<(String, Vec<u8>)>,
1384
1385    /// Whether to validate the resulting component prior to returning it
1386    validate: bool,
1387
1388    /// Whether to generate trapping stubs for any unresolved imports
1389    stub_missing_functions: bool,
1390
1391    /// Whether to use a built-in implementation of `dlopen`/`dlsym`.
1392    use_built_in_libdl: bool,
1393
1394    /// Whether to generate debug `name` sections.
1395    debug_names: bool,
1396
1397    /// Size of stack (in bytes) to allocate in the synthesized main module
1398    ///
1399    /// If `None`, use `DEFAULT_STACK_SIZE_BYTES`.
1400    stack_size: Option<u32>,
1401
1402    /// This affects how when to WIT worlds are merged together, for example
1403    /// from two different libraries, whether their imports are unified when the
1404    /// semver version ranges for interface allow it.
1405    merge_imports_based_on_semver: Option<bool>,
1406}
1407
1408impl Linker {
1409    /// Add a dynamic library module to this linker.
1410    ///
1411    /// If `dl_openable` is true, all of the library's exports will be added to the `dlopen`/`dlsym` lookup table
1412    /// for runtime resolution.
1413    pub fn library(mut self, name: &str, module: &[u8], dl_openable: bool) -> Result<Self> {
1414        self.libraries
1415            .push((name.to_owned(), module.to_vec(), dl_openable));
1416
1417        Ok(self)
1418    }
1419
1420    /// Add an adapter to this linker.
1421    ///
1422    /// See [crate::encoding::ComponentEncoder::adapter] for details.
1423    pub fn adapter(mut self, name: &str, module: &[u8]) -> Result<Self> {
1424        self.adapters.push((name.to_owned(), module.to_vec()));
1425
1426        Ok(self)
1427    }
1428
1429    /// Specify whether to validate the resulting component prior to returning it
1430    pub fn validate(mut self, validate: bool) -> Self {
1431        self.validate = validate;
1432        self
1433    }
1434
1435    /// Specify size of stack to allocate in the synthesized main module
1436    pub fn stack_size(mut self, stack_size: u32) -> Self {
1437        self.stack_size = Some(stack_size);
1438        self
1439    }
1440
1441    /// Specify whether to generate trapping stubs for any unresolved imports
1442    pub fn stub_missing_functions(mut self, stub_missing_functions: bool) -> Self {
1443        self.stub_missing_functions = stub_missing_functions;
1444        self
1445    }
1446
1447    /// Specify whether to use a built-in implementation of `dlopen`/`dlsym`.
1448    pub fn use_built_in_libdl(mut self, use_built_in_libdl: bool) -> Self {
1449        self.use_built_in_libdl = use_built_in_libdl;
1450        self
1451    }
1452
1453    /// Whether or not to generate debug name sections.
1454    pub fn debug_names(mut self, enable: bool) -> Self {
1455        self.debug_names = enable;
1456        self
1457    }
1458
1459    /// This affects how when to WIT worlds are merged together, for example
1460    /// from two different libraries, whether their imports are unified when the
1461    /// semver version ranges for interface allow it.
1462    ///
1463    /// This is enabled by default.
1464    pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
1465        self.merge_imports_based_on_semver = Some(merge);
1466        self
1467    }
1468
1469    /// Encode the component and return the bytes
1470    pub fn encode(mut self) -> Result<Vec<u8>> {
1471        if self.use_built_in_libdl {
1472            self.use_built_in_libdl = false;
1473            self = self.library("libdl.so", include_bytes!("../libdl.so"), false)?;
1474        }
1475
1476        let adapter_names = self
1477            .adapters
1478            .iter()
1479            .map(|(name, _)| name.as_str())
1480            .collect_unique::<HashSet<_>>();
1481
1482        if adapter_names.len() != self.adapters.len() {
1483            bail!("duplicate adapter name");
1484        }
1485
1486        let metadata = self
1487            .libraries
1488            .iter()
1489            .map(|(name, module, dl_openable)| {
1490                Metadata::try_new(name, *dl_openable, module, &adapter_names)
1491                    .with_context(|| format!("failed to extract linking metadata from {name}"))
1492            })
1493            .collect::<Result<Vec<_>>>()?;
1494
1495        {
1496            let names = self
1497                .libraries
1498                .iter()
1499                .map(|(name, ..)| name.as_str())
1500                .collect_unique::<HashSet<_>>();
1501
1502            let missing = metadata
1503                .iter()
1504                .filter_map(|metadata| {
1505                    let missing = metadata
1506                        .needed_libs
1507                        .iter()
1508                        .copied()
1509                        .filter(|name| !names.contains(*name))
1510                        .collect::<Vec<_>>();
1511
1512                    if missing.is_empty() {
1513                        None
1514                    } else {
1515                        Some((metadata.name, missing))
1516                    }
1517                })
1518                .collect::<Vec<_>>();
1519
1520            if !missing.is_empty() {
1521                bail!(
1522                    "missing libraries:\n{}",
1523                    missing
1524                        .iter()
1525                        .map(|(needed_by, missing)| format!(
1526                            "\t{needed_by} needs {}",
1527                            missing.join(", ")
1528                        ))
1529                        .collect::<Vec<_>>()
1530                        .join("\n")
1531                );
1532            }
1533        }
1534
1535        let exporters = resolve_exporters(&metadata)?;
1536
1537        let cabi_realloc_exporter = exporters
1538            .get(&ExportKey {
1539                name: "cabi_realloc",
1540                ty: Type::Function(FunctionType {
1541                    parameters: vec![ValueType::I32; 4],
1542                    results: vec![ValueType::I32],
1543                }),
1544            })
1545            .map(|exporters| exporters.first().unwrap().0);
1546
1547        let (exporters, missing, _) = resolve_symbols(&metadata, &exporters);
1548
1549        if !missing.is_empty() {
1550            if missing
1551                .iter()
1552                .all(|(_, export)| matches!(&export.key.ty, Type::Function(_)))
1553                && (self.stub_missing_functions
1554                    || missing
1555                        .iter()
1556                        .all(|(_, export)| export.flags.contains(SymbolFlags::BINDING_WEAK)))
1557            {
1558                self.stub_missing_functions = false;
1559                self.libraries
1560                    .push((STUB_LIBRARY_NAME.into(), make_stubs_module(&missing), false));
1561                return self.encode();
1562            } else {
1563                bail!(
1564                    "unresolved symbol(s):\n{}",
1565                    missing
1566                        .iter()
1567                        .filter(|(_, export)| !export.flags.contains(SymbolFlags::BINDING_WEAK))
1568                        .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) })
1569                        .collect::<Vec<_>>()
1570                        .join("\n")
1571                );
1572            }
1573        }
1574
1575        let dependencies = find_dependencies(&metadata, &exporters)?;
1576
1577        {
1578            let reachable = find_reachable(&metadata, &dependencies);
1579            let unreachable = self
1580                .libraries
1581                .iter()
1582                .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone()))
1583                .collect_unique::<HashSet<_>>();
1584
1585            if !unreachable.is_empty() {
1586                self.libraries
1587                    .retain(|(name, ..)| !unreachable.contains(name));
1588                return self.encode();
1589            }
1590        }
1591
1592        let topo_sorted = topo_sort(metadata.len(), &dependencies)?;
1593
1594        let EnvExports {
1595            exports: env_exports,
1596            reexport_cabi_realloc,
1597        } = env_exports(&metadata, &exporters, &topo_sorted)?;
1598
1599        let (env_module, dl_openables, table_base) = make_env_module(
1600            &metadata,
1601            &env_exports,
1602            if reexport_cabi_realloc {
1603                // If "env" module already reexports "cabi_realloc", we don't need to
1604                // reexport it again.
1605                None
1606            } else {
1607                cabi_realloc_exporter
1608            },
1609            self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES),
1610        );
1611
1612        let mut encoder = ComponentEncoder::default()
1613            .validate(self.validate)
1614            .debug_names(self.debug_names);
1615        if let Some(merge) = self.merge_imports_based_on_semver {
1616            encoder = encoder.merge_imports_based_on_semver(merge);
1617        };
1618        encoder = encoder.module(&env_module)?;
1619
1620        for (name, module) in &self.adapters {
1621            encoder = encoder.adapter(name, module)?;
1622        }
1623
1624        let default_env_items = [
1625            Item {
1626                alias: metadata::MEMORY.into(),
1627                kind: ExportKind::Memory,
1628                which: MainOrAdapter::Main,
1629                name: metadata::MEMORY.into(),
1630            },
1631            Item {
1632                alias: metadata::INDIRECT_FUNCTION_TABLE.into(),
1633                kind: ExportKind::Table,
1634                which: MainOrAdapter::Main,
1635                name: metadata::INDIRECT_FUNCTION_TABLE.into(),
1636            },
1637            Item {
1638                alias: metadata::STACK_POINTER.into(),
1639                kind: ExportKind::Global,
1640                which: MainOrAdapter::Main,
1641                name: metadata::STACK_POINTER.into(),
1642            },
1643            Item {
1644                alias: metadata::INIT_STACK_POINTER.into(),
1645                kind: ExportKind::Global,
1646                which: MainOrAdapter::Main,
1647                name: metadata::INIT_STACK_POINTER.into(),
1648            },
1649        ];
1650
1651        let mut seen = HashSet::new();
1652        for index in topo_sorted {
1653            let (name, module, _) = &self.libraries[index];
1654            let metadata = &metadata[index];
1655
1656            let env_items = default_env_items
1657                .iter()
1658                .cloned()
1659                .chain([
1660                    Item {
1661                        alias: metadata::MEMORY_BASE.into(),
1662                        kind: ExportKind::Global,
1663                        which: MainOrAdapter::Main,
1664                        name: format!("{name}:memory_base"),
1665                    },
1666                    Item {
1667                        alias: metadata::TABLE_BASE.into(),
1668                        kind: ExportKind::Global,
1669                        which: MainOrAdapter::Main,
1670                        name: format!("{name}:table_base"),
1671                    },
1672                ])
1673                .chain(metadata.env_imports.iter().map(|(name, (ty, _))| {
1674                    let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap();
1675
1676                    Item {
1677                        alias: (*name).into(),
1678                        kind: ExportKind::Func,
1679                        which: if seen.contains(exporter) {
1680                            MainOrAdapter::Adapter(exporter.to_owned())
1681                        } else {
1682                            MainOrAdapter::Main
1683                        },
1684                        name: (*name).into(),
1685                    }
1686                }))
1687                .chain(
1688                    metadata
1689                        .tag_imports
1690                        .iter()
1691                        .map(|(name, ty)| {
1692                            let (exporter, _) = find_tag_exporter(name, ty, &exporters).unwrap();
1693
1694                            Ok(Item {
1695                                alias: (*name).into(),
1696                                kind: ExportKind::Tag,
1697                                which: if seen.contains(exporter) {
1698                                    MainOrAdapter::Adapter(exporter.to_owned())
1699                                } else {
1700                                    // As of this writing, LLVM-produced shared
1701                                    // libraries which use C++ exceptions import
1702                                    // a `cpp_exception` tag which is defined in
1703                                    // `libunwind.so`.  Presumably
1704                                    // `libunwind.so` will not import anything
1705                                    // circularly from such shared libraries, so
1706                                    // this case shouldn't be hit in practice
1707                                    // unless we're dealing with some other,
1708                                    // non-LLVM toolchain that does weird
1709                                    // circular things with imports and
1710                                    // exception tags.
1711                                    bail!(
1712                                        "circular dependency prevents direct tag import from `{}`",
1713                                        exporter.to_owned()
1714                                    )
1715                                },
1716                                name: (*name).into(),
1717                            })
1718                        })
1719                        .collect::<Result<Vec<_>>>()?,
1720                )
1721                .chain(if metadata.is_asyncified {
1722                    vec![
1723                        Item {
1724                            alias: metadata::ASYNCIFY_STATE.into(),
1725                            kind: ExportKind::Global,
1726                            which: MainOrAdapter::Main,
1727                            name: metadata::ASYNCIFY_STATE.into(),
1728                        },
1729                        Item {
1730                            alias: metadata::ASYNCIFY_DATA.into(),
1731                            kind: ExportKind::Global,
1732                            which: MainOrAdapter::Main,
1733                            name: metadata::ASYNCIFY_DATA.into(),
1734                        },
1735                    ]
1736                } else {
1737                    vec![]
1738                })
1739                .collect();
1740
1741            let global_item = |address_name: &str| Item {
1742                alias: address_name.into(),
1743                kind: ExportKind::Global,
1744                which: MainOrAdapter::Main,
1745                name: format!("{name}:{address_name}"),
1746            };
1747
1748            let mem_items = metadata
1749                .memory_address_imports
1750                .iter()
1751                .copied()
1752                .map(global_item)
1753                .chain(
1754                    [
1755                        metadata::HEAP_BASE,
1756                        metadata::HEAP_END,
1757                        metadata::STACK_HIGH,
1758                        metadata::STACK_LOW,
1759                    ]
1760                    .into_iter()
1761                    .map(|name| Item {
1762                        alias: name.into(),
1763                        kind: ExportKind::Global,
1764                        which: MainOrAdapter::Main,
1765                        name: name.into(),
1766                    }),
1767                )
1768                .collect();
1769
1770            let func_items = metadata
1771                .table_address_imports
1772                .iter()
1773                .copied()
1774                .map(global_item)
1775                .collect();
1776
1777            let mut import_items = BTreeMap::<_, Vec<_>>::new();
1778            for import in &metadata.imports {
1779                import_items.entry(import.module).or_default().push(Item {
1780                    alias: import.name.into(),
1781                    kind: ExportKind::from(&import.ty),
1782                    which: MainOrAdapter::Main,
1783                    name: format!("{}:{}", import.module, import.name),
1784                });
1785            }
1786
1787            encoder = encoder.library(
1788                name,
1789                module,
1790                LibraryInfo {
1791                    instantiate_after_shims: false,
1792                    arguments: [
1793                        (metadata::GOT_MEM.into(), Instance::Items(mem_items)),
1794                        (metadata::GOT_FUNC.into(), Instance::Items(func_items)),
1795                        (metadata::ENV.into(), Instance::Items(env_items)),
1796                    ]
1797                    .into_iter()
1798                    .chain(
1799                        import_items
1800                            .into_iter()
1801                            .map(|(k, v)| (k.into(), Instance::Items(v))),
1802                    )
1803                    .collect(),
1804                },
1805            )?;
1806
1807            seen.insert(name.as_str());
1808        }
1809
1810        encoder
1811            .library(
1812                "__init",
1813                &make_init_module(
1814                    &metadata,
1815                    &exporters,
1816                    &env_exports,
1817                    dl_openables,
1818                    table_base,
1819                )?,
1820                LibraryInfo {
1821                    instantiate_after_shims: true,
1822                    arguments: iter::once((
1823                        metadata::ENV.into(),
1824                        Instance::MainOrAdapter(MainOrAdapter::Main),
1825                    ))
1826                    .chain(self.libraries.iter().map(|(name, ..)| {
1827                        (
1828                            name.clone(),
1829                            Instance::MainOrAdapter(MainOrAdapter::Adapter(name.clone())),
1830                        )
1831                    }))
1832                    .collect(),
1833                },
1834            )?
1835            .encode()
1836    }
1837}