about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src/back/apple.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back/apple.rs')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/apple.rs84
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`.