wasm_encoder/core/
linking.rs

1use crate::{encode_section, CustomSection, Encode, Section, SectionId};
2use alloc::borrow::Cow;
3use alloc::vec;
4use alloc::vec::Vec;
5
6const VERSION: u32 = 2;
7
8/// An encoder for the [linking custom
9/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section).
10///
11/// This section is a non-standard convention that is supported by the LLVM
12/// toolchain. It, along with associated "reloc.*" custom sections, allows you
13/// to treat a Wasm module as a low-level object file that can be linked with
14/// other Wasm object files to produce a final, complete Wasm module.
15///
16/// The linking section must come before the reloc sections.
17///
18/// # Example
19///
20/// ```
21/// use wasm_encoder::{LinkingSection, Module, SymbolTable};
22///
23/// // Create a new linking section.
24/// let mut linking = LinkingSection::new();
25///
26/// // Define a symbol table.
27/// let mut sym_tab = SymbolTable::new();
28///
29/// // Define a function symbol in the symbol table.
30/// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED;
31/// let func_index = 42;
32/// let sym_name = "my_exported_func";
33/// sym_tab.function(flags, func_index, Some(sym_name));
34///
35/// // Add the symbol table to our linking section.
36/// linking.symbol_table(&sym_tab);
37///
38/// // Add the linking section to a new Wasm module and get the encoded bytes.
39/// let mut module = Module::new();
40/// module.section(&linking);
41/// let wasm_bytes = module.finish();
42/// ```
43#[derive(Clone, Debug)]
44pub struct LinkingSection {
45    bytes: Vec<u8>,
46}
47
48impl LinkingSection {
49    /// Construct a new encoder for the linking custom section.
50    pub fn new() -> Self {
51        Self::default()
52    }
53
54    // TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection.
55
56    // TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection.
57
58    // TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection.
59
60    /// Add a symbol table subsection.
61    pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self {
62        symbol_table.encode(&mut self.bytes);
63        self
64    }
65}
66
67impl Default for LinkingSection {
68    fn default() -> Self {
69        let mut bytes = Vec::new();
70        VERSION.encode(&mut bytes);
71        Self { bytes }
72    }
73}
74
75impl Encode for LinkingSection {
76    fn encode(&self, sink: &mut Vec<u8>) {
77        CustomSection {
78            name: "linking".into(),
79            data: Cow::Borrowed(&self.bytes),
80        }
81        .encode(sink);
82    }
83}
84
85impl Section for LinkingSection {
86    fn id(&self) -> u8 {
87        SectionId::Custom.into()
88    }
89}
90
91#[allow(unused)]
92const WASM_SEGMENT_INFO: u8 = 5;
93#[allow(unused)]
94const WASM_INIT_FUNCS: u8 = 6;
95#[allow(unused)]
96const WASM_COMDAT_INFO: u8 = 7;
97const WASM_SYMBOL_TABLE: u8 = 8;
98
99/// A subsection of the [linking custom section][crate::LinkingSection] that
100/// provides extra information about the symbols present in this Wasm object
101/// file.
102#[derive(Clone, Debug, Default)]
103pub struct SymbolTable {
104    bytes: Vec<u8>,
105    num_added: u32,
106}
107
108const SYMTAB_FUNCTION: u32 = 0;
109const SYMTAB_DATA: u32 = 1;
110const SYMTAB_GLOBAL: u32 = 2;
111#[allow(unused)]
112const SYMTAB_SECTION: u32 = 3;
113#[allow(unused)]
114const SYMTAB_TAG: u32 = 4;
115const SYMTAB_TABLE: u32 = 5;
116
117impl SymbolTable {
118    /// Construct a new symbol table subsection encoder.
119    pub fn new() -> Self {
120        SymbolTable {
121            bytes: vec![],
122            num_added: 0,
123        }
124    }
125
126    /// Define a function symbol in this symbol table.
127    ///
128    /// The `name` must be omitted if `index` references an imported table and
129    /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
130    pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
131        SYMTAB_FUNCTION.encode(&mut self.bytes);
132        flags.encode(&mut self.bytes);
133        index.encode(&mut self.bytes);
134        if let Some(name) = name {
135            name.encode(&mut self.bytes);
136        }
137        self.num_added += 1;
138        self
139    }
140
141    /// Define a global symbol in this symbol table.
142    ///
143    /// The `name` must be omitted if `index` references an imported table and
144    /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
145    pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
146        SYMTAB_GLOBAL.encode(&mut self.bytes);
147        flags.encode(&mut self.bytes);
148        index.encode(&mut self.bytes);
149        if let Some(name) = name {
150            name.encode(&mut self.bytes);
151        }
152        self.num_added += 1;
153        self
154    }
155
156    // TODO: tags
157
158    /// Define a table symbol in this symbol table.
159    ///
160    /// The `name` must be omitted if `index` references an imported table and
161    /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
162    pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
163        SYMTAB_TABLE.encode(&mut self.bytes);
164        flags.encode(&mut self.bytes);
165        index.encode(&mut self.bytes);
166        if let Some(name) = name {
167            name.encode(&mut self.bytes);
168        }
169        self.num_added += 1;
170        self
171    }
172
173    /// Add a data symbol to this symbol table.
174    pub fn data(
175        &mut self,
176        flags: u32,
177        name: &str,
178        definition: Option<DataSymbolDefinition>,
179    ) -> &mut Self {
180        SYMTAB_DATA.encode(&mut self.bytes);
181        flags.encode(&mut self.bytes);
182        name.encode(&mut self.bytes);
183        if let Some(def) = definition {
184            def.index.encode(&mut self.bytes);
185            def.offset.encode(&mut self.bytes);
186            def.size.encode(&mut self.bytes);
187        }
188        self.num_added += 1;
189        self
190    }
191
192    // TODO: sections
193
194    /// This is a weak symbol.
195    ///
196    /// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
197    ///
198    /// When linking multiple modules defining the same symbol, all weak
199    /// definitions are discarded if any strong definitions exist; then if
200    /// multiple weak definitions exist all but one (unspecified) are discarded;
201    /// and finally it is an error if more than one definition remains.
202    pub const WASM_SYM_BINDING_WEAK: u32 = 0x1;
203
204    /// This is a local symbol.
205    ///
206    /// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`.
207    ///
208    /// Local symbols are not to be exported, or linked to other
209    /// modules/sections. The names of all non-local symbols must be unique, but
210    /// the names of local symbols are not considered for uniqueness. A local
211    /// function or global symbol cannot reference an import.
212    pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02;
213
214    /// This is a hidden symbol.
215    ///
216    /// Hidden symbols are not to be exported when performing the final link,
217    /// but may be linked to other modules.
218    pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04;
219
220    /// This symbol is not defined.
221    ///
222    /// For non-data symbols, this must match whether the symbol is an import or
223    /// is defined; for data symbols, determines whether a segment is specified.
224    pub const WASM_SYM_UNDEFINED: u32 = 0x10;
225
226    /// This symbol is intended to be exported from the wasm module to the host
227    /// environment.
228    ///
229    /// This differs from the visibility flags in that it effects the static
230    /// linker.
231    pub const WASM_SYM_EXPORTED: u32 = 0x20;
232
233    /// This symbol uses an explicit symbol name, rather than reusing the name
234    /// from a wasm import.
235    ///
236    /// This allows it to remap imports from foreign WebAssembly modules into
237    /// local symbols with different names.
238    pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40;
239
240    /// This symbol is intended to be included in the linker output, regardless
241    /// of whether it is used by the program.
242    pub const WASM_SYM_NO_STRIP: u32 = 0x80;
243}
244
245impl Encode for SymbolTable {
246    fn encode(&self, sink: &mut Vec<u8>) {
247        sink.push(WASM_SYMBOL_TABLE);
248        encode_section(sink, self.num_added, &self.bytes);
249    }
250}
251
252/// The definition of a data symbol within a symbol table.
253#[derive(Clone, Debug)]
254pub struct DataSymbolDefinition {
255    /// The index of the data segment that this symbol is in.
256    pub index: u32,
257    /// The offset of this symbol within its segment.
258    pub offset: u32,
259    /// The byte size (which can be zero) of this data symbol.
260    ///
261    /// Note that `offset + size` must be less than or equal to the segment's
262    /// size.
263    pub size: u32,
264}