diff options
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back/apple.rs')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/apple.rs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index d9c5c3e5af9..bfa7635a869 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -2,6 +2,7 @@ use std::env; use std::fmt::{Display, from_fn}; use std::num::ParseIntError; +use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::Session; use rustc_target::spec::Target; @@ -26,6 +27,89 @@ pub(super) fn macho_platform(target: &Target) -> u32 { } } +/// Add relocation and section data needed for a symbol to be considered +/// undefined by ld64. +/// +/// The relocation must be valid, and hence must point to a valid piece of +/// machine code, and hence this is unfortunately very architecture-specific. +/// +/// +/// # New architectures +/// +/// The values here are basically the same as emitted by the following program: +/// +/// ```c +/// // clang -c foo.c -target $CLANG_TARGET +/// void foo(void); +/// +/// extern int bar; +/// +/// void* foobar[2] = { +/// (void*)foo, +/// (void*)&bar, +/// // ... +/// }; +/// ``` +/// +/// Can be inspected with: +/// ```console +/// objdump --macho --reloc foo.o +/// objdump --macho --full-contents foo.o +/// ``` +pub(super) fn add_data_and_relocation( + file: &mut object::write::Object<'_>, + section: object::write::SectionId, + symbol: object::write::SymbolId, + target: &Target, + kind: SymbolExportKind, +) -> object::write::Result<()> { + let authenticated_pointer = + kind == SymbolExportKind::Text && target.llvm_target.starts_with("arm64e"); + + let data: &[u8] = match target.pointer_width { + _ if authenticated_pointer => &[0, 0, 0, 0, 0, 0, 0, 0x80], + 32 => &[0; 4], + 64 => &[0; 8], + pointer_width => unimplemented!("unsupported Apple pointer width {pointer_width:?}"), + }; + + if target.arch == "x86_64" { + // Force alignment for the entire section to be 16 on x86_64. + file.section_mut(section).append_data(&[], 16); + } else { + // Elsewhere, the section alignment is the same as the pointer width. + file.section_mut(section).append_data(&[], target.pointer_width as u64); + } + + let offset = file.section_mut(section).append_data(data, data.len() as u64); + + let flags = if authenticated_pointer { + object::write::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_AUTHENTICATED_POINTER, + r_pcrel: false, + r_length: 3, + } + } else if target.arch == "arm" { + // FIXME(madsmtm): Remove once `object` supports 32-bit ARM relocations: + // https://github.com/gimli-rs/object/pull/757 + object::write::RelocationFlags::MachO { + r_type: object::macho::ARM_RELOC_VANILLA, + r_pcrel: false, + r_length: 2, + } + } else { + object::write::RelocationFlags::Generic { + kind: object::RelocationKind::Absolute, + encoding: object::RelocationEncoding::Generic, + size: target.pointer_width as u8, + } + }; + + file.add_relocation(section, object::write::Relocation { offset, addend: 0, symbol, flags })?; + + Ok(()) +} + /// Deployment target or SDK version. /// /// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`. |
