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