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}