@@ -15,6 +15,7 @@ use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
1515use rustc_metadata:: creader:: MetadataLoader ;
1616use rustc_metadata:: fs:: METADATA_FILENAME ;
1717use rustc_metadata:: EncodedMetadata ;
18+ use rustc_serialize:: leb128;
1819use rustc_session:: Session ;
1920use rustc_span:: sym;
2021use rustc_target:: abi:: Endian ;
@@ -420,10 +421,9 @@ pub enum MetadataPosition {
420421/// it's not in an allowlist of otherwise well known dwarf section names to
421422/// go into the final artifact.
422423///
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.
427427///
428428/// * COFF - Windows-like targets create an object with a section that has
429429/// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
@@ -438,22 +438,13 @@ pub fn create_wrapper_file(
438438 data : & [ u8 ] ,
439439) -> ( Vec < u8 > , MetadataPosition ) {
440440 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.
457448 return ( data. to_vec ( ) , MetadataPosition :: Last ) ;
458449 } ;
459450 let section = if file. format ( ) == BinaryFormat :: Xcoff {
@@ -532,6 +523,9 @@ pub fn create_compressed_metadata_file(
532523 packed_metadata. extend ( metadata. raw_data ( ) ) ;
533524
534525 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+ }
535529 return packed_metadata. to_vec ( ) ;
536530 } ;
537531 if file. format ( ) == BinaryFormat :: Xcoff {
@@ -624,3 +618,57 @@ pub fn create_compressed_metadata_file_for_xcoff(
624618 file. append_section_data ( section, data, 1 ) ;
625619 file. write ( ) . unwrap ( )
626620}
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