1 | use std::borrow::Cow; |
2 | |
3 | use crate::{encode_section, CustomSection, Encode, Section, SectionId}; |
4 | |
5 | const 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)] |
43 | pub struct LinkingSection { |
44 | bytes: Vec<u8>, |
45 | } |
46 | |
47 | impl 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 | |
66 | impl 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 | |
74 | impl 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 | |
84 | impl Section for LinkingSection { |
85 | fn id(&self) -> u8 { |
86 | SectionId::Custom.into() |
87 | } |
88 | } |
89 | |
90 | #[allow (unused)] |
91 | const WASM_SEGMENT_INFO: u8 = 5; |
92 | #[allow (unused)] |
93 | const WASM_INIT_FUNCS: u8 = 6; |
94 | #[allow (unused)] |
95 | const WASM_COMDAT_INFO: u8 = 7; |
96 | const 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)] |
102 | pub struct SymbolTable { |
103 | bytes: Vec<u8>, |
104 | num_added: u32, |
105 | } |
106 | |
107 | const SYMTAB_FUNCTION: u32 = 0; |
108 | const SYMTAB_DATA: u32 = 1; |
109 | const SYMTAB_GLOBAL: u32 = 2; |
110 | #[allow (unused)] |
111 | const SYMTAB_SECTION: u32 = 3; |
112 | #[allow (unused)] |
113 | const SYMTAB_TAG: u32 = 4; |
114 | const SYMTAB_TABLE: u32 = 5; |
115 | |
116 | impl 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 | |
244 | impl 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)] |
253 | pub 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 | |