@@ -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 } ;
@@ -319,11 +358,15 @@ pub fn create_wrapper_file(
319358 // to add a case above.
320359 return ( data. to_vec ( ) , MetadataPosition :: Last ) ;
321360 } ;
322- let section = file. add_section (
323- file. segment_name ( StandardSegment :: Debug ) . to_vec ( ) ,
324- section_name,
325- SectionKind :: Debug ,
326- ) ;
361+ let section = if file. format ( ) == BinaryFormat :: Xcoff {
362+ file. add_section ( Vec :: new ( ) , b".info" . to_vec ( ) , SectionKind :: Debug )
363+ } else {
364+ file. add_section (
365+ file. segment_name ( StandardSegment :: Debug ) . to_vec ( ) ,
366+ section_name,
367+ SectionKind :: Debug ,
368+ )
369+ } ;
327370 match file. format ( ) {
328371 BinaryFormat :: Coff => {
329372 file. section_mut ( section) . flags =
@@ -333,6 +376,30 @@ pub fn create_wrapper_file(
333376 file. section_mut ( section) . flags =
334377 SectionFlags :: Elf { sh_flags : elf:: SHF_EXCLUDE as u64 } ;
335378 }
379+ BinaryFormat :: Xcoff => {
380+ file. add_section ( Vec :: new ( ) , b".text" . to_vec ( ) , SectionKind :: Text ) ;
381+ file. section_mut ( section) . flags =
382+ SectionFlags :: Xcoff { s_flags : xcoff:: STYP_INFO as u32 } ;
383+
384+ let len = data. len ( ) as u32 ;
385+ let offset = file. append_section_data ( section, & len. to_be_bytes ( ) , 1 ) ;
386+ // Add a symbol referring to the data in .info section.
387+ file. add_symbol ( Symbol {
388+ name : AIX_METADATA_SYMBOL_NAME . into ( ) ,
389+ value : offset + 4 ,
390+ size : 0 ,
391+ kind : SymbolKind :: Unknown ,
392+ scope : SymbolScope :: Dynamic ,
393+ weak : false ,
394+ section : SymbolSection :: Section ( section) ,
395+ flags : SymbolFlags :: Xcoff {
396+ n_sclass : xcoff:: C_INFO ,
397+ x_smtyp : xcoff:: C_HIDEXT ,
398+ x_smclas : xcoff:: C_HIDEXT ,
399+ containing_csect : None ,
400+ } ,
401+ } ) ;
402+ }
336403 _ => { }
337404 } ;
338405 file. append_section_data ( section, data, 1 ) ;
@@ -369,6 +436,9 @@ pub fn create_compressed_metadata_file(
369436 let Some ( mut file) = create_object_file ( sess) else {
370437 return compressed. to_vec ( ) ;
371438 } ;
439+ if file. format ( ) == BinaryFormat :: Xcoff {
440+ return create_compressed_metadata_file_for_xcoff ( file, & compressed, symbol_name) ;
441+ }
372442 let section = file. add_section (
373443 file. segment_name ( StandardSegment :: Data ) . to_vec ( ) ,
374444 b".rustc" . to_vec ( ) ,
@@ -398,3 +468,60 @@ pub fn create_compressed_metadata_file(
398468
399469 file. write ( ) . unwrap ( )
400470}
471+
472+ /// * Xcoff - On AIX, custom sections are merged into predefined sections,
473+ /// so custom .rustc section is not preserved during linking.
474+ /// For this reason, we store metadata in predefined .info section, and
475+ /// define a symbol to reference the metadata. To preserve metadata during
476+ /// linking on AIX, we have to
477+ /// 1. Create an empty .text section, a empty .data section.
478+ /// 2. Define an empty symbol named `symbol_name` inside .data section.
479+ /// 3. Define an symbol named `AIX_METADATA_SYMBOL_NAME` referencing
480+ /// data inside .info section.
481+ /// From XCOFF's view, (2) creates a csect entry in the symbol table, the
482+ /// symbol created by (3) is a info symbol for the preceding csect. Thus
483+ /// two symbols are preserved during linking and we can use the second symbol
484+ /// to reference the metadata.
485+ pub fn create_compressed_metadata_file_for_xcoff (
486+ mut file : write:: Object < ' _ > ,
487+ data : & [ u8 ] ,
488+ symbol_name : & str ,
489+ ) -> Vec < u8 > {
490+ assert ! ( file. format( ) == BinaryFormat :: Xcoff ) ;
491+ file. add_section ( Vec :: new ( ) , b".text" . to_vec ( ) , SectionKind :: Text ) ;
492+ let data_section = file. add_section ( Vec :: new ( ) , b".data" . to_vec ( ) , SectionKind :: Data ) ;
493+ let section = file. add_section ( Vec :: new ( ) , b".info" . to_vec ( ) , SectionKind :: Debug ) ;
494+ file. add_file_symbol ( "lib.rmeta" . into ( ) ) ;
495+ file. section_mut ( section) . flags = SectionFlags :: Xcoff { s_flags : xcoff:: STYP_INFO as u32 } ;
496+ // Add a global symbol to data_section.
497+ file. add_symbol ( Symbol {
498+ name : symbol_name. as_bytes ( ) . into ( ) ,
499+ value : 0 ,
500+ size : 0 ,
501+ kind : SymbolKind :: Data ,
502+ scope : SymbolScope :: Dynamic ,
503+ weak : true ,
504+ section : SymbolSection :: Section ( data_section) ,
505+ flags : SymbolFlags :: None ,
506+ } ) ;
507+ let len = data. len ( ) as u32 ;
508+ let offset = file. append_section_data ( section, & len. to_be_bytes ( ) , 1 ) ;
509+ // Add a symbol referring to the rustc metadata.
510+ file. add_symbol ( Symbol {
511+ name : AIX_METADATA_SYMBOL_NAME . into ( ) ,
512+ value : offset + 4 , // The metadata is preceded by a 4-byte length field.
513+ size : 0 ,
514+ kind : SymbolKind :: Unknown ,
515+ scope : SymbolScope :: Dynamic ,
516+ weak : false ,
517+ section : SymbolSection :: Section ( section) ,
518+ flags : SymbolFlags :: Xcoff {
519+ n_sclass : xcoff:: C_INFO ,
520+ x_smtyp : xcoff:: C_HIDEXT ,
521+ x_smclas : xcoff:: C_HIDEXT ,
522+ containing_csect : None ,
523+ } ,
524+ } ) ;
525+ file. append_section_data ( section, data, 1 ) ;
526+ file. write ( ) . unwrap ( )
527+ }
0 commit comments