Skip to content

Commit 7452822

Browse files
committed
Auto merge of #107583 - EsmeYi:aix_xcoff_metadata, r=bjorn3
Support the rustc metadata for AIX Support the rustc metadata for rlibs and dylibs on AIX. XCOFF is the object file format on AIX.
2 parents 42f28f9 + e31661c commit 7452822

File tree

2 files changed

+141
-12
lines changed

2 files changed

+141
-12
lines changed

compiler/rustc_codegen_ssa/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ libc = "0.2.50"
4848
[dependencies.object]
4949
version = "0.31.1"
5050
default-features = false
51-
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
51+
features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write"]
5252

5353
[target.'cfg(windows)'.dependencies.windows]
5454
version = "0.48.0"

compiler/rustc_codegen_ssa/src/back/metadata.rs

+140-11
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use std::path::Path;
66

77
use object::write::{self, StandardSegment, Symbol, SymbolSection};
88
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,
1111
};
1212

1313
use snap::write::FrameEncoder;
@@ -35,6 +35,8 @@ use rustc_target::spec::{RelocModel, Target};
3535
#[derive(Debug)]
3636
pub struct DefaultMetadataLoader;
3737

38+
static AIX_METADATA_SYMBOL_NAME: &'static str = "__aix_rust_metadata";
39+
3840
fn 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

5052
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> {
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+
144181
pub(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

Comments
 (0)