]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/back/wasm.rs
Auto merge of #58741 - varkor:lang-lib-feature-shared-name, r=alexreg
[rust.git] / src / librustc_codegen_llvm / back / wasm.rs
1 use std::fs;
2 use std::path::Path;
3 use std::str;
4
5 use rustc_data_structures::fx::FxHashMap;
6 use serialize::leb128;
7
8 // https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
9 const WASM_IMPORT_SECTION_ID: u8 = 2;
10 const WASM_CUSTOM_SECTION_ID: u8 = 0;
11
12 const WASM_EXTERNAL_KIND_FUNCTION: u8 = 0;
13 const WASM_EXTERNAL_KIND_TABLE: u8 = 1;
14 const WASM_EXTERNAL_KIND_MEMORY: u8 = 2;
15 const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3;
16
17 /// Rewrite the module imports are listed from in a wasm module given the field
18 /// name to module name mapping in `import_map`.
19 ///
20 /// LLVM 6 which we're using right now doesn't have the ability to configure the
21 /// module a wasm symbol is import from. Rather all imported symbols come from
22 /// the bland `"env"` module unconditionally. Furthermore we'd *also* need
23 /// support in LLD for preserving these import modules, which it unfortunately
24 /// currently does not.
25 ///
26 /// This function is intended as a hack for now where we manually rewrite the
27 /// wasm output by LLVM to have the correct import modules listed. The
28 /// `#[link(wasm_import_module = "...")]` attribute in Rust translates to the
29 /// module that each symbol is imported from, so here we manually go through the
30 /// wasm file, decode it, rewrite imports, and then rewrite the wasm module.
31 ///
32 /// Support for this was added to LLVM in
33 /// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still
34 /// needs to be added, tracked at https://bugs.llvm.org/show_bug.cgi?id=37168
35 pub fn rewrite_imports(path: &Path, import_map: &FxHashMap<String, String>) {
36     if import_map.is_empty() {
37         return
38     }
39
40     let wasm = fs::read(path).expect("failed to read wasm output");
41     let mut ret = WasmEncoder::new();
42     ret.data.extend(&wasm[..8]);
43
44     // skip the 8 byte wasm/version header
45     for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) {
46         ret.byte(id);
47         if id == WASM_IMPORT_SECTION_ID {
48             info!("rewriting import section");
49             let data = rewrite_import_section(
50                 &mut WasmDecoder::new(raw),
51                 import_map,
52             );
53             ret.bytes(&data);
54         } else {
55             info!("carry forward section {}, {} bytes long", id, raw.len());
56             ret.bytes(raw);
57         }
58     }
59
60     fs::write(path, &ret.data).expect("failed to write wasm output");
61
62     fn rewrite_import_section(
63         wasm: &mut WasmDecoder<'_>,
64         import_map: &FxHashMap<String, String>,
65     )
66         -> Vec<u8>
67     {
68         let mut dst = WasmEncoder::new();
69         let n = wasm.u32();
70         dst.u32(n);
71         info!("rewriting {} imports", n);
72         for _ in 0..n {
73             rewrite_import_entry(wasm, &mut dst, import_map);
74         }
75         return dst.data
76     }
77
78     fn rewrite_import_entry(wasm: &mut WasmDecoder<'_>,
79                             dst: &mut WasmEncoder,
80                             import_map: &FxHashMap<String, String>) {
81         // More info about the binary format here is available at:
82         // https://webassembly.github.io/spec/core/binary/modules.html#import-section
83         //
84         // Note that you can also find the whole point of existence of this
85         // function here, where we map the `module` name to a different one if
86         // we've got one listed.
87         let module = wasm.str();
88         let field = wasm.str();
89         let new_module = if module == "env" {
90             import_map.get(field).map(|s| &**s).unwrap_or(module)
91         } else {
92             module
93         };
94         info!("import rewrite ({} => {}) / {}", module, new_module, field);
95         dst.str(new_module);
96         dst.str(field);
97         let kind = wasm.byte();
98         dst.byte(kind);
99         match kind {
100             WASM_EXTERNAL_KIND_FUNCTION => dst.u32(wasm.u32()),
101             WASM_EXTERNAL_KIND_TABLE => {
102                 dst.byte(wasm.byte()); // element_type
103                 dst.limits(wasm.limits());
104             }
105             WASM_EXTERNAL_KIND_MEMORY => dst.limits(wasm.limits()),
106             WASM_EXTERNAL_KIND_GLOBAL => {
107                 dst.byte(wasm.byte()); // content_type
108                 dst.bool(wasm.bool()); // mutable
109             }
110             b => panic!("unknown kind: {}", b),
111         }
112     }
113 }
114
115 /// Adds or augment the existing `producers` section to encode information about
116 /// the Rust compiler used to produce the wasm file.
117 pub fn add_producer_section(
118     path: &Path,
119     rust_version: &str,
120     rustc_version: &str,
121 ) {
122     struct Field<'a> {
123         name: &'a str,
124         values: Vec<FieldValue<'a>>,
125     }
126
127     #[derive(Copy, Clone)]
128     struct FieldValue<'a> {
129         name: &'a str,
130         version: &'a str,
131     }
132
133     let wasm = fs::read(path).expect("failed to read wasm output");
134     let mut ret = WasmEncoder::new();
135     ret.data.extend(&wasm[..8]);
136
137     // skip the 8 byte wasm/version header
138     let rustc_value = FieldValue {
139         name: "rustc",
140         version: rustc_version,
141     };
142     let rust_value = FieldValue {
143         name: "Rust",
144         version: rust_version,
145     };
146     let mut fields = Vec::new();
147     let mut wrote_rustc = false;
148     let mut wrote_rust = false;
149
150     // Move all sections from the original wasm file to our output, skipping
151     // everything except the producers section
152     for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) {
153         if id != WASM_CUSTOM_SECTION_ID {
154             ret.byte(id);
155             ret.bytes(raw);
156             continue
157         }
158         let mut decoder = WasmDecoder::new(raw);
159         if decoder.str() != "producers" {
160             ret.byte(id);
161             ret.bytes(raw);
162             continue
163         }
164
165         // Read off the producers section into our fields outside the loop,
166         // we'll re-encode the producers section when we're done (to handle an
167         // entirely missing producers section as well).
168         info!("rewriting existing producers section");
169
170         for _ in 0..decoder.u32() {
171             let name = decoder.str();
172             let mut values = Vec::new();
173             for _ in 0..decoder.u32() {
174                 let name = decoder.str();
175                 let version = decoder.str();
176                 values.push(FieldValue { name, version });
177             }
178
179             if name == "language" {
180                 values.push(rust_value);
181                 wrote_rust = true;
182             } else if name == "processed-by" {
183                 values.push(rustc_value);
184                 wrote_rustc = true;
185             }
186             fields.push(Field { name, values });
187         }
188     }
189
190     if !wrote_rust {
191         fields.push(Field {
192             name: "language",
193             values: vec![rust_value],
194         });
195     }
196     if !wrote_rustc {
197         fields.push(Field {
198             name: "processed-by",
199             values: vec![rustc_value],
200         });
201     }
202
203     // Append the producers section to the end of the wasm file.
204     let mut section = WasmEncoder::new();
205     section.str("producers");
206     section.u32(fields.len() as u32);
207     for field in fields {
208         section.str(field.name);
209         section.u32(field.values.len() as u32);
210         for value in field.values {
211             section.str(value.name);
212             section.str(value.version);
213         }
214     }
215     ret.byte(WASM_CUSTOM_SECTION_ID);
216     ret.bytes(&section.data);
217
218     fs::write(path, &ret.data).expect("failed to write wasm output");
219 }
220
221 struct WasmSections<'a>(WasmDecoder<'a>);
222
223 impl<'a> Iterator for WasmSections<'a> {
224     type Item = (u8, &'a [u8]);
225
226     fn next(&mut self) -> Option<(u8, &'a [u8])> {
227         if self.0.data.is_empty() {
228             return None
229         }
230
231         // see https://webassembly.github.io/spec/core/binary/modules.html#sections
232         let id = self.0.byte();
233         let section_len = self.0.u32();
234         info!("new section {} / {} bytes", id, section_len);
235         let section = self.0.skip(section_len as usize);
236         Some((id, section))
237     }
238 }
239
240 struct WasmDecoder<'a> {
241     data: &'a [u8],
242 }
243
244 impl<'a> WasmDecoder<'a> {
245     fn new(data: &'a [u8]) -> WasmDecoder<'a> {
246         WasmDecoder { data }
247     }
248
249     fn byte(&mut self) -> u8 {
250         self.skip(1)[0]
251     }
252
253     fn u32(&mut self) -> u32 {
254         let (n, l1) = leb128::read_u32_leb128(self.data);
255         self.data = &self.data[l1..];
256         return n
257     }
258
259     fn skip(&mut self, amt: usize) -> &'a [u8] {
260         let (data, rest) = self.data.split_at(amt);
261         self.data = rest;
262         data
263     }
264
265     fn str(&mut self) -> &'a str {
266         let len = self.u32();
267         str::from_utf8(self.skip(len as usize)).unwrap()
268     }
269
270     fn bool(&mut self) -> bool {
271         self.byte() == 1
272     }
273
274     fn limits(&mut self) -> (u32, Option<u32>) {
275         let has_max = self.bool();
276         (self.u32(), if has_max { Some(self.u32()) } else { None })
277     }
278 }
279
280 struct WasmEncoder {
281     data: Vec<u8>,
282 }
283
284 impl WasmEncoder {
285     fn new() -> WasmEncoder {
286         WasmEncoder { data: Vec::new() }
287     }
288
289     fn u32(&mut self, val: u32) {
290         leb128::write_u32_leb128(&mut self.data, val);
291     }
292
293     fn byte(&mut self, val: u8) {
294         self.data.push(val);
295     }
296
297     fn bytes(&mut self, val: &[u8]) {
298         self.u32(val.len() as u32);
299         self.data.extend_from_slice(val);
300     }
301
302     fn str(&mut self, val: &str) {
303         self.bytes(val.as_bytes())
304     }
305
306     fn bool(&mut self, b: bool) {
307         self.byte(b as u8);
308     }
309
310     fn limits(&mut self, limits: (u32, Option<u32>)) {
311         self.bool(limits.1.is_some());
312         self.u32(limits.0);
313         if let Some(c) = limits.1 {
314             self.u32(c);
315         }
316     }
317 }