| 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 | |