@@ -6,8 +6,8 @@ use std::path::Path;
6
6
7
7
use object:: write:: { self , StandardSegment , Symbol , SymbolSection } ;
8
8
use 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 ,
11
11
} ;
12
12
13
13
use snap:: write:: FrameEncoder ;
@@ -35,6 +35,8 @@ use rustc_target::spec::{RelocModel, Target};
35
35
#[ derive( Debug ) ]
36
36
pub struct DefaultMetadataLoader ;
37
37
38
+ static AIX_METADATA_SYMBOL_NAME : & ' static str = "__aix_rust_metadata" ;
39
+
38
40
fn load_metadata_with (
39
41
path : & Path ,
40
42
f : impl for < ' a > FnOnce ( & ' a [ u8 ] ) -> Result < & ' a [ u8 ] , String > ,
@@ -48,7 +50,7 @@ fn load_metadata_with(
48
50
}
49
51
50
52
impl 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 > {
52
54
load_metadata_with ( path, |data| {
53
55
let archive = object:: read:: archive:: ArchiveFile :: parse ( & * data)
54
56
. map_err ( |e| format ! ( "failed to parse rlib '{}': {}" , path. display( ) , e) ) ?;
@@ -60,16 +62,24 @@ impl MetadataLoader for DefaultMetadataLoader {
60
62
let data = entry
61
63
. data ( data)
62
64
. 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
+ }
64
70
}
65
71
}
66
72
67
73
Err ( format ! ( "metadata not found in rlib '{}'" , path. display( ) ) )
68
74
} )
69
75
}
70
76
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
+ }
73
83
}
74
84
}
75
85
@@ -141,6 +151,33 @@ fn add_gnu_property_note(
141
151
file. append_section_data ( section, & data, 8 ) ;
142
152
}
143
153
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
+
144
181
pub ( crate ) fn create_object_file ( sess : & Session ) -> Option < write:: Object < ' static > > {
145
182
let endianness = match sess. target . options . endian {
146
183
Endian :: Little => Endianness :: Little ,
@@ -183,6 +220,8 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
183
220
BinaryFormat :: MachO
184
221
} else if sess. target . is_like_windows {
185
222
BinaryFormat :: Coff
223
+ } else if sess. target . is_like_aix {
224
+ BinaryFormat :: Xcoff
186
225
} else {
187
226
BinaryFormat :: Elf
188
227
} ;
@@ -319,11 +358,15 @@ pub fn create_wrapper_file(
319
358
// to add a case above.
320
359
return ( data. to_vec ( ) , MetadataPosition :: Last ) ;
321
360
} ;
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
+ } ;
327
370
match file. format ( ) {
328
371
BinaryFormat :: Coff => {
329
372
file. section_mut ( section) . flags =
@@ -333,6 +376,30 @@ pub fn create_wrapper_file(
333
376
file. section_mut ( section) . flags =
334
377
SectionFlags :: Elf { sh_flags : elf:: SHF_EXCLUDE as u64 } ;
335
378
}
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
+ }
336
403
_ => { }
337
404
} ;
338
405
file. append_section_data ( section, data, 1 ) ;
@@ -369,6 +436,9 @@ pub fn create_compressed_metadata_file(
369
436
let Some ( mut file) = create_object_file ( sess) else {
370
437
return compressed. to_vec ( ) ;
371
438
} ;
439
+ if file. format ( ) == BinaryFormat :: Xcoff {
440
+ return create_compressed_metadata_file_for_xcoff ( file, & compressed, symbol_name) ;
441
+ }
372
442
let section = file. add_section (
373
443
file. segment_name ( StandardSegment :: Data ) . to_vec ( ) ,
374
444
b".rustc" . to_vec ( ) ,
@@ -398,3 +468,60 @@ pub fn create_compressed_metadata_file(
398
468
399
469
file. write ( ) . unwrap ( )
400
470
}
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