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