summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_ssa/src/back/metadata.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back/metadata.rs')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs91
1 files changed, 86 insertions, 5 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index d5d843702..ad27b854d 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -12,9 +12,9 @@ use object::{
use snap::write::FrameEncoder;
+use object::elf::NT_GNU_PROPERTY_TYPE_0;
use rustc_data_structures::memmap::Mmap;
-use rustc_data_structures::owned_slice::try_slice_owned;
-use rustc_data_structures::sync::MetadataRef;
+use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
use rustc_metadata::fs::METADATA_FILENAME;
use rustc_metadata::EncodedMetadata;
use rustc_session::cstore::MetadataLoader;
@@ -38,7 +38,7 @@ pub struct DefaultMetadataLoader;
fn load_metadata_with(
path: &Path,
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
-) -> Result<MetadataRef, String> {
+) -> Result<OwnedSlice, String> {
let file =
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
@@ -48,7 +48,7 @@ fn load_metadata_with(
}
impl MetadataLoader for DefaultMetadataLoader {
- fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
+ fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
load_metadata_with(path, |data| {
let archive = object::read::archive::ArchiveFile::parse(&*data)
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
@@ -68,7 +68,7 @@ impl MetadataLoader for DefaultMetadataLoader {
})
}
- fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
+ fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
}
}
@@ -93,6 +93,54 @@ pub(super) fn search_for_section<'a>(
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
}
+fn add_gnu_property_note(
+ file: &mut write::Object<'static>,
+ architecture: Architecture,
+ binary_format: BinaryFormat,
+ endianness: Endianness,
+) {
+ // check bti protection
+ if binary_format != BinaryFormat::Elf
+ || !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64)
+ {
+ return;
+ }
+
+ let section = file.add_section(
+ file.segment_name(StandardSegment::Data).to_vec(),
+ b".note.gnu.property".to_vec(),
+ SectionKind::Note,
+ );
+ let mut data: Vec<u8> = Vec::new();
+ let n_namsz: u32 = 4; // Size of the n_name field
+ let n_descsz: u32 = 16; // Size of the n_desc field
+ let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
+ let header_values = [n_namsz, n_descsz, n_type];
+ header_values.iter().for_each(|v| {
+ data.extend_from_slice(&match endianness {
+ Endianness::Little => v.to_le_bytes(),
+ Endianness::Big => v.to_be_bytes(),
+ })
+ });
+ data.extend_from_slice(b"GNU\0"); // Owner of the program property note
+ let pr_type: u32 = match architecture {
+ Architecture::X86_64 => 0xc0000002,
+ Architecture::Aarch64 => 0xc0000000,
+ _ => unreachable!(),
+ };
+ let pr_datasz: u32 = 4; //size of the pr_data field
+ let pr_data: u32 = 3; //program property descriptor
+ let pr_padding: u32 = 0;
+ let property_values = [pr_type, pr_datasz, pr_data, pr_padding];
+ property_values.iter().for_each(|v| {
+ data.extend_from_slice(&match endianness {
+ Endianness::Little => v.to_le_bytes(),
+ Endianness::Big => v.to_be_bytes(),
+ })
+ });
+ file.append_section_data(section, &data, 8);
+}
+
pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
let endianness = match sess.target.options.endian {
Endian::Little => Endianness::Little,
@@ -140,6 +188,11 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
let mut file = write::Object::new(binary_format, architecture, endianness);
+ if sess.target.is_like_osx {
+ if let Some(build_version) = macho_object_build_version_for_target(&sess.target) {
+ file.set_macho_build_version(build_version)
+ }
+ }
let e_flags = match architecture {
Architecture::Mips => {
let arch = match sess.target.options.cpu.as_ref() {
@@ -205,10 +258,38 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
_ => elf::ELFOSABI_NONE,
};
let abi_version = 0;
+ add_gnu_property_note(&mut file, architecture, binary_format, endianness);
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
Some(file)
}
+/// Apple's LD, when linking for Mac Catalyst, requires object files to
+/// contain information about what they were built for (LC_BUILD_VERSION):
+/// the platform (macOS/watchOS etc), minimum OS version, and SDK version.
+/// This returns a `MachOBuildVersion` if necessary for the target.
+fn macho_object_build_version_for_target(
+ target: &Target,
+) -> Option<object::write::MachOBuildVersion> {
+ if !target.llvm_target.ends_with("-macabi") {
+ return None;
+ }
+ /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
+ /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
+ fn pack_version((major, minor): (u32, u32)) -> u32 {
+ (major << 16) | (minor << 8)
+ }
+
+ let platform = object::macho::PLATFORM_MACCATALYST;
+ let min_os = (14, 0);
+ let sdk = (16, 2);
+
+ let mut build_version = object::write::MachOBuildVersion::default();
+ build_version.platform = platform;
+ build_version.minos = pack_version(min_os);
+ build_version.sdk = pack_version(sdk);
+ Some(build_version)
+}
+
pub enum MetadataPosition {
First,
Last,