wasm_encoder/core/linking.rs
1use crate::{CustomSection, Encode, Section, SectionId, encode_section};
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 /// Add a target architecture subsection, e.g. `"wasm32"` or `"wasm64"`.
67 pub fn target_arch(&mut self, arch: &str) -> &mut Self {
68 self.bytes.push(WASM_TARGET_ARCH);
69 let mut subsection = Vec::new();
70 arch.encode(&mut subsection);
71 subsection.as_slice().encode(&mut self.bytes);
72 self
73 }
74}
75
76impl Default for LinkingSection {
77 fn default() -> Self {
78 let mut bytes = Vec::new();
79 VERSION.encode(&mut bytes);
80 Self { bytes }
81 }
82}
83
84impl Encode for LinkingSection {
85 fn encode(&self, sink: &mut Vec<u8>) {
86 CustomSection {
87 name: "linking".into(),
88 data: Cow::Borrowed(&self.bytes),
89 }
90 .encode(sink);
91 }
92}
93
94impl Section for LinkingSection {
95 fn id(&self) -> u8 {
96 SectionId::Custom.into()
97 }
98}
99
100#[allow(unused)]
101const WASM_SEGMENT_INFO: u8 = 5;
102#[allow(unused)]
103const WASM_INIT_FUNCS: u8 = 6;
104#[allow(unused)]
105const WASM_COMDAT_INFO: u8 = 7;
106const WASM_SYMBOL_TABLE: u8 = 8;
107const WASM_TARGET_ARCH: u8 = 9;
108
109/// A subsection of the [linking custom section][crate::LinkingSection] that
110/// provides extra information about the symbols present in this Wasm object
111/// file.
112#[derive(Clone, Debug, Default)]
113pub struct SymbolTable {
114 bytes: Vec<u8>,
115 num_added: u32,
116}
117
118const SYMTAB_FUNCTION: u32 = 0;
119const SYMTAB_DATA: u32 = 1;
120const SYMTAB_GLOBAL: u32 = 2;
121#[allow(unused)]
122const SYMTAB_SECTION: u32 = 3;
123#[allow(unused)]
124const SYMTAB_TAG: u32 = 4;
125const SYMTAB_TABLE: u32 = 5;
126
127impl SymbolTable {
128 /// Construct a new symbol table subsection encoder.
129 pub fn new() -> Self {
130 SymbolTable {
131 bytes: vec![],
132 num_added: 0,
133 }
134 }
135
136 /// Define a function symbol in this symbol table.
137 ///
138 /// The `name` must be omitted if `index` references an imported table and
139 /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
140 pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
141 SYMTAB_FUNCTION.encode(&mut self.bytes);
142 flags.encode(&mut self.bytes);
143 index.encode(&mut self.bytes);
144 if let Some(name) = name {
145 name.encode(&mut self.bytes);
146 }
147 self.num_added += 1;
148 self
149 }
150
151 /// Define a global symbol in this symbol table.
152 ///
153 /// The `name` must be omitted if `index` references an imported table and
154 /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
155 pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
156 SYMTAB_GLOBAL.encode(&mut self.bytes);
157 flags.encode(&mut self.bytes);
158 index.encode(&mut self.bytes);
159 if let Some(name) = name {
160 name.encode(&mut self.bytes);
161 }
162 self.num_added += 1;
163 self
164 }
165
166 // TODO: tags
167
168 /// Define a table symbol in this symbol table.
169 ///
170 /// The `name` must be omitted if `index` references an imported table and
171 /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
172 pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
173 SYMTAB_TABLE.encode(&mut self.bytes);
174 flags.encode(&mut self.bytes);
175 index.encode(&mut self.bytes);
176 if let Some(name) = name {
177 name.encode(&mut self.bytes);
178 }
179 self.num_added += 1;
180 self
181 }
182
183 /// Add a data symbol to this symbol table.
184 pub fn data(
185 &mut self,
186 flags: u32,
187 name: &str,
188 definition: Option<DataSymbolDefinition>,
189 ) -> &mut Self {
190 SYMTAB_DATA.encode(&mut self.bytes);
191 flags.encode(&mut self.bytes);
192 name.encode(&mut self.bytes);
193 if let Some(def) = definition {
194 def.index.encode(&mut self.bytes);
195 def.offset.encode(&mut self.bytes);
196 def.size.encode(&mut self.bytes);
197 }
198 self.num_added += 1;
199 self
200 }
201
202 // TODO: sections
203
204 /// This is a weak symbol.
205 ///
206 /// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
207 ///
208 /// When linking multiple modules defining the same symbol, all weak
209 /// definitions are discarded if any strong definitions exist; then if
210 /// multiple weak definitions exist all but one (unspecified) are discarded;
211 /// and finally it is an error if more than one definition remains.
212 pub const WASM_SYM_BINDING_WEAK: u32 = 0x1;
213
214 /// This is a local symbol.
215 ///
216 /// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`.
217 ///
218 /// Local symbols are not to be exported, or linked to other
219 /// modules/sections. The names of all non-local symbols must be unique, but
220 /// the names of local symbols are not considered for uniqueness. A local
221 /// function or global symbol cannot reference an import.
222 pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02;
223
224 /// This is a hidden symbol.
225 ///
226 /// Hidden symbols are not to be exported when performing the final link,
227 /// but may be linked to other modules.
228 pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04;
229
230 /// This symbol is not defined.
231 ///
232 /// For non-data symbols, this must match whether the symbol is an import or
233 /// is defined; for data symbols, determines whether a segment is specified.
234 pub const WASM_SYM_UNDEFINED: u32 = 0x10;
235
236 /// This symbol is intended to be exported from the wasm module to the host
237 /// environment.
238 ///
239 /// This differs from the visibility flags in that it effects the static
240 /// linker.
241 pub const WASM_SYM_EXPORTED: u32 = 0x20;
242
243 /// This symbol uses an explicit symbol name, rather than reusing the name
244 /// from a wasm import.
245 ///
246 /// This allows it to remap imports from foreign WebAssembly modules into
247 /// local symbols with different names.
248 pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40;
249
250 /// This symbol is intended to be included in the linker output, regardless
251 /// of whether it is used by the program.
252 pub const WASM_SYM_NO_STRIP: u32 = 0x80;
253}
254
255impl Encode for SymbolTable {
256 fn encode(&self, sink: &mut Vec<u8>) {
257 sink.push(WASM_SYMBOL_TABLE);
258 encode_section(sink, self.num_added, &self.bytes);
259 }
260}
261
262/// The definition of a data symbol within a symbol table.
263#[derive(Clone, Debug)]
264pub struct DataSymbolDefinition {
265 /// The index of the data segment that this symbol is in.
266 pub index: u32,
267 /// The offset of this symbol within its segment.
268 pub offset: u32,
269 /// The byte size (which can be zero) of this data symbol.
270 ///
271 /// Note that `offset + size` must be less than or equal to the segment's
272 /// size.
273 pub size: u32,
274}