wasm_encoder/core/
linking.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
use std::borrow::Cow;

use crate::{encode_section, CustomSection, Encode, Section, SectionId};

const VERSION: u32 = 2;

/// An encoder for the [linking custom
/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section).
///
/// This section is a non-standard convention that is supported by the LLVM
/// toolchain. It, along with associated "reloc.*" custom sections, allows you
/// to treat a Wasm module as a low-level object file that can be linked with
/// other Wasm object files to produce a final, complete Wasm module.
///
/// The linking section must come before the reloc sections.
///
/// # Example
///
/// ```
/// use wasm_encoder::{LinkingSection, Module, SymbolTable};
///
/// // Create a new linking section.
/// let mut linking = LinkingSection::new();
///
/// // Define a symbol table.
/// let mut sym_tab = SymbolTable::new();
///
/// // Define a function symbol in the symbol table.
/// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED;
/// let func_index = 42;
/// let sym_name = "my_exported_func";
/// sym_tab.function(flags, func_index, Some(sym_name));
///
/// // Add the symbol table to our linking section.
/// linking.symbol_table(&sym_tab);
///
/// // Add the linking section to a new Wasm module and get the encoded bytes.
/// let mut module = Module::new();
/// module.section(&linking);
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct LinkingSection {
    bytes: Vec<u8>,
}

impl LinkingSection {
    /// Construct a new encoder for the linking custom section.
    pub fn new() -> Self {
        Self::default()
    }

    // TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection.

    // TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection.

    // TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection.

    /// Add a symbol table subsection.
    pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self {
        symbol_table.encode(&mut self.bytes);
        self
    }
}

impl Default for LinkingSection {
    fn default() -> Self {
        let mut bytes = Vec::new();
        VERSION.encode(&mut bytes);
        Self { bytes }
    }
}

impl Encode for LinkingSection {
    fn encode(&self, sink: &mut Vec<u8>) {
        CustomSection {
            name: "linking".into(),
            data: Cow::Borrowed(&self.bytes),
        }
        .encode(sink);
    }
}

impl Section for LinkingSection {
    fn id(&self) -> u8 {
        SectionId::Custom.into()
    }
}

#[allow(unused)]
const WASM_SEGMENT_INFO: u8 = 5;
#[allow(unused)]
const WASM_INIT_FUNCS: u8 = 6;
#[allow(unused)]
const WASM_COMDAT_INFO: u8 = 7;
const WASM_SYMBOL_TABLE: u8 = 8;

/// A subsection of the [linking custom section][crate::LinkingSection] that
/// provides extra information about the symbols present in this Wasm object
/// file.
#[derive(Clone, Debug, Default)]
pub struct SymbolTable {
    bytes: Vec<u8>,
    num_added: u32,
}

const SYMTAB_FUNCTION: u32 = 0;
const SYMTAB_DATA: u32 = 1;
const SYMTAB_GLOBAL: u32 = 2;
#[allow(unused)]
const SYMTAB_SECTION: u32 = 3;
#[allow(unused)]
const SYMTAB_TAG: u32 = 4;
const SYMTAB_TABLE: u32 = 5;

impl SymbolTable {
    /// Construct a new symbol table subsection encoder.
    pub fn new() -> Self {
        SymbolTable {
            bytes: vec![],
            num_added: 0,
        }
    }

    /// Define a function symbol in this symbol table.
    ///
    /// The `name` must be omitted if `index` references an imported table and
    /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
    pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
        SYMTAB_FUNCTION.encode(&mut self.bytes);
        flags.encode(&mut self.bytes);
        index.encode(&mut self.bytes);
        if let Some(name) = name {
            name.encode(&mut self.bytes);
        }
        self.num_added += 1;
        self
    }

    /// Define a global symbol in this symbol table.
    ///
    /// The `name` must be omitted if `index` references an imported table and
    /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
    pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
        SYMTAB_GLOBAL.encode(&mut self.bytes);
        flags.encode(&mut self.bytes);
        index.encode(&mut self.bytes);
        if let Some(name) = name {
            name.encode(&mut self.bytes);
        }
        self.num_added += 1;
        self
    }

    // TODO: tags

    /// Define a table symbol in this symbol table.
    ///
    /// The `name` must be omitted if `index` references an imported table and
    /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
    pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
        SYMTAB_TABLE.encode(&mut self.bytes);
        flags.encode(&mut self.bytes);
        index.encode(&mut self.bytes);
        if let Some(name) = name {
            name.encode(&mut self.bytes);
        }
        self.num_added += 1;
        self
    }

    /// Add a data symbol to this symbol table.
    pub fn data(
        &mut self,
        flags: u32,
        name: &str,
        definition: Option<DataSymbolDefinition>,
    ) -> &mut Self {
        SYMTAB_DATA.encode(&mut self.bytes);
        flags.encode(&mut self.bytes);
        name.encode(&mut self.bytes);
        if let Some(def) = definition {
            def.index.encode(&mut self.bytes);
            def.offset.encode(&mut self.bytes);
            def.size.encode(&mut self.bytes);
        }
        self.num_added += 1;
        self
    }

    // TODO: sections

    /// This is a weak symbol.
    ///
    /// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
    ///
    /// When linking multiple modules defining the same symbol, all weak
    /// definitions are discarded if any strong definitions exist; then if
    /// multiple weak definitions exist all but one (unspecified) are discarded;
    /// and finally it is an error if more than one definition remains.
    pub const WASM_SYM_BINDING_WEAK: u32 = 0x1;

    /// This is a local symbol.
    ///
    /// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`.
    ///
    /// Local symbols are not to be exported, or linked to other
    /// modules/sections. The names of all non-local symbols must be unique, but
    /// the names of local symbols are not considered for uniqueness. A local
    /// function or global symbol cannot reference an import.
    pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02;

    /// This is a hidden symbol.
    ///
    /// Hidden symbols are not to be exported when performing the final link,
    /// but may be linked to other modules.
    pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04;

    /// This symbol is not defined.
    ///
    /// For non-data symbols, this must match whether the symbol is an import or
    /// is defined; for data symbols, determines whether a segment is specified.
    pub const WASM_SYM_UNDEFINED: u32 = 0x10;

    /// This symbol is intended to be exported from the wasm module to the host
    /// environment.
    ///
    /// This differs from the visibility flags in that it effects the static
    /// linker.
    pub const WASM_SYM_EXPORTED: u32 = 0x20;

    /// This symbol uses an explicit symbol name, rather than reusing the name
    /// from a wasm import.
    ///
    /// This allows it to remap imports from foreign WebAssembly modules into
    /// local symbols with different names.
    pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40;

    /// This symbol is intended to be included in the linker output, regardless
    /// of whether it is used by the program.
    pub const WASM_SYM_NO_STRIP: u32 = 0x80;
}

impl Encode for SymbolTable {
    fn encode(&self, sink: &mut Vec<u8>) {
        sink.push(WASM_SYMBOL_TABLE);
        encode_section(sink, self.num_added, &self.bytes);
    }
}

/// The definition of a data symbol within a symbol table.
#[derive(Clone, Debug)]
pub struct DataSymbolDefinition {
    /// The index of the data segment that this symbol is in.
    pub index: u32,
    /// The offset of this symbol within its segment.
    pub offset: u32,
    /// The byte size (which can be zero) of this data symbol.
    ///
    /// Note that `offset + size` must be less than or equal to the segment's
    /// size.
    pub size: u32,
}