@@ -15,6 +15,7 @@ use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
15
15
use rustc_metadata:: creader:: MetadataLoader ;
16
16
use rustc_metadata:: fs:: METADATA_FILENAME ;
17
17
use rustc_metadata:: EncodedMetadata ;
18
+ use rustc_serialize:: leb128;
18
19
use rustc_session:: Session ;
19
20
use rustc_span:: sym;
20
21
use rustc_target:: abi:: Endian ;
@@ -420,10 +421,9 @@ pub enum MetadataPosition {
420
421
/// it's not in an allowlist of otherwise well known dwarf section names to
421
422
/// go into the final artifact.
422
423
///
423
- /// * WebAssembly - we actually don't have any container format for this
424
- /// target. WebAssembly doesn't support the `dylib` crate type anyway so
425
- /// there's no need for us to support this at this time. Consequently the
426
- /// metadata bytes are simply stored as-is into an rlib.
424
+ /// * WebAssembly - this uses wasm files themselves as the object file format
425
+ /// so an empty file with no linking metadata but a single custom section is
426
+ /// created holding our metadata.
427
427
///
428
428
/// * COFF - Windows-like targets create an object with a section that has
429
429
/// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
@@ -438,22 +438,13 @@ pub fn create_wrapper_file(
438
438
data : & [ u8 ] ,
439
439
) -> ( Vec < u8 > , MetadataPosition ) {
440
440
let Some ( mut file) = create_object_file ( sess) else {
441
- // This is used to handle all "other" targets. This includes targets
442
- // in two categories:
443
- //
444
- // * Some targets don't have support in the `object` crate just yet
445
- // to write an object file. These targets are likely to get filled
446
- // out over time.
447
- //
448
- // * Targets like WebAssembly don't support dylibs, so the purpose
449
- // of putting metadata in object files, to support linking rlibs
450
- // into dylibs, is moot.
451
- //
452
- // In both of these cases it means that linking into dylibs will
453
- // not be supported by rustc. This doesn't matter for targets like
454
- // WebAssembly and for targets not supported by the `object` crate
455
- // yet it means that work will need to be done in the `object` crate
456
- // to add a case above.
441
+ if sess. target . is_like_wasm {
442
+ return ( create_metadata_file_for_wasm ( data, & section_name) , MetadataPosition :: First ) ;
443
+ }
444
+
445
+ // Targets using this branch don't have support implemented here yet or
446
+ // they're not yet implemented in the `object` crate and will likely
447
+ // fill out this module over time.
457
448
return ( data. to_vec ( ) , MetadataPosition :: Last ) ;
458
449
} ;
459
450
let section = if file. format ( ) == BinaryFormat :: Xcoff {
@@ -532,6 +523,9 @@ pub fn create_compressed_metadata_file(
532
523
packed_metadata. extend ( metadata. raw_data ( ) ) ;
533
524
534
525
let Some ( mut file) = create_object_file ( sess) else {
526
+ if sess. target . is_like_wasm {
527
+ return create_metadata_file_for_wasm ( & packed_metadata, b".rustc" ) ;
528
+ }
535
529
return packed_metadata. to_vec ( ) ;
536
530
} ;
537
531
if file. format ( ) == BinaryFormat :: Xcoff {
@@ -624,3 +618,57 @@ pub fn create_compressed_metadata_file_for_xcoff(
624
618
file. append_section_data ( section, data, 1 ) ;
625
619
file. write ( ) . unwrap ( )
626
620
}
621
+
622
+ /// Creates a simple WebAssembly object file, which is itself a wasm module,
623
+ /// that contains a custom section of the name `section_name` with contents
624
+ /// `data`.
625
+ ///
626
+ /// NB: the `object` crate does not yet have support for writing the the wasm
627
+ /// object file format. The format is simple enough that for now an extra crate
628
+ /// from crates.io (such as `wasm-encoder`). The file format is:
629
+ ///
630
+ /// * 4-byte header "\0asm"
631
+ /// * 4-byte version number - 1u32 in little-endian format
632
+ /// * concatenated sections, which for this object is always "custom sections"
633
+ ///
634
+ /// Custom sections are then defined by:
635
+ /// * 1-byte section identifier - 0 for a custom section
636
+ /// * leb-encoded section length (size of the contents beneath this bullet)
637
+ /// * leb-encoded custom section name length
638
+ /// * custom section name
639
+ /// * section contents
640
+ ///
641
+ /// One custom section, `linking`, is added here in accordance with
642
+ /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md>
643
+ /// which is required to inform LLD that this is an object file but it should
644
+ /// otherwise basically ignore it if it otherwise looks at it. The linking
645
+ /// section currently is defined by a single version byte (2) and then further
646
+ /// sections, but we have no more sections, so it's just the byte "2".
647
+ ///
648
+ /// The next custom section is the one we're interested in.
649
+ pub fn create_metadata_file_for_wasm ( data : & [ u8 ] , section_name : & [ u8 ] ) -> Vec < u8 > {
650
+ let mut bytes = b"\0 asm\x01 \0 \0 \0 " . to_vec ( ) ;
651
+
652
+ let mut append_custom_section = |section_name : & [ u8 ] , data : & [ u8 ] | {
653
+ let mut section_name_len = [ 0 ; leb128:: max_leb128_len :: < usize > ( ) ] ;
654
+ let off = leb128:: write_usize_leb128 ( & mut section_name_len, section_name. len ( ) ) ;
655
+ let section_name_len = & section_name_len[ ..off] ;
656
+
657
+ let mut section_len = [ 0 ; leb128:: max_leb128_len :: < usize > ( ) ] ;
658
+ let off = leb128:: write_usize_leb128 (
659
+ & mut section_len,
660
+ data. len ( ) + section_name_len. len ( ) + section_name. len ( ) ,
661
+ ) ;
662
+ let section_len = & section_len[ ..off] ;
663
+
664
+ bytes. push ( 0u8 ) ;
665
+ bytes. extend_from_slice ( section_len) ;
666
+ bytes. extend_from_slice ( section_name_len) ;
667
+ bytes. extend_from_slice ( section_name) ;
668
+ bytes. extend_from_slice ( data) ;
669
+ } ;
670
+
671
+ append_custom_section ( b"linking" , & [ 2 ] ) ;
672
+ append_custom_section ( section_name, data) ;
673
+ bytes
674
+ }
0 commit comments