Skip to content

Commit

Permalink
AArch64: implement properly local-exec TLS model relocations
Browse files Browse the repository at this point in the history
  • Loading branch information
marxin authored and davidlattimore committed Jan 5, 2025
1 parent bd48b87 commit d584502
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 14 deletions.
24 changes: 12 additions & 12 deletions libwild/src/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,47 +644,47 @@ impl crate::arch::Arch for AArch64 {

// 5.7.11.4 Local Exec thread-local storage model
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G2 => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 32, end: 48 },
insn: RelocationInstruction::Movnz,
},
None,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G1 => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 16, end: 32 },
insn: RelocationInstruction::Movnz,
},
None,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 16, end: 32 },
insn: RelocationInstruction::Movkz,
},
None,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G0 => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 0, end: 16 },
insn: RelocationInstruction::Movnz,
},
None,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 0, end: 16 },
insn: RelocationInstruction::Movkz,
},
None,
),
object::elf::R_AARCH64_TLSLE_ADD_TPREL_HI12 => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 12, end: 24 },
insn: RelocationInstruction::Add,
Expand All @@ -693,7 +693,7 @@ impl crate::arch::Arch for AArch64 {
),
object::elf::R_AARCH64_TLSLE_ADD_TPREL_LO12
| object::elf::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 0, end: 12 },
insn: RelocationInstruction::Add,
Expand All @@ -702,7 +702,7 @@ impl crate::arch::Arch for AArch64 {
),
object::elf::R_AARCH64_TLSLE_LDST8_TPREL_LO12
| object::elf::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 0, end: 12 },
insn: RelocationInstruction::LdSt,
Expand All @@ -711,7 +711,7 @@ impl crate::arch::Arch for AArch64 {
),
object::elf::R_AARCH64_TLSLE_LDST16_TPREL_LO12
| object::elf::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 1, end: 12 },
insn: RelocationInstruction::LdSt,
Expand All @@ -720,7 +720,7 @@ impl crate::arch::Arch for AArch64 {
),
object::elf::R_AARCH64_TLSLE_LDST32_TPREL_LO12
| object::elf::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 2, end: 12 },
insn: RelocationInstruction::LdSt,
Expand All @@ -729,7 +729,7 @@ impl crate::arch::Arch for AArch64 {
),
object::elf::R_AARCH64_TLSLE_LDST64_TPREL_LO12
| object::elf::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 3, end: 12 },
insn: RelocationInstruction::LdSt,
Expand All @@ -738,7 +738,7 @@ impl crate::arch::Arch for AArch64 {
),
object::elf::R_AARCH64_TLSLE_LDST128_TPREL_LO12
| object::elf::R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationKind::TpOffAArch64,
RelocationSize::BitMasking {
range: BitRange { start: 4, end: 12 },
insn: RelocationInstruction::LdSt,
Expand Down
19 changes: 18 additions & 1 deletion libwild/src/alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ impl Alignment {
1 << self.exponent
}

pub(crate) fn mask(self) -> u64 {
self.value() - 1
}

pub(crate) fn align_up(self, value: u64) -> u64 {
value.next_multiple_of(self.value())
}
Expand All @@ -73,10 +77,14 @@ impl Alignment {
value.next_multiple_of(self.value() as usize)
}

pub(crate) fn align_down(self, value: u64) -> u64 {
value & !self.mask()
}

/// Returns `mem_offset`, possibly adjusted up so that it is >= `align_up(mem_offset)` and has
/// the same modulo as `file_offset`
pub(crate) fn align_modulo(self, file_offset: u64, mut mem_offset: u64) -> u64 {
let mask = self.value() - 1;
let mask = self.mask();
mem_offset = self.align_up(mem_offset);
if mem_offset & mask == file_offset & mask {
return mem_offset;
Expand Down Expand Up @@ -113,3 +121,12 @@ fn test_align_modulo() {
assert_eq!(PAGE.align_modulo(0x123456, 0x987000), 0x987456);
assert_eq!(PAGE.align_modulo(0x2afce, 0x42af7e), 0x42bfce);
}

#[test]
fn test_align_down() {
assert_eq!(Alignment::new(16).unwrap().align_down(16), 16);
assert_eq!(Alignment::new(16).unwrap().align_down(17), 16);
assert_eq!(Alignment::new(16).unwrap().align_down(32), 32);
assert_eq!(Alignment::new(16).unwrap().align_down(0), 0);
assert_eq!(Alignment::new(16).unwrap().align_down(1), 0);
}
4 changes: 4 additions & 0 deletions libwild/src/elf_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,10 @@ fn apply_relocation<S: StorageModel, A: Arch>(
.value()
.wrapping_sub(layout.tls_end_address())
.wrapping_add(addend),
RelocationKind::TpOffAArch64 => resolution
.value()
.wrapping_sub(layout.tls_start_address_aarch64())
.wrapping_add(addend),
RelocationKind::None => 0,
};
rel_info
Expand Down
9 changes: 9 additions & 0 deletions libwild/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,14 @@ impl<'data, S: StorageModel> Layout<'data, '_, S> {
alignment.align_up(tls_end)
}

/// Returns the memory address of the start of the TLS segment used by the AArch64.
pub(crate) fn tls_start_address_aarch64(&self) -> u64 {
let tdata = self.section_layouts.get(output_section_id::TDATA);
// Two words at TP are reserved by the arch.
let tls_start = tdata.mem_offset - 2 * 8;
tdata.alignment.align_down(tls_start)
}

pub(crate) fn layout_data(&self) -> linker_layout::Layout {
let files = self
.group_layouts
Expand Down Expand Up @@ -2478,6 +2486,7 @@ fn resolution_flags(rel_kind: RelocationKind) -> ResolutionFlags {
| RelocationKind::Relative
| RelocationKind::DtpOff
| RelocationKind::TpOff
| RelocationKind::TpOffAArch64
| RelocationKind::SymRelGotBase
| RelocationKind::Got
| RelocationKind::None => ResolutionFlags::DIRECT,
Expand Down
3 changes: 3 additions & 0 deletions linker-utils/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@ pub enum RelocationKind {
/// The offset of a TLS variable within the executable's TLS storage.
TpOff,

/// The offset of a TLS variable within the executable's TLS storage, AArch64 TLS block layout.
TpOffAArch64,

/// No relocation needs to be applied. Produced when we eliminate a relocation due to an
/// optimisation.
None,
Expand Down
3 changes: 2 additions & 1 deletion wild/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,8 @@ fn integration_test(
"cpp-integration.cc",
"rust-tls.rs",
"input_does_not_exist.c",
"ifunc2.c"
"ifunc2.c",
"tls-local-exec.c"
)]
program_name: &'static str,
#[allow(unused_variables)] setup_symlink: (),
Expand Down
19 changes: 19 additions & 0 deletions wild/tests/sources/tls-local-exec.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//#AbstractConfig:default
//#DiffIgnore:.dynamic.DT_NEEDED
//#DiffIgnore:section.data
//#DiffIgnore:section.data.alignment
//#DiffIgnore:section.rodata
//#DiffIgnore:section.rodata.alignment

//#Config:pie:default
//#CompArgs:-fpie
//#LinkArgs:--cc=gcc -Wl,-z,now

__thread long tvar = 1;
__thread int tvar2 = 2;
__thread char tvar3 = 3;

int main() {
// __builtin_printf ("%ld, %d, %d\n", tvar, tvar2, tvar3);
return tvar + tvar2 + tvar3 + 36;
}

0 comments on commit d584502

Please sign in to comment.