@@ -6,8 +6,8 @@ use std::path::Path;
66
77use object:: write:: { self , StandardSegment , Symbol , SymbolSection } ;
88use object:: {
9- elf, pe, Architecture , BinaryFormat , Endianness , FileFlags , Object , ObjectSection ,
10- SectionFlags , SectionKind , SymbolFlags , SymbolKind , SymbolScope ,
9+ elf, pe, xcoff , Architecture , BinaryFormat , Endianness , FileFlags , Object , ObjectSection ,
10+ ObjectSymbol , SectionFlags , SectionKind , SymbolFlags , SymbolKind , SymbolScope ,
1111} ;
1212
1313use snap:: write:: FrameEncoder ;
@@ -35,6 +35,8 @@ use rustc_target::spec::{RelocModel, Target};
3535#[ derive( Debug ) ]
3636pub struct DefaultMetadataLoader ;
3737
38+ static AIX_METADATA_SYMBOL_NAME : & ' static str = "__aix_rust_metadata" ;
39+
3840fn load_metadata_with (
3941 path : & Path ,
4042 f : impl for < ' a > FnOnce ( & ' a [ u8 ] ) -> Result < & ' a [ u8 ] , String > ,
@@ -48,7 +50,7 @@ fn load_metadata_with(
4850}
4951
5052impl MetadataLoader for DefaultMetadataLoader {
51- fn get_rlib_metadata ( & self , _target : & Target , path : & Path ) -> Result < OwnedSlice , String > {
53+ fn get_rlib_metadata ( & self , target : & Target , path : & Path ) -> Result < OwnedSlice , String > {
5254 load_metadata_with ( path, |data| {
5355 let archive = object:: read:: archive:: ArchiveFile :: parse ( & * data)
5456 . map_err ( |e| format ! ( "failed to parse rlib '{}': {}" , path. display( ) , e) ) ?;
@@ -60,16 +62,24 @@ impl MetadataLoader for DefaultMetadataLoader {
6062 let data = entry
6163 . data ( data)
6264 . map_err ( |e| format ! ( "failed to parse rlib '{}': {}" , path. display( ) , e) ) ?;
63- return search_for_section ( path, data, ".rmeta" ) ;
65+ if target. is_like_aix {
66+ return get_metadata_xcoff ( path, data) ;
67+ } else {
68+ return search_for_section ( path, data, ".rmeta" ) ;
69+ }
6470 }
6571 }
6672
6773 Err ( format ! ( "metadata not found in rlib '{}'" , path. display( ) ) )
6874 } )
6975 }
7076
71- fn get_dylib_metadata ( & self , _target : & Target , path : & Path ) -> Result < OwnedSlice , String > {
72- load_metadata_with ( path, |data| search_for_section ( path, data, ".rustc" ) )
77+ fn get_dylib_metadata ( & self , target : & Target , path : & Path ) -> Result < OwnedSlice , String > {
78+ if target. is_like_aix {
79+ load_metadata_with ( path, |data| get_metadata_xcoff ( path, data) )
80+ } else {
81+ load_metadata_with ( path, |data| search_for_section ( path, data, ".rustc" ) )
82+ }
7383 }
7484}
7585
@@ -141,6 +151,33 @@ fn add_gnu_property_note(
141151 file. append_section_data ( section, & data, 8 ) ;
142152}
143153
154+ pub ( super ) fn get_metadata_xcoff < ' a > ( path : & Path , data : & ' a [ u8 ] ) -> Result < & ' a [ u8 ] , String > {
155+ let Ok ( file) = object:: File :: parse ( data) else {
156+ return Ok ( data) ;
157+ } ;
158+ let info_data = search_for_section ( path, data, ".info" ) ?;
159+ if let Some ( metadata_symbol) =
160+ file. symbols ( ) . find ( |sym| sym. name ( ) == Ok ( AIX_METADATA_SYMBOL_NAME ) )
161+ {
162+ let offset = metadata_symbol. address ( ) as usize ;
163+ if offset < 4 {
164+ return Err ( format ! ( "Invalid metadata symbol offset: {}" , offset) ) ;
165+ }
166+ // The offset specifies the location of rustc metadata in the comment section.
167+ // The metadata is preceded by a 4-byte length field.
168+ let len = u32:: from_be_bytes ( info_data[ ( offset - 4 ) ..offset] . try_into ( ) . unwrap ( ) ) as usize ;
169+ if offset + len > ( info_data. len ( ) as usize ) {
170+ return Err ( format ! (
171+ "Metadata at offset {} with size {} is beyond .info section" ,
172+ offset, len
173+ ) ) ;
174+ }
175+ return Ok ( & info_data[ offset..( offset + len) ] ) ;
176+ } else {
177+ return Err ( format ! ( "Unable to find symbol {}" , AIX_METADATA_SYMBOL_NAME ) ) ;
178+ } ;
179+ }
180+
144181pub ( crate ) fn create_object_file ( sess : & Session ) -> Option < write:: Object < ' static > > {
145182 let endianness = match sess. target . options . endian {
146183 Endian :: Little => Endianness :: Little ,
@@ -183,6 +220,8 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
183220 BinaryFormat :: MachO
184221 } else if sess. target . is_like_windows {
185222 BinaryFormat :: Coff
223+ } else if sess. target . is_like_aix {
224+ BinaryFormat :: Xcoff
186225 } else {
187226 BinaryFormat :: Elf
188227 } ;
@@ -351,11 +390,15 @@ pub fn create_wrapper_file(
351390 // to add a case above.
352391 return ( data. to_vec ( ) , MetadataPosition :: Last ) ;
353392 } ;
354- let section = file. add_section (
355- file. segment_name ( StandardSegment :: Debug ) . to_vec ( ) ,
356- section_name,
357- SectionKind :: Debug ,
358- ) ;
393+ let section = if file. format ( ) == BinaryFormat :: Xcoff {
394+ file. add_section ( Vec :: new ( ) , b".info" . to_vec ( ) , SectionKind :: Debug )
395+ } else {
396+ file. add_section (
397+ file. segment_name ( StandardSegment :: Debug ) . to_vec ( ) ,
398+ section_name,
399+ SectionKind :: Debug ,
400+ )
401+ } ;
359402 match file. format ( ) {
360403 BinaryFormat :: Coff => {
361404 file. section_mut ( section) . flags =
@@ -365,6 +408,31 @@ pub fn create_wrapper_file(
365408 file. section_mut ( section) . flags =
366409 SectionFlags :: Elf { sh_flags : elf:: SHF_EXCLUDE as u64 } ;
367410 }
411+ BinaryFormat :: Xcoff => {
412+ // AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss.
413+ file. add_section ( Vec :: new ( ) , b".text" . to_vec ( ) , SectionKind :: Text ) ;
414+ file. section_mut ( section) . flags =
415+ SectionFlags :: Xcoff { s_flags : xcoff:: STYP_INFO as u32 } ;
416+
417+ let len = data. len ( ) as u32 ;
418+ let offset = file. append_section_data ( section, & len. to_be_bytes ( ) , 1 ) ;
419+ // Add a symbol referring to the data in .info section.
420+ file. add_symbol ( Symbol {
421+ name : AIX_METADATA_SYMBOL_NAME . into ( ) ,
422+ value : offset + 4 ,
423+ size : 0 ,
424+ kind : SymbolKind :: Unknown ,
425+ scope : SymbolScope :: Compilation ,
426+ weak : false ,
427+ section : SymbolSection :: Section ( section) ,
428+ flags : SymbolFlags :: Xcoff {
429+ n_sclass : xcoff:: C_INFO ,
430+ x_smtyp : xcoff:: C_HIDEXT ,
431+ x_smclas : xcoff:: C_HIDEXT ,
432+ containing_csect : None ,
433+ } ,
434+ } ) ;
435+ }
368436 _ => { }
369437 } ;
370438 file. append_section_data ( section, data, 1 ) ;
@@ -401,6 +469,9 @@ pub fn create_compressed_metadata_file(
401469 let Some ( mut file) = create_object_file ( sess) else {
402470 return compressed. to_vec ( ) ;
403471 } ;
472+ if file. format ( ) == BinaryFormat :: Xcoff {
473+ return create_compressed_metadata_file_for_xcoff ( file, & compressed, symbol_name) ;
474+ }
404475 let section = file. add_section (
405476 file. segment_name ( StandardSegment :: Data ) . to_vec ( ) ,
406477 b".rustc" . to_vec ( ) ,
@@ -430,3 +501,61 @@ pub fn create_compressed_metadata_file(
430501
431502 file. write ( ) . unwrap ( )
432503}
504+
505+ /// * Xcoff - On AIX, custom sections are merged into predefined sections,
506+ /// so custom .rustc section is not preserved during linking.
507+ /// For this reason, we store metadata in predefined .info section, and
508+ /// define a symbol to reference the metadata. To preserve metadata during
509+ /// linking on AIX, we have to
510+ /// 1. Create an empty .text section, a empty .data section.
511+ /// 2. Define an empty symbol named `symbol_name` inside .data section.
512+ /// 3. Define an symbol named `AIX_METADATA_SYMBOL_NAME` referencing
513+ /// data inside .info section.
514+ /// From XCOFF's view, (2) creates a csect entry in the symbol table, the
515+ /// symbol created by (3) is a info symbol for the preceding csect. Thus
516+ /// two symbols are preserved during linking and we can use the second symbol
517+ /// to reference the metadata.
518+ pub fn create_compressed_metadata_file_for_xcoff (
519+ mut file : write:: Object < ' _ > ,
520+ data : & [ u8 ] ,
521+ symbol_name : & str ,
522+ ) -> Vec < u8 > {
523+ assert ! ( file. format( ) == BinaryFormat :: Xcoff ) ;
524+ // AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss.
525+ file. add_section ( Vec :: new ( ) , b".text" . to_vec ( ) , SectionKind :: Text ) ;
526+ let data_section = file. add_section ( Vec :: new ( ) , b".data" . to_vec ( ) , SectionKind :: Data ) ;
527+ let section = file. add_section ( Vec :: new ( ) , b".info" . to_vec ( ) , SectionKind :: Debug ) ;
528+ file. add_file_symbol ( "lib.rmeta" . into ( ) ) ;
529+ file. section_mut ( section) . flags = SectionFlags :: Xcoff { s_flags : xcoff:: STYP_INFO as u32 } ;
530+ // Add a global symbol to data_section.
531+ file. add_symbol ( Symbol {
532+ name : symbol_name. as_bytes ( ) . into ( ) ,
533+ value : 0 ,
534+ size : 0 ,
535+ kind : SymbolKind :: Data ,
536+ scope : SymbolScope :: Dynamic ,
537+ weak : true ,
538+ section : SymbolSection :: Section ( data_section) ,
539+ flags : SymbolFlags :: None ,
540+ } ) ;
541+ let len = data. len ( ) as u32 ;
542+ let offset = file. append_section_data ( section, & len. to_be_bytes ( ) , 1 ) ;
543+ // Add a symbol referring to the rustc metadata.
544+ file. add_symbol ( Symbol {
545+ name : AIX_METADATA_SYMBOL_NAME . into ( ) ,
546+ value : offset + 4 , // The metadata is preceded by a 4-byte length field.
547+ size : 0 ,
548+ kind : SymbolKind :: Unknown ,
549+ scope : SymbolScope :: Dynamic ,
550+ weak : false ,
551+ section : SymbolSection :: Section ( section) ,
552+ flags : SymbolFlags :: Xcoff {
553+ n_sclass : xcoff:: C_INFO ,
554+ x_smtyp : xcoff:: C_HIDEXT ,
555+ x_smclas : xcoff:: C_HIDEXT ,
556+ containing_csect : None ,
557+ } ,
558+ } ) ;
559+ file. append_section_data ( section, data, 1 ) ;
560+ file. write ( ) . unwrap ( )
561+ }
0 commit comments