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

@@ -4,7 +4,7 @@
//! function. The name of an external declaration doesn't have any meaning to
//! Cranelift, which compiles functions independently.
use crate::ir::LibCall;
use crate::ir::{KnownSymbol, LibCall};
use core::cmp;
use core::fmt::{self, Write};
use core::str::FromStr;
@@ -46,6 +46,8 @@ pub enum ExternalName {
},
/// A well-known runtime library function.
LibCall(LibCall),
/// A well-known symbol.
KnownSymbol(KnownSymbol),
}
impl ExternalName {
@@ -104,6 +106,7 @@ impl fmt::Display for ExternalName {
Ok(())
}
Self::LibCall(lc) => write!(f, "%{}", lc),
Self::KnownSymbol(ks) => write!(f, "%{}", ks),
}
}
}
@@ -112,11 +115,18 @@ impl FromStr for ExternalName {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
// Try to parse as a libcall name, otherwise it's a test case.
match s.parse() {
Ok(lc) => Ok(Self::LibCall(lc)),
Err(_) => Ok(Self::testcase(s.as_bytes())),
// Try to parse as a known symbol
if let Ok(ks) = s.parse() {
return Ok(Self::KnownSymbol(ks));
}
// Try to parse as a libcall name
if let Ok(lc) = s.parse() {
return Ok(Self::LibCall(lc));
}
// Otherwise its a test case name
Ok(Self::testcase(s.as_bytes()))
}
}