aarch64: Implement TLS ELF GD Relocations
Implement the `TlsValue` opcode in the aarch64 backend for ELF_GD. This is a little bit unusual as the default TLS mechanism for aarch64 is TLS Descriptors in other compilers. However currently we only recognize elf_gd so lets start with that as a TLS implementation.
This commit is contained in:
@@ -68,6 +68,16 @@ pub enum Reloc {
|
||||
|
||||
/// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry.
|
||||
MachOX86_64Tlv,
|
||||
|
||||
/// AArch64 TLS GD
|
||||
/// Set an ADRP immediate field to the top 21 bits of the final address. Checks for overflow.
|
||||
/// This is equivalent to `R_AARCH64_TLSGD_ADR_PAGE21` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage)
|
||||
Aarch64TlsGdAdrPage21,
|
||||
|
||||
/// AArch64 TLS GD
|
||||
/// Set the add immediate field to the low 12 bits of the final address. Does not check for overflow.
|
||||
/// This is equivalent to `R_AARCH64_TLSGD_ADD_LO12_NC` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage)
|
||||
Aarch64TlsGdAddLo12Nc,
|
||||
}
|
||||
|
||||
impl fmt::Display for Reloc {
|
||||
@@ -87,6 +97,8 @@ impl fmt::Display for Reloc {
|
||||
|
||||
Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
|
||||
Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"),
|
||||
Self::Aarch64TlsGdAdrPage21 => write!(f, "Aarch64TlsGdAdrPage21"),
|
||||
Self::Aarch64TlsGdAddLo12Nc => write!(f, "Aarch64TlsGdAddLo12Nc"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use crate::binemit::{CodeOffset, Reloc, StackMap};
|
||||
use crate::ir::constant::ConstantData;
|
||||
use crate::ir::types::*;
|
||||
use crate::ir::{MemFlags, TrapCode};
|
||||
use crate::ir::{LibCall, MemFlags, TrapCode};
|
||||
use crate::isa::aarch64::inst::*;
|
||||
use crate::machinst::ty_bits;
|
||||
|
||||
@@ -2563,6 +2563,32 @@ impl MachInstEmit for Inst {
|
||||
sink.bind_label(jump_around_label);
|
||||
}
|
||||
}
|
||||
|
||||
&Inst::ElfTlsGetAddr { ref symbol } => {
|
||||
// This is the instruction sequence that GCC emits for ELF GD TLS Relocations in aarch64
|
||||
// See: https://gcc.godbolt.org/z/KhMh5Gvra
|
||||
|
||||
// adrp x0, <label>
|
||||
sink.add_reloc(state.cur_srcloc(), Reloc::Aarch64TlsGdAdrPage21, symbol, 0);
|
||||
sink.put4(0x90000000);
|
||||
|
||||
// add x0, x0, <label>
|
||||
sink.add_reloc(state.cur_srcloc(), Reloc::Aarch64TlsGdAddLo12Nc, symbol, 0);
|
||||
sink.put4(0x91000000);
|
||||
|
||||
// bl __tls_get_addr
|
||||
sink.add_reloc(
|
||||
state.cur_srcloc(),
|
||||
Reloc::Arm64Call,
|
||||
&ExternalName::LibCall(LibCall::ElfTlsGetAddr),
|
||||
0,
|
||||
);
|
||||
sink.put4(0x94000000);
|
||||
|
||||
// nop
|
||||
sink.put4(0xd503201f);
|
||||
}
|
||||
|
||||
&Inst::ValueLabelMarker { .. } => {
|
||||
// Nothing; this is only used to compute debug info.
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ pub mod args;
|
||||
pub use self::args::*;
|
||||
pub mod emit;
|
||||
pub use self::emit::*;
|
||||
use crate::isa::aarch64::abi::AArch64MachineDeps;
|
||||
|
||||
pub mod unwind;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -1276,6 +1278,11 @@ pub enum Inst {
|
||||
needed_space: CodeOffset,
|
||||
},
|
||||
|
||||
/// A call to the `ElfTlsGetAddr` libcall. Returns address of TLS symbol in x0.
|
||||
ElfTlsGetAddr {
|
||||
symbol: ExternalName,
|
||||
},
|
||||
|
||||
/// A definition of a value label.
|
||||
ValueLabelMarker {
|
||||
reg: Reg,
|
||||
@@ -2150,6 +2157,12 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
||||
&Inst::ValueLabelMarker { reg, .. } => {
|
||||
collector.add_use(reg);
|
||||
}
|
||||
|
||||
&Inst::ElfTlsGetAddr { .. } => {
|
||||
for reg in AArch64MachineDeps::get_regs_clobbered_by_call(CallConv::SystemV) {
|
||||
collector.add_def(reg);
|
||||
}
|
||||
}
|
||||
&Inst::Unwind { .. } => {}
|
||||
&Inst::EmitIsland { .. } => {}
|
||||
}
|
||||
@@ -2959,6 +2972,7 @@ fn aarch64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
||||
}
|
||||
&mut Inst::VirtualSPOffsetAdj { .. } => {}
|
||||
&mut Inst::EmitIsland { .. } => {}
|
||||
&mut Inst::ElfTlsGetAddr { .. } => {}
|
||||
&mut Inst::ValueLabelMarker { ref mut reg, .. } => {
|
||||
map_use(mapper, reg);
|
||||
}
|
||||
@@ -4333,6 +4347,10 @@ impl Inst {
|
||||
}
|
||||
&Inst::EmitIsland { needed_space } => format!("emit_island {}", needed_space),
|
||||
|
||||
&Inst::ElfTlsGetAddr { ref symbol } => {
|
||||
format!("elf_tls_get_addr {}", symbol)
|
||||
}
|
||||
|
||||
&Inst::ValueLabelMarker { label, reg } => {
|
||||
format!("value_label {:?}, {}", label, reg.show_rru(mb_rru))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::ir::{InstructionData, Opcode, TrapCode};
|
||||
use crate::isa::aarch64::settings as aarch64_settings;
|
||||
use crate::machinst::lower::*;
|
||||
use crate::machinst::*;
|
||||
use crate::settings::Flags;
|
||||
use crate::settings::{Flags, TlsModel};
|
||||
use crate::{CodegenError, CodegenResult};
|
||||
|
||||
use crate::isa::aarch64::abi::*;
|
||||
@@ -3489,7 +3489,24 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
});
|
||||
}
|
||||
|
||||
Opcode::TlsValue => unimplemented!("tls_value"),
|
||||
Opcode::TlsValue => match flags.tls_model() {
|
||||
TlsModel::ElfGd => {
|
||||
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||
let (name, _, _) = ctx.symbol_value(insn).unwrap();
|
||||
let symbol = name.clone();
|
||||
ctx.emit(Inst::ElfTlsGetAddr { symbol });
|
||||
|
||||
let x0 = xreg(0);
|
||||
ctx.emit(Inst::gen_move(dst, x0, I64));
|
||||
}
|
||||
_ => {
|
||||
todo!(
|
||||
"Unimplemented TLS model in AArch64 backend: {:?}",
|
||||
flags.tls_model()
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
Opcode::FcvtLowFromSint => unimplemented!("FcvtLowFromSint"),
|
||||
Opcode::FvpromoteLow => unimplemented!("FvpromoteLow"),
|
||||
Opcode::Fvdemote => unimplemented!("Fvdemote"),
|
||||
|
||||
29
cranelift/filetests/filetests/isa/aarch64/tls-elf-gd.clif
Normal file
29
cranelift/filetests/filetests/isa/aarch64/tls-elf-gd.clif
Normal file
@@ -0,0 +1,29 @@
|
||||
test compile
|
||||
set tls_model=elf_gd
|
||||
target aarch64
|
||||
|
||||
function u0:0(i32) -> i32, i64 {
|
||||
gv0 = symbol colocated tls u1:0
|
||||
|
||||
block0(v0: i32):
|
||||
v1 = global_value.i64 gv0
|
||||
return v0, v1
|
||||
}
|
||||
; check: stp fp, lr, [sp, #-16]!
|
||||
; nextln: mov fp, sp
|
||||
; nextln: str x19, [sp, #-16]!
|
||||
; nextln: stp d14, d15, [sp, #-16]!
|
||||
; nextln: stp d12, d13, [sp, #-16]!
|
||||
; nextln: stp d10, d11, [sp, #-16]!
|
||||
; nextln: stp d8, d9, [sp, #-16]!
|
||||
; nextln: mov x19, x0
|
||||
; nextln: elf_tls_get_addr u1:0
|
||||
; nextln: mov x1, x0
|
||||
; nextln: mov x0, x19
|
||||
; nextln: ldp d8, d9, [sp], #16
|
||||
; nextln: ldp d10, d11, [sp], #16
|
||||
; nextln: ldp d12, d13, [sp], #16
|
||||
; nextln: ldp d14, d15, [sp], #16
|
||||
; nextln: ldr x19, [sp], #16
|
||||
; nextln: ldp fp, lr, [sp], #16
|
||||
; nextln: ret
|
||||
@@ -618,6 +618,30 @@ impl ObjectModule {
|
||||
32,
|
||||
)
|
||||
}
|
||||
Reloc::Aarch64TlsGdAdrPage21 => {
|
||||
assert_eq!(
|
||||
self.object.format(),
|
||||
object::BinaryFormat::Elf,
|
||||
"Aarch64TlsGdAdrPrel21 is not supported for this file format"
|
||||
);
|
||||
(
|
||||
RelocationKind::Elf(object::elf::R_AARCH64_TLSGD_ADR_PAGE21),
|
||||
RelocationEncoding::Generic,
|
||||
21,
|
||||
)
|
||||
}
|
||||
Reloc::Aarch64TlsGdAddLo12Nc => {
|
||||
assert_eq!(
|
||||
self.object.format(),
|
||||
object::BinaryFormat::Elf,
|
||||
"Aarch64TlsGdAddLo12Nc is not supported for this file format"
|
||||
);
|
||||
(
|
||||
RelocationKind::Elf(object::elf::R_AARCH64_TLSGD_ADD_LO12_NC),
|
||||
RelocationEncoding::Generic,
|
||||
12,
|
||||
)
|
||||
}
|
||||
// FIXME
|
||||
reloc => unimplemented!("{:?}", reloc),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user