wit_component/
linking.rs

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