From 823215f47ac281576649436ad6416e2191fa05e9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:23:13 +0000 Subject: [PATCH] Allow marking data objects as used for the linker --- cranelift/jit/src/backend.rs | 1 + cranelift/module/src/data_context.rs | 17 +++++++++++--- cranelift/module/src/module.rs | 2 +- cranelift/object/src/backend.rs | 35 +++++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/cranelift/jit/src/backend.rs b/cranelift/jit/src/backend.rs index b6817181a256..4a477be0a425 100644 --- a/cranelift/jit/src/backend.rs +++ b/cranelift/jit/src/backend.rs @@ -611,6 +611,7 @@ impl Module for JITModule { data_relocs: _, custom_segment_section: _, align, + used: _, } = data; // Make sure to allocate at least 1 byte. Allocating 0 bytes is UB. Previously a dummy diff --git a/cranelift/module/src/data_context.rs b/cranelift/module/src/data_context.rs index cc13e036cb5e..5399ea317ec3 100644 --- a/cranelift/module/src/data_context.rs +++ b/cranelift/module/src/data_context.rs @@ -1,4 +1,4 @@ -//! Defines `DataContext`. +//! Defines `DataDescription`. use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc}; use cranelift_codegen::entity::PrimaryMap; @@ -62,9 +62,12 @@ pub struct DataDescription { pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>, /// Object file section pub custom_segment_section: Option<(String, String)>, - /// Alignment in bytes. `None` means that the default alignment of the respective module should - /// be used. + /// Alignment in bytes. `None` means that the default alignment of the + /// respective module should be used. pub align: Option, + /// Whether or not to request the linker to preserve this data object even + /// if not referenced. + pub used: bool, } impl DataDescription { @@ -78,6 +81,7 @@ impl DataDescription { data_relocs: vec![], custom_segment_section: None, align: None, + used: false, } } @@ -90,6 +94,7 @@ impl DataDescription { self.data_relocs.clear(); self.custom_segment_section = None; self.align = None; + self.used = false; } /// Define a zero-initialized object with the given size. @@ -117,6 +122,12 @@ impl DataDescription { self.align = Some(align); } + /// Set whether or not the linker should preserve this data object even if + /// not referenced. + pub fn set_used(&mut self, used: bool) { + self.used = used; + } + /// Declare an external function import. /// /// Users of the `Module` API generally should call diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index 041c66298dfb..852787edb2e1 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -979,7 +979,7 @@ pub trait Module { relocs: &[ModuleReloc], ) -> ModuleResult<()>; - /// Define a data object, producing the data contents from the given `DataContext`. + /// Define a data object, producing the data contents from the given `DataDescription`. fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()>; } diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index 4e7ecd92271f..6c0404301480 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -15,8 +15,8 @@ use object::write::{ Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection, }; use object::{ - RelocationEncoding, RelocationFlags, RelocationKind, SectionKind, SymbolFlags, SymbolKind, - SymbolScope, + RelocationEncoding, RelocationFlags, RelocationKind, SectionFlags, SectionKind, SymbolFlags, + SymbolKind, SymbolScope, }; use std::collections::HashMap; use std::collections::hash_map::Entry; @@ -394,6 +394,7 @@ impl Module for ObjectModule { data_relocs: _, ref custom_segment_section, align, + used, } = data; let pointer_reloc = match self.isa.triple().pointer_width().unwrap() { @@ -422,7 +423,7 @@ impl Module for ObjectModule { } else { StandardSection::ReadOnlyDataWithRel }; - if self.per_data_object_section { + if self.per_data_object_section || used { // FIXME pass empty symbol name once add_subsection produces `.text` as section name // instead of `.text.` when passed an empty symbol name. (object#748) Until then // pass `subsection` to produce `.text.subsection` as section name to reduce @@ -451,6 +452,34 @@ impl Module for ObjectModule { ) }; + if used { + match self.object.format() { + object::BinaryFormat::Elf => { + let section = self.object.section_mut(section); + match &mut section.flags { + SectionFlags::None => { + section.flags = SectionFlags::Elf { + sh_flags: object::elf::SHF_GNU_RETAIN.into(), + } + } + SectionFlags::Elf { sh_flags } => { + *sh_flags |= u64::from(object::elf::SHF_GNU_RETAIN) + } + _ => unreachable!(), + } + } + object::BinaryFormat::Coff => {} + object::BinaryFormat::MachO => { + let symbol = self.object.symbol_mut(symbol); + assert!(matches!(symbol.flags, SymbolFlags::None)); + symbol.flags = SymbolFlags::MachO { + n_desc: object::macho::N_NO_DEAD_STRIP, + } + } + _ => unreachable!(), + } + } + let align = std::cmp::max(align.unwrap_or(1), self.isa.symbol_alignment()); let offset = match *init { Init::Uninitialized => {