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