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