1 | use crate::prelude::*; |
2 | use crate::{ |
3 | BinaryReader, BinaryReaderError, FromReader, Result, SectionLimited, Subsection, Subsections, |
4 | }; |
5 | use core::ops::Range; |
6 | |
7 | bitflags::bitflags! { |
8 | /// Flags for WebAssembly symbols. |
9 | /// |
10 | /// These flags correspond to those described in |
11 | /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md> |
12 | /// with the `WASM_SYM_*` prefix. |
13 | #[repr (transparent)] |
14 | #[derive (Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
15 | pub struct SymbolFlags: u32 { |
16 | /* N.B.: |
17 | Newly added flags should be keep in sync with `print_dylink0_flags` |
18 | in `crates/wasmprinter/src/lib.rs`. |
19 | */ |
20 | /// This is a weak symbol. |
21 | const BINDING_WEAK = 1 << 0; |
22 | /// This is a local symbol (this is exclusive with [BINDING_WEAK]). |
23 | const BINDING_LOCAL = 1 << 1; |
24 | /// This is a hidden symbol. |
25 | const VISIBILITY_HIDDEN = 1 << 2; |
26 | /// This symbol is not defined. |
27 | const UNDEFINED = 1 << 4; |
28 | /// This symbol is intended to be exported from the wasm module to the host environment. |
29 | const EXPORTED = 1 << 5; |
30 | /// This symbol uses an explicit symbol name, rather than reusing the name from a wasm import. |
31 | const EXPLICIT_NAME = 1 << 6; |
32 | /// This symbol is intended to be included in the linker output, regardless of whether it is used by the program. |
33 | const NO_STRIP = 1 << 7; |
34 | /// This symbol resides in thread local storage. |
35 | const TLS = 1 << 8; |
36 | /// This symbol represents an absolute address. |
37 | const ABSOLUTE = 1 << 9; |
38 | } |
39 | |
40 | /// Flags for WebAssembly segments. |
41 | /// |
42 | /// These flags are defined by implementation at the time of writing: |
43 | /// <https://github.com/llvm/llvm-project/blob/llvmorg-17.0.6/llvm/include/llvm/BinaryFormat/Wasm.h#L391-L394> |
44 | #[repr (transparent)] |
45 | #[derive (Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] |
46 | pub struct SegmentFlags: u32 { |
47 | /// The segment contains only null-terminated strings, which allows the linker to perform merging. |
48 | const STRINGS = 0x1; |
49 | /// The segment contains thread-local data. |
50 | const TLS = 0x2; |
51 | } |
52 | } |
53 | |
54 | impl<'a> FromReader<'a> for SymbolFlags { |
55 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
56 | Ok(Self::from_bits_retain(bits:reader.read_var_u32()?)) |
57 | } |
58 | } |
59 | |
60 | impl<'a> FromReader<'a> for SegmentFlags { |
61 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
62 | Ok(Self::from_bits_retain(bits:reader.read_var_u32()?)) |
63 | } |
64 | } |
65 | |
66 | /// A reader for the `linking` custom section of a WebAssembly module. |
67 | /// |
68 | /// This format is currently defined upstream at |
69 | /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md>. |
70 | #[derive (Debug, Clone)] |
71 | pub struct LinkingSectionReader<'a> { |
72 | /// The version of linking metadata contained in this section. |
73 | version: u32, |
74 | /// The subsections in this section. |
75 | subsections: Subsections<'a, Linking<'a>>, |
76 | /// The range of the entire section, including the version. |
77 | range: Range<usize>, |
78 | } |
79 | |
80 | /// Represents a reader for segments from the linking custom section. |
81 | pub type SegmentMap<'a> = SectionLimited<'a, Segment<'a>>; |
82 | |
83 | /// Represents extra metadata about the data segments. |
84 | #[derive (Debug, Copy, Clone)] |
85 | pub struct Segment<'a> { |
86 | /// The name for the segment. |
87 | pub name: &'a str, |
88 | /// The required alignment of the segment, encoded as a power of 2. |
89 | pub alignment: u32, |
90 | /// The flags for the segment. |
91 | pub flags: SegmentFlags, |
92 | } |
93 | |
94 | impl<'a> FromReader<'a> for Segment<'a> { |
95 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
96 | let name: &'a str = reader.read_string()?; |
97 | let alignment: u32 = reader.read_var_u32()?; |
98 | let flags: SegmentFlags = reader.read()?; |
99 | Ok(Self { |
100 | name, |
101 | alignment, |
102 | flags, |
103 | }) |
104 | } |
105 | } |
106 | |
107 | /// Represents a reader for init functions from the linking custom section. |
108 | pub type InitFuncMap<'a> = SectionLimited<'a, InitFunc>; |
109 | |
110 | /// Represents an init function in the linking custom section. |
111 | #[derive (Debug, Copy, Clone)] |
112 | pub struct InitFunc { |
113 | /// The priority of the init function. |
114 | pub priority: u32, |
115 | /// The symbol index of init function (*not* the function index). |
116 | pub symbol_index: u32, |
117 | } |
118 | |
119 | impl<'a> FromReader<'a> for InitFunc { |
120 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
121 | let priority: u32 = reader.read_var_u32()?; |
122 | let symbol_index: u32 = reader.read_var_u32()?; |
123 | Ok(Self { |
124 | priority, |
125 | symbol_index, |
126 | }) |
127 | } |
128 | } |
129 | |
130 | /// Represents a reader for COMDAT data from the linking custom section. |
131 | pub type ComdatMap<'a> = SectionLimited<'a, Comdat<'a>>; |
132 | |
133 | /// Represents [COMDAT](https://llvm.org/docs/LangRef.html#comdats) data in the linking custom section. |
134 | #[derive (Debug, Clone)] |
135 | pub struct Comdat<'a> { |
136 | /// The name of this comdat. |
137 | pub name: &'a str, |
138 | /// The flags. |
139 | pub flags: u32, |
140 | /// The member symbols of this comdat. |
141 | pub symbols: SectionLimited<'a, ComdatSymbol>, |
142 | } |
143 | |
144 | impl<'a> FromReader<'a> for Comdat<'a> { |
145 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
146 | let name: &'a str = reader.read_string()?; |
147 | let flags: u32 = reader.read_var_u32()?; |
148 | // FIXME(#188) ideally shouldn't need to skip here |
149 | let symbols: BinaryReader<'a> = reader.skip(|reader: &mut BinaryReader<'a>| { |
150 | let count: u32 = reader.read_var_u32()?; |
151 | for _ in 0..count { |
152 | reader.read::<ComdatSymbol>()?; |
153 | } |
154 | Ok(()) |
155 | })?; |
156 | Ok(Self { |
157 | name, |
158 | flags, |
159 | symbols: SectionLimited::new(reader:symbols)?, |
160 | }) |
161 | } |
162 | } |
163 | |
164 | /// Represents a symbol that is part of a comdat. |
165 | #[derive (Debug, Copy, Clone)] |
166 | pub struct ComdatSymbol { |
167 | /// The kind of the symbol. |
168 | pub kind: ComdatSymbolKind, |
169 | /// The index of the symbol. Must not be an import. |
170 | pub index: u32, |
171 | } |
172 | |
173 | impl<'a> FromReader<'a> for ComdatSymbol { |
174 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
175 | let kind: ComdatSymbolKind = reader.read()?; |
176 | let index: u32 = reader.read_var_u32()?; |
177 | Ok(Self { kind, index }) |
178 | } |
179 | } |
180 | |
181 | /// Represents a symbol kind. |
182 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
183 | pub enum ComdatSymbolKind { |
184 | /// The symbol is a data segment. |
185 | Data, |
186 | /// The symbol is a function. |
187 | Func, |
188 | /// The symbol is a global. |
189 | Global, |
190 | /// The symbol is an event. |
191 | Event, |
192 | /// The symbol is a table. |
193 | Table, |
194 | /// The symbol is a section. |
195 | Section, |
196 | } |
197 | |
198 | impl<'a> FromReader<'a> for ComdatSymbolKind { |
199 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
200 | let offset: usize = reader.original_position(); |
201 | match reader.read_u8()? { |
202 | 0 => Ok(Self::Data), |
203 | 1 => Ok(Self::Func), |
204 | 2 => Ok(Self::Global), |
205 | 3 => Ok(Self::Event), |
206 | 4 => Ok(Self::Table), |
207 | 5 => Ok(Self::Section), |
208 | k: u8 => Err(BinaryReader::invalid_leading_byte_error( |
209 | byte:k, |
210 | desc:"comdat symbol kind" , |
211 | offset, |
212 | )), |
213 | } |
214 | } |
215 | } |
216 | |
217 | /// Represents a reader for symbol info from the linking custom section. |
218 | pub type SymbolInfoMap<'a> = SectionLimited<'a, SymbolInfo<'a>>; |
219 | |
220 | /// Represents extra information about symbols in the linking custom section. |
221 | /// |
222 | /// The symbol flags correspond to those described in |
223 | /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md> |
224 | /// with the `WASM_SYM_*` prefix. |
225 | #[derive (Debug, Copy, Clone)] |
226 | pub enum SymbolInfo<'a> { |
227 | /// The symbol is a function. |
228 | Func { |
229 | /// The flags for the symbol. |
230 | flags: SymbolFlags, |
231 | /// The index of the function corresponding to this symbol. |
232 | index: u32, |
233 | /// The name for the function, if it is defined or uses an explicit name. |
234 | name: Option<&'a str>, |
235 | }, |
236 | /// The symbol is a data symbol. |
237 | Data { |
238 | /// The flags for the symbol. |
239 | flags: SymbolFlags, |
240 | /// The name for the symbol. |
241 | name: &'a str, |
242 | /// The definition of the data symbol, if it is defined. |
243 | symbol: Option<DefinedDataSymbol>, |
244 | }, |
245 | /// The symbol is a global. |
246 | Global { |
247 | /// The flags for the symbol. |
248 | flags: SymbolFlags, |
249 | /// The index of the global corresponding to this symbol. |
250 | index: u32, |
251 | /// The name for the global, if it is defined or uses an explicit name. |
252 | name: Option<&'a str>, |
253 | }, |
254 | /// The symbol is a section. |
255 | Section { |
256 | /// The flags for the symbol. |
257 | flags: SymbolFlags, |
258 | /// The index of the function corresponding to this symbol. |
259 | section: u32, |
260 | }, |
261 | /// The symbol is an event. |
262 | Event { |
263 | /// The flags for the symbol. |
264 | flags: SymbolFlags, |
265 | /// The index of the event corresponding to this symbol. |
266 | index: u32, |
267 | /// The name for the event, if it is defined or uses an explicit name. |
268 | name: Option<&'a str>, |
269 | }, |
270 | /// The symbol is a table. |
271 | Table { |
272 | /// The flags for the symbol. |
273 | flags: SymbolFlags, |
274 | /// The index of the table corresponding to this symbol. |
275 | index: u32, |
276 | /// The name for the table, if it is defined or uses an explicit name. |
277 | name: Option<&'a str>, |
278 | }, |
279 | } |
280 | |
281 | impl<'a> FromReader<'a> for SymbolInfo<'a> { |
282 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
283 | let offset = reader.original_position(); |
284 | let kind = reader.read_u8()?; |
285 | let flags: SymbolFlags = reader.read()?; |
286 | |
287 | let defined = !flags.contains(SymbolFlags::UNDEFINED); |
288 | let explicit_name = flags.contains(SymbolFlags::EXPLICIT_NAME); |
289 | |
290 | const SYMTAB_FUNCTION: u8 = 0; |
291 | const SYMTAB_DATA: u8 = 1; |
292 | const SYMTAB_GLOBAL: u8 = 2; |
293 | const SYMTAB_SECTION: u8 = 3; |
294 | const SYMTAB_EVENT: u8 = 4; |
295 | const SYMTAB_TABLE: u8 = 5; |
296 | |
297 | // https://github.com/WebAssembly/wabt/blob/1.0.34/src/binary-writer.cc#L1226 |
298 | match kind { |
299 | SYMTAB_FUNCTION | SYMTAB_GLOBAL | SYMTAB_EVENT | SYMTAB_TABLE => { |
300 | let index = reader.read_var_u32()?; |
301 | let name = match defined || explicit_name { |
302 | true => Some(reader.read_string()?), |
303 | false => None, |
304 | }; |
305 | Ok(match kind { |
306 | SYMTAB_FUNCTION => Self::Func { flags, index, name }, |
307 | SYMTAB_GLOBAL => Self::Global { flags, index, name }, |
308 | SYMTAB_EVENT => Self::Event { flags, index, name }, |
309 | SYMTAB_TABLE => Self::Table { flags, index, name }, |
310 | _ => unreachable!(), |
311 | }) |
312 | } |
313 | SYMTAB_DATA => { |
314 | let name = reader.read_string()?; |
315 | let data = match defined { |
316 | true => Some(reader.read()?), |
317 | false => None, |
318 | }; |
319 | Ok(Self::Data { |
320 | flags, |
321 | name, |
322 | symbol: data, |
323 | }) |
324 | } |
325 | SYMTAB_SECTION => { |
326 | let section = reader.read_var_u32()?; |
327 | Ok(Self::Section { flags, section }) |
328 | } |
329 | k => Err(BinaryReader::invalid_leading_byte_error( |
330 | k, |
331 | "symbol kind" , |
332 | offset, |
333 | )), |
334 | } |
335 | } |
336 | } |
337 | |
338 | /// Represents the metadata about a data symbol defined in the wasm file. |
339 | #[derive (Debug, Copy, Clone)] |
340 | pub struct DefinedDataSymbol { |
341 | /// The index of the data segment. |
342 | pub index: u32, |
343 | /// The offset within the segment. Must be <= the segment's size. |
344 | pub offset: u32, |
345 | /// The size of the data, which can be zero. `offset + size` must be <= the segment's size. |
346 | pub size: u32, |
347 | } |
348 | |
349 | impl<'a> FromReader<'a> for DefinedDataSymbol { |
350 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
351 | let index: u32 = reader.read_var_u32()?; |
352 | let offset: u32 = reader.read_var_u32()?; |
353 | let size: u32 = reader.read_var_u32()?; |
354 | Ok(Self { |
355 | index, |
356 | offset, |
357 | size, |
358 | }) |
359 | } |
360 | } |
361 | |
362 | /// Represents a subsection read from the linking custom section. |
363 | #[derive (Debug, Clone)] |
364 | pub enum Linking<'a> { |
365 | /// Extra metadata about the data segments. |
366 | SegmentInfo(SegmentMap<'a>), |
367 | /// A list of constructor functions to be called at startup. |
368 | InitFuncs(InitFuncMap<'a>), |
369 | /// The [COMDAT](https://llvm.org/docs/LangRef.html#comdats) groups of associated linking objects. |
370 | ComdatInfo(ComdatMap<'a>), |
371 | /// Extra information about the symbols present in the module. |
372 | SymbolTable(SymbolInfoMap<'a>), |
373 | /// An unknown [linking subsection](https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#linking-metadata-section). |
374 | Unknown { |
375 | /// The identifier for this subsection. |
376 | ty: u8, |
377 | /// The contents of this subsection. |
378 | data: &'a [u8], |
379 | /// The range of bytes, relative to the start of the original data |
380 | /// stream, that the contents of this subsection reside in. |
381 | range: Range<usize>, |
382 | }, |
383 | } |
384 | |
385 | impl<'a> Subsection<'a> for Linking<'a> { |
386 | fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result<Self> { |
387 | let data: &[u8] = reader.remaining_buffer(); |
388 | let offset: usize = reader.original_position(); |
389 | Ok(match id { |
390 | 5 => Self::SegmentInfo(SegmentMap::new(reader)?), |
391 | 6 => Self::InitFuncs(InitFuncMap::new(reader)?), |
392 | 7 => Self::ComdatInfo(ComdatMap::new(reader)?), |
393 | 8 => Self::SymbolTable(SymbolInfoMap::new(reader)?), |
394 | ty: u8 => Self::Unknown { |
395 | ty, |
396 | data, |
397 | range: offset..offset + data.len(), |
398 | }, |
399 | }) |
400 | } |
401 | } |
402 | |
403 | impl<'a> LinkingSectionReader<'a> { |
404 | /// Creates a new reader for the linking section contents starting at |
405 | /// `offset` within the original wasm file. |
406 | pub fn new(mut reader: BinaryReader<'a>) -> Result<Self> { |
407 | let range = reader.range(); |
408 | let offset = reader.original_position(); |
409 | |
410 | let version = reader.read_var_u32()?; |
411 | if version != 2 { |
412 | return Err(BinaryReaderError::new( |
413 | format!("unsupported linking section version: {}" , version), |
414 | offset, |
415 | )); |
416 | } |
417 | |
418 | let subsections = Subsections::new(reader.shrink()); |
419 | Ok(Self { |
420 | version, |
421 | subsections, |
422 | range, |
423 | }) |
424 | } |
425 | |
426 | /// Returns the version of linking metadata contained in this section. |
427 | pub fn version(&self) -> u32 { |
428 | self.version |
429 | } |
430 | |
431 | /// Returns the original byte offset of this section. |
432 | pub fn original_position(&self) -> usize { |
433 | self.subsections.original_position() |
434 | } |
435 | |
436 | /// Returns the range, as byte offsets, of this section within the original |
437 | /// wasm binary. |
438 | pub fn range(&self) -> Range<usize> { |
439 | self.range.clone() |
440 | } |
441 | |
442 | /// Returns the iterator for advancing through the subsections. |
443 | /// |
444 | /// You can also use [`IntoIterator::into_iter`] directly on this type. |
445 | pub fn subsections(&self) -> Subsections<'a, Linking<'a>> { |
446 | self.subsections.clone() |
447 | } |
448 | } |
449 | |
450 | impl<'a> IntoIterator for LinkingSectionReader<'a> { |
451 | type Item = Result<Linking<'a>>; |
452 | type IntoIter = Subsections<'a, Linking<'a>>; |
453 | |
454 | fn into_iter(self) -> Self::IntoIter { |
455 | self.subsections |
456 | } |
457 | } |
458 | |