s390x: Implement tls_value (#4616)

Implement the tls_value for s390 in the ELF general-dynamic mode.

Notable differences to the x86_64 implementation are:
- We use a __tls_get_offset libcall instead of __tls_get_addr.
- The current thread pointer (stored in a pair of access registers)
  needs to be added to the result of __tls_get_offset.
- __tls_get_offset has a variant ABI that requires the address of
  the GOT (global offset table) is passed in %r12.

This means we need a new libcall entries for __tls_get_offset.
In addition, we also need a way to access _GLOBAL_OFFSET_TABLE_.
The latter is a "magic" symbol with a well-known name defined
by the ABI and recognized by the linker.  This patch introduces
a new ExternalName::KnownSymbol variant to support such names
(originally due to @afonso360).

We also need to emit a relocation on a symbol placed in a
constant pool, as well as an extra relocation on the call
to __tls_get_offset required for TLS linker optimization.

Needed by the cg_clif frontend.
This commit is contained in:
Ulrich Weigand
2022-08-10 19:02:07 +02:00
committed by GitHub
parent 354daf5b93
commit 50fcab2984
17 changed files with 302 additions and 36 deletions

View File

@@ -7,7 +7,7 @@ pub mod generated_code;
use crate::isa::s390x::abi::{S390xMachineDeps, REG_SAVE_AREA_SIZE};
use crate::isa::s390x::inst::{
gpr, stack_reg, writable_gpr, zero_reg, CallIndInfo, CallInfo, Cond, Inst as MInst, MemArg,
MemArgPair, UImm12, UImm16Shifted, UImm32Shifted,
MemArgPair, SymbolReloc, UImm12, UImm16Shifted, UImm32Shifted,
};
use crate::isa::s390x::settings::Flags as IsaFlags;
use crate::machinst::isle::*;
@@ -16,7 +16,7 @@ use crate::settings::Flags;
use crate::{
ir::{
condcodes::*, immediates::*, types::*, AtomicRmwOp, Endianness, Inst, InstructionData,
LibCall, MemFlags, Opcode, TrapCode, Value, ValueList,
KnownSymbol, LibCall, MemFlags, Opcode, TrapCode, Value, ValueList,
},
isa::unwind::UnwindInst,
isa::CallConv,
@@ -34,12 +34,14 @@ use target_lexicon::Triple;
/// Information describing a library call to be emitted.
pub struct LibCallInfo {
libcall: LibCall,
tls_symbol: Option<SymbolReloc>,
}
type BoxCallInfo = Box<CallInfo>;
type BoxCallIndInfo = Box<CallIndInfo>;
type VecMachLabel = Vec<MachLabel>;
type BoxExternalName = Box<ExternalName>;
type BoxSymbolReloc = Box<SymbolReloc>;
type VecMInst = Vec<MInst>;
type VecMInstBuilder = Cell<Vec<MInst>>;
@@ -117,6 +119,7 @@ where
opcode: *opcode,
caller_callconv: self.lower_ctx.abi().call_conv(),
callee_callconv: abi.call_conv(),
tls_symbol: None,
})
}
@@ -136,6 +139,14 @@ where
fn lib_call_info_memcpy(&mut self) -> LibCallInfo {
LibCallInfo {
libcall: LibCall::Memcpy,
tls_symbol: None,
}
}
fn lib_call_info_tls_get_offset(&mut self, tls_symbol: &SymbolReloc) -> LibCallInfo {
LibCallInfo {
libcall: LibCall::ElfTlsGetOffset,
tls_symbol: Some(tls_symbol.clone()),
}
}
@@ -156,6 +167,7 @@ where
smallvec![gpr(2), gpr(3), gpr(4)],
smallvec![writable_gpr(2)],
),
LibCall::ElfTlsGetOffset => (smallvec![gpr(2), gpr(12)], smallvec![writable_gpr(2)]),
_ => unreachable!(),
};
@@ -173,9 +185,15 @@ where
opcode: Opcode::Call,
caller_callconv,
callee_callconv,
tls_symbol: info.tls_symbol.clone(),
})
}
#[inline]
fn box_symbol_reloc(&mut self, symbol_reloc: &SymbolReloc) -> BoxSymbolReloc {
Box::new(symbol_reloc.clone())
}
#[inline]
fn allow_div_traps(&mut self, _: Type) -> Option<()> {
if !self.flags.avoid_div_traps() {
@@ -707,6 +725,15 @@ where
}
}
#[inline]
fn memarg_got(&mut self) -> MemArg {
MemArg::Symbol {
name: Box::new(ExternalName::KnownSymbol(KnownSymbol::ElfGlobalOffsetTable)),
offset: 0,
flags: MemFlags::trusted(),
}
}
#[inline]
fn memarg_symbol_offset_sum(&mut self, off1: i64, off2: i64) -> Option<i32> {
let off = i32::try_from(off1 + off2).ok()?;