@@ -17,6 +17,7 @@ use serialize::leb128;
1717
1818// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
1919const WASM_IMPORT_SECTION_ID : u8 = 2 ;
20+ const WASM_CUSTOM_SECTION_ID : u8 = 0 ;
2021
2122const WASM_EXTERNAL_KIND_FUNCTION : u8 = 0 ;
2223const WASM_EXTERNAL_KIND_TABLE : u8 = 1 ;
@@ -121,6 +122,112 @@ pub fn rewrite_imports(path: &Path, import_map: &FxHashMap<String, String>) {
121122 }
122123}
123124
125+ /// Add or augment the existing `producers` section to encode information about
126+ /// the Rust compiler used to produce the wasm file.
127+ pub fn add_producer_section (
128+ path : & Path ,
129+ rust_version : & str ,
130+ rustc_version : & str ,
131+ ) {
132+ struct Field < ' a > {
133+ name : & ' a str ,
134+ values : Vec < FieldValue < ' a > > ,
135+ }
136+
137+ #[ derive( Copy , Clone ) ]
138+ struct FieldValue < ' a > {
139+ name : & ' a str ,
140+ version : & ' a str ,
141+ }
142+
143+ let wasm = fs:: read ( path) . expect ( "failed to read wasm output" ) ;
144+ let mut ret = WasmEncoder :: new ( ) ;
145+ ret. data . extend ( & wasm[ ..8 ] ) ;
146+
147+ // skip the 8 byte wasm/version header
148+ let rustc_value = FieldValue {
149+ name : "rustc" ,
150+ version : rustc_version,
151+ } ;
152+ let rust_value = FieldValue {
153+ name : "Rust" ,
154+ version : rust_version,
155+ } ;
156+ let mut fields = Vec :: new ( ) ;
157+ let mut wrote_rustc = false ;
158+ let mut wrote_rust = false ;
159+
160+ // Move all sections from the original wasm file to our output, skipping
161+ // everything except the producers section
162+ for ( id, raw) in WasmSections ( WasmDecoder :: new ( & wasm[ 8 ..] ) ) {
163+ if id != WASM_CUSTOM_SECTION_ID {
164+ ret. byte ( id) ;
165+ ret. bytes ( raw) ;
166+ continue
167+ }
168+ let mut decoder = WasmDecoder :: new ( raw) ;
169+ if decoder. str ( ) != "producers" {
170+ ret. byte ( id) ;
171+ ret. bytes ( raw) ;
172+ continue
173+ }
174+
175+ // Read off the producers section into our fields outside the loop,
176+ // we'll re-encode the producers section when we're done (to handle an
177+ // entirely missing producers section as well).
178+ info ! ( "rewriting existing producers section" ) ;
179+
180+ for _ in 0 ..decoder. u32 ( ) {
181+ let name = decoder. str ( ) ;
182+ let mut values = Vec :: new ( ) ;
183+ for _ in 0 ..decoder. u32 ( ) {
184+ let name = decoder. str ( ) ;
185+ let version = decoder. str ( ) ;
186+ values. push ( FieldValue { name, version } ) ;
187+ }
188+
189+ if name == "language" {
190+ values. push ( rust_value) ;
191+ wrote_rust = true ;
192+ } else if name == "processed-by" {
193+ values. push ( rustc_value) ;
194+ wrote_rustc = true ;
195+ }
196+ fields. push ( Field { name, values } ) ;
197+ }
198+ }
199+
200+ if !wrote_rust {
201+ fields. push ( Field {
202+ name : "language" ,
203+ values : vec ! [ rust_value] ,
204+ } ) ;
205+ }
206+ if !wrote_rustc {
207+ fields. push ( Field {
208+ name : "processed-by" ,
209+ values : vec ! [ rustc_value] ,
210+ } ) ;
211+ }
212+
213+ // Append the producers section to the end of the wasm file.
214+ let mut section = WasmEncoder :: new ( ) ;
215+ section. str ( "producers" ) ;
216+ section. u32 ( fields. len ( ) as u32 ) ;
217+ for field in fields {
218+ section. str ( field. name ) ;
219+ section. u32 ( field. values . len ( ) as u32 ) ;
220+ for value in field. values {
221+ section. str ( value. name ) ;
222+ section. str ( value. version ) ;
223+ }
224+ }
225+ ret. byte ( WASM_CUSTOM_SECTION_ID ) ;
226+ ret. bytes ( & section. data ) ;
227+
228+ fs:: write ( path, & ret. data ) . expect ( "failed to write wasm output" ) ;
229+ }
230+
124231struct WasmSections < ' a > ( WasmDecoder < ' a > ) ;
125232
126233impl < ' a > Iterator for WasmSections < ' a > {
0 commit comments