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