wit_component_update/
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, HeapType, ImportSection,
39        Instruction as Ins, MemArg, MemorySection, MemoryType, Module, RawCustomSection, RefType,
40        StartSection, 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.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.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.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.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            ty: u32::try_from(index).unwrap(),
438            table: 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 {
468                nullable: true,
469                heap_type: HeapType::Func,
470            },
471            minimum: table_offset,
472            maximum: None,
473        });
474        exports.export("__indirect_function_table", ExportKind::Table, 0);
475        module.section(&tables);
476    }
477
478    {
479        let mut memories = MemorySection::new();
480        memories.memory(MemoryType {
481            minimum: u64::from(memory_size),
482            maximum: None,
483            memory64: false,
484            shared: false,
485            page_size_log2: None,
486        });
487        exports.export("memory", ExportKind::Memory, 0);
488        module.section(&memories);
489    }
490
491    module.section(&globals);
492    module.section(&exports);
493    module.section(&code);
494    module.section(&RawCustomSection(
495        &crate::base_producers().raw_custom_section(),
496    ));
497
498    let module = module.finish();
499    wasmparser::validate(&module).unwrap();
500
501    (module, dl_openables, indirection_table_base)
502}
503
504/// Synthesize the "init" module, responsible for initializing global variables per the dynamic linking tool
505/// convention and calling any static constructors and/or link-time fixup functions.
506///
507/// This module also contains the data segment for the `dlopen`/`dlsym` lookup table.
508fn make_init_module(
509    metadata: &[Metadata],
510    exporters: &IndexMap<&ExportKey, (&str, &Export)>,
511    function_exports: &[(&str, &FunctionType, usize)],
512    dl_openables: DlOpenables,
513    indirection_table_base: u32,
514) -> Result<Vec<u8>> {
515    let mut module = Module::new();
516
517    // TODO: deduplicate types
518    let mut types = TypeSection::new();
519    types.function([], []);
520    let thunk_ty = 0;
521    types.function([ValType::I32], []);
522    let one_i32_param_ty = 1;
523    let mut type_offset = 2;
524
525    for metadata in metadata {
526        if metadata.dl_openable {
527            for export in &metadata.exports {
528                if let Type::Function(ty) = &export.key.ty {
529                    types.function(
530                        ty.parameters.iter().copied().map(ValType::from),
531                        ty.results.iter().copied().map(ValType::from),
532                    );
533                }
534            }
535        }
536    }
537    for (_, ty, _) in function_exports {
538        types.function(
539            ty.parameters.iter().copied().map(ValType::from),
540            ty.results.iter().copied().map(ValType::from),
541        );
542    }
543    module.section(&types);
544
545    let mut imports = ImportSection::new();
546    imports.import(
547        "env",
548        "memory",
549        MemoryType {
550            minimum: 0,
551            maximum: None,
552            memory64: false,
553            shared: false,
554            page_size_log2: None,
555        },
556    );
557    imports.import(
558        "env",
559        "__indirect_function_table",
560        TableType {
561            element_type: RefType {
562                nullable: true,
563                heap_type: HeapType::Func,
564            },
565            minimum: 0,
566            maximum: None,
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),
748        );
749        elements.active(
750            None,
751            &const_u32(indirection_table_base),
752            Elements::Functions(&indirections),
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<'a>(
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
1053/// Analyze the specified metadata and generate a list of functions which should be re-exported as a
1054/// `call.indirect`-based function by the main (AKA "env") module, including the offset of the library containing
1055/// the original export.
1056fn env_function_exports<'a>(
1057    metadata: &'a [Metadata<'a>],
1058    exporters: &'a IndexMap<&'a ExportKey, (&'a str, &Export)>,
1059    topo_sorted: &[usize],
1060) -> Result<Vec<(&'a str, &'a FunctionType, usize)>> {
1061    let function_exporters = exporters
1062        .iter()
1063        .filter_map(|(export, exporter)| {
1064            if let Type::Function(ty) = &export.ty {
1065                Some((export.name, (ty, *exporter)))
1066            } else {
1067                None
1068            }
1069        })
1070        .collect_unique::<HashMap<_, _>>();
1071
1072    let indexes = metadata
1073        .iter()
1074        .enumerate()
1075        .map(|(index, metadata)| (metadata.name, index))
1076        .collect_unique::<HashMap<_, _>>();
1077
1078    let mut result = Vec::new();
1079    let mut exported = HashSet::new();
1080    let mut seen = HashSet::new();
1081
1082    for &index in topo_sorted {
1083        let metadata = &metadata[index];
1084
1085        for name in &metadata.table_address_imports {
1086            if !exported.contains(name) {
1087                let (ty, (exporter, _)) = function_exporters
1088                    .get(name)
1089                    .ok_or_else(|| anyhow!("unable to find {name:?} in any library"))?;
1090
1091                result.push((*name, *ty, indexes[exporter]));
1092                exported.insert(*name);
1093            }
1094        }
1095
1096        for (import_name, (ty, _)) in &metadata.env_imports {
1097            if !exported.contains(import_name) {
1098                let exporter = indexes[find_function_exporter(import_name, ty, exporters)
1099                    .unwrap()
1100                    .0];
1101                if !seen.contains(&exporter) {
1102                    result.push((*import_name, ty, exporter));
1103                    exported.insert(*import_name);
1104                }
1105            }
1106        }
1107        seen.insert(index);
1108    }
1109
1110    Ok(result)
1111}
1112
1113/// Synthesize a module which contains trapping stub exports for the specified functions.
1114fn make_stubs_module(missing: &[(&str, Export)]) -> Vec<u8> {
1115    let mut types = TypeSection::new();
1116    let mut exports = ExportSection::new();
1117    let mut functions = FunctionSection::new();
1118    let mut code = CodeSection::new();
1119    for (offset, (_, export)) in missing.iter().enumerate() {
1120        let offset = u32::try_from(offset).unwrap();
1121
1122        let Export {
1123            key:
1124                ExportKey {
1125                    name,
1126                    ty: Type::Function(ty),
1127                },
1128            ..
1129        } = export
1130        else {
1131            unreachable!();
1132        };
1133
1134        types.function(
1135            ty.parameters.iter().copied().map(ValType::from),
1136            ty.results.iter().copied().map(ValType::from),
1137        );
1138        functions.function(offset);
1139        let mut function = Function::new([]);
1140        function.instruction(&Ins::Unreachable);
1141        function.instruction(&Ins::End);
1142        code.function(&function);
1143        exports.export(name, ExportKind::Func, offset);
1144    }
1145
1146    let mut module = Module::new();
1147
1148    module.section(&types);
1149    module.section(&functions);
1150    module.section(&exports);
1151    module.section(&code);
1152    module.section(&RawCustomSection(
1153        &crate::base_producers().raw_custom_section(),
1154    ));
1155
1156    let module = module.finish();
1157    wasmparser::validate(&module).unwrap();
1158
1159    module
1160}
1161
1162/// Determine which of the specified libraries are transitively reachable at runtime, i.e. reachable from a
1163/// component export or via `dlopen`.
1164fn find_reachable<'a>(
1165    metadata: &'a [Metadata<'a>],
1166    dependencies: &IndexMap<usize, IndexSet<usize>>,
1167) -> IndexSet<&'a str> {
1168    let reachable = metadata
1169        .iter()
1170        .enumerate()
1171        .filter_map(|(index, metadata)| {
1172            if metadata.has_component_exports || metadata.dl_openable || metadata.has_wasi_start {
1173                Some(index)
1174            } else {
1175                None
1176            }
1177        })
1178        .collect_unique::<IndexSet<_>>();
1179
1180    let empty = &IndexSet::new();
1181
1182    reachable
1183        .iter()
1184        .chain(
1185            reachable
1186                .iter()
1187                .flat_map(|index| dependencies.get(index).unwrap_or(empty)),
1188        )
1189        .map(|&index| metadata[index].name)
1190        .collect()
1191}
1192
1193/// Builder type for composing dynamic library modules into a component
1194#[derive(Default)]
1195pub struct Linker {
1196    /// The `(name, module, dl_openable)` triple representing the libraries to be composed
1197    ///
1198    /// The order of this list determines priority in cases where more than one library exports the same symbol.
1199    libraries: Vec<(String, Vec<u8>, bool)>,
1200
1201    /// The set of adapters to use when generating the component
1202    adapters: Vec<(String, Vec<u8>)>,
1203
1204    /// Whether to validate the resulting component prior to returning it
1205    validate: bool,
1206
1207    /// Whether to generate trapping stubs for any unresolved imports
1208    stub_missing_functions: bool,
1209
1210    /// Whether to use a built-in implementation of `dlopen`/`dlsym`.
1211    use_built_in_libdl: bool,
1212
1213    /// Size of stack (in bytes) to allocate in the synthesized main module
1214    ///
1215    /// If `None`, use `DEFAULT_STACK_SIZE_BYTES`.
1216    stack_size: Option<u32>,
1217}
1218
1219impl Linker {
1220    /// Add a dynamic library module to this linker.
1221    ///
1222    /// If `dl_openable` is true, all of the libraries exports will be added to the `dlopen`/`dlsym` lookup table
1223    /// for runtime resolution.
1224    pub fn library(mut self, name: &str, module: &[u8], dl_openable: bool) -> Result<Self> {
1225        self.libraries
1226            .push((name.to_owned(), module.to_vec(), dl_openable));
1227
1228        Ok(self)
1229    }
1230
1231    /// Add an adapter to this linker.
1232    ///
1233    /// See [crate::encoding::ComponentEncoder::adapter] for details.
1234    pub fn adapter(mut self, name: &str, module: &[u8]) -> Result<Self> {
1235        self.adapters.push((name.to_owned(), module.to_vec()));
1236
1237        Ok(self)
1238    }
1239
1240    /// Specify whether to validate the resulting component prior to returning it
1241    pub fn validate(mut self, validate: bool) -> Self {
1242        self.validate = validate;
1243        self
1244    }
1245
1246    /// Specify size of stack to allocate in the synthesized main module
1247    pub fn stack_size(mut self, stack_size: u32) -> Self {
1248        self.stack_size = Some(stack_size);
1249        self
1250    }
1251
1252    /// Specify whether to generate trapping stubs for any unresolved imports
1253    pub fn stub_missing_functions(mut self, stub_missing_functions: bool) -> Self {
1254        self.stub_missing_functions = stub_missing_functions;
1255        self
1256    }
1257
1258    /// Specify whether to use a built-in implementation of `dlopen`/`dlsym`.
1259    pub fn use_built_in_libdl(mut self, use_built_in_libdl: bool) -> Self {
1260        self.use_built_in_libdl = use_built_in_libdl;
1261        self
1262    }
1263
1264    /// Encode the component and return the bytes
1265    pub fn encode(mut self) -> Result<Vec<u8>> {
1266        if self.use_built_in_libdl {
1267            self.use_built_in_libdl = false;
1268            self = self.library("libdl.so", include_bytes!("../libdl.so"), false)?;
1269        }
1270
1271        let adapter_names = self
1272            .adapters
1273            .iter()
1274            .map(|(name, _)| name.as_str())
1275            .collect_unique::<HashSet<_>>();
1276
1277        if adapter_names.len() != self.adapters.len() {
1278            bail!("duplicate adapter name");
1279        }
1280
1281        let metadata = self
1282            .libraries
1283            .iter()
1284            .map(|(name, module, dl_openable)| {
1285                Metadata::try_new(name, *dl_openable, module, &adapter_names)
1286                    .with_context(|| format!("failed to extract linking metadata from {name}"))
1287            })
1288            .collect::<Result<Vec<_>>>()?;
1289
1290        {
1291            let names = self
1292                .libraries
1293                .iter()
1294                .map(|(name, ..)| name.as_str())
1295                .collect_unique::<HashSet<_>>();
1296
1297            let missing = metadata
1298                .iter()
1299                .filter_map(|metadata| {
1300                    let missing = metadata
1301                        .needed_libs
1302                        .iter()
1303                        .copied()
1304                        .filter(|name| !names.contains(*name))
1305                        .collect::<Vec<_>>();
1306
1307                    if missing.is_empty() {
1308                        None
1309                    } else {
1310                        Some((metadata.name, missing))
1311                    }
1312                })
1313                .collect::<Vec<_>>();
1314
1315            if !missing.is_empty() {
1316                bail!(
1317                    "missing libraries:\n{}",
1318                    missing
1319                        .iter()
1320                        .map(|(needed_by, missing)| format!(
1321                            "\t{needed_by} needs {}",
1322                            missing.join(", ")
1323                        ))
1324                        .collect::<Vec<_>>()
1325                        .join("\n")
1326                );
1327            }
1328        }
1329
1330        let exporters = resolve_exporters(&metadata)?;
1331
1332        let cabi_realloc_exporter = exporters
1333            .get(&ExportKey {
1334                name: "cabi_realloc",
1335                ty: Type::Function(FunctionType {
1336                    parameters: vec![ValueType::I32; 4],
1337                    results: vec![ValueType::I32],
1338                }),
1339            })
1340            .map(|exporters| exporters.first().unwrap().0);
1341
1342        let (exporters, missing, _) = resolve_symbols(&metadata, &exporters);
1343
1344        if !missing.is_empty() {
1345            if missing
1346                .iter()
1347                .all(|(_, export)| matches!(&export.key.ty, Type::Function(_)))
1348                && (self.stub_missing_functions
1349                    || missing
1350                        .iter()
1351                        .all(|(_, export)| export.flags.contains(SymbolFlags::BINDING_WEAK)))
1352            {
1353                self.stub_missing_functions = false;
1354                self.libraries.push((
1355                    "wit-component:stubs".into(),
1356                    make_stubs_module(&missing),
1357                    false,
1358                ));
1359                return self.encode();
1360            } else {
1361                bail!(
1362                    "unresolved symbol(s):\n{}",
1363                    missing
1364                        .iter()
1365                        .filter(|(_, export)| !export.flags.contains(SymbolFlags::BINDING_WEAK))
1366                        .map(|(importer, export)| { format!("\t{importer} needs {}", export.key) })
1367                        .collect::<Vec<_>>()
1368                        .join("\n")
1369                );
1370            }
1371        }
1372
1373        let dependencies = find_dependencies(&metadata, &exporters)?;
1374
1375        {
1376            let reachable = find_reachable(&metadata, &dependencies);
1377            let unreachable = self
1378                .libraries
1379                .iter()
1380                .filter_map(|(name, ..)| (!reachable.contains(name.as_str())).then(|| name.clone()))
1381                .collect_unique::<HashSet<_>>();
1382
1383            if !unreachable.is_empty() {
1384                self.libraries
1385                    .retain(|(name, ..)| !unreachable.contains(name));
1386                return self.encode();
1387            }
1388        }
1389
1390        let topo_sorted = topo_sort(metadata.len(), &dependencies)?;
1391
1392        let env_function_exports = env_function_exports(&metadata, &exporters, &topo_sorted)?;
1393
1394        let (env_module, dl_openables, table_base) = make_env_module(
1395            &metadata,
1396            &env_function_exports,
1397            cabi_realloc_exporter,
1398            self.stack_size.unwrap_or(DEFAULT_STACK_SIZE_BYTES),
1399        );
1400
1401        let mut encoder = ComponentEncoder::default()
1402            .validate(self.validate)
1403            .module(&env_module)?;
1404
1405        for (name, module) in &self.adapters {
1406            encoder = encoder.adapter(name, module)?;
1407        }
1408
1409        let default_env_items = [
1410            Item {
1411                alias: "memory".into(),
1412                kind: ExportKind::Memory,
1413                which: MainOrAdapter::Main,
1414                name: "memory".into(),
1415            },
1416            Item {
1417                alias: "__indirect_function_table".into(),
1418                kind: ExportKind::Table,
1419                which: MainOrAdapter::Main,
1420                name: "__indirect_function_table".into(),
1421            },
1422            Item {
1423                alias: "__stack_pointer".into(),
1424                kind: ExportKind::Global,
1425                which: MainOrAdapter::Main,
1426                name: "__stack_pointer".into(),
1427            },
1428        ];
1429
1430        let mut seen = HashSet::new();
1431        for index in topo_sorted {
1432            let (name, module, _) = &self.libraries[index];
1433            let metadata = &metadata[index];
1434
1435            let env_items = default_env_items
1436                .iter()
1437                .cloned()
1438                .chain([
1439                    Item {
1440                        alias: "__memory_base".into(),
1441                        kind: ExportKind::Global,
1442                        which: MainOrAdapter::Main,
1443                        name: format!("{name}:memory_base"),
1444                    },
1445                    Item {
1446                        alias: "__table_base".into(),
1447                        kind: ExportKind::Global,
1448                        which: MainOrAdapter::Main,
1449                        name: format!("{name}:table_base"),
1450                    },
1451                ])
1452                .chain(metadata.env_imports.iter().map(|(name, (ty, _))| {
1453                    let (exporter, _) = find_function_exporter(name, ty, &exporters).unwrap();
1454
1455                    Item {
1456                        alias: (*name).into(),
1457                        kind: ExportKind::Func,
1458                        which: if seen.contains(exporter) {
1459                            MainOrAdapter::Adapter(exporter.to_owned())
1460                        } else {
1461                            MainOrAdapter::Main
1462                        },
1463                        name: (*name).into(),
1464                    }
1465                }))
1466                .chain(if metadata.is_asyncified {
1467                    vec![
1468                        Item {
1469                            alias: "__asyncify_state".into(),
1470                            kind: ExportKind::Global,
1471                            which: MainOrAdapter::Main,
1472                            name: "__asyncify_state".into(),
1473                        },
1474                        Item {
1475                            alias: "__asyncify_data".into(),
1476                            kind: ExportKind::Global,
1477                            which: MainOrAdapter::Main,
1478                            name: "__asyncify_data".into(),
1479                        },
1480                    ]
1481                } else {
1482                    vec![]
1483                })
1484                .collect();
1485
1486            let global_item = |address_name: &str| Item {
1487                alias: address_name.into(),
1488                kind: ExportKind::Global,
1489                which: MainOrAdapter::Main,
1490                name: format!("{name}:{address_name}"),
1491            };
1492
1493            let mem_items = metadata
1494                .memory_address_imports
1495                .iter()
1496                .copied()
1497                .map(global_item)
1498                .chain(["__heap_base", "__heap_end"].into_iter().map(|name| Item {
1499                    alias: name.into(),
1500                    kind: ExportKind::Global,
1501                    which: MainOrAdapter::Main,
1502                    name: name.into(),
1503                }))
1504                .collect();
1505
1506            let func_items = metadata
1507                .table_address_imports
1508                .iter()
1509                .copied()
1510                .map(global_item)
1511                .collect();
1512
1513            let mut import_items = BTreeMap::<_, Vec<_>>::new();
1514            for import in &metadata.imports {
1515                import_items.entry(import.module).or_default().push(Item {
1516                    alias: import.name.into(),
1517                    kind: ExportKind::from(&import.ty),
1518                    which: MainOrAdapter::Main,
1519                    name: format!("{}:{}", import.module, import.name),
1520                });
1521            }
1522
1523            encoder = encoder.library(
1524                name,
1525                module,
1526                LibraryInfo {
1527                    instantiate_after_shims: false,
1528                    arguments: [
1529                        ("GOT.mem".into(), Instance::Items(mem_items)),
1530                        ("GOT.func".into(), Instance::Items(func_items)),
1531                        ("env".into(), Instance::Items(env_items)),
1532                    ]
1533                    .into_iter()
1534                    .chain(
1535                        import_items
1536                            .into_iter()
1537                            .map(|(k, v)| (k.into(), Instance::Items(v))),
1538                    )
1539                    .collect(),
1540                },
1541            )?;
1542
1543            seen.insert(name.as_str());
1544        }
1545
1546        encoder
1547            .library(
1548                "__init",
1549                &make_init_module(
1550                    &metadata,
1551                    &exporters,
1552                    &env_function_exports,
1553                    dl_openables,
1554                    table_base,
1555                )?,
1556                LibraryInfo {
1557                    instantiate_after_shims: true,
1558                    arguments: iter::once((
1559                        "env".into(),
1560                        Instance::MainOrAdapter(MainOrAdapter::Main),
1561                    ))
1562                    .chain(self.libraries.iter().map(|(name, ..)| {
1563                        (
1564                            name.clone(),
1565                            Instance::MainOrAdapter(MainOrAdapter::Adapter(name.clone())),
1566                        )
1567                    }))
1568                    .collect(),
1569                },
1570            )?
1571            .encode()
1572    }
1573}