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:
@@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
42
cranelift/codegen/src/ir/known_symbol.rs
Normal file
42
cranelift/codegen/src/ir/known_symbol.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
#[cfg(feature = "enable-serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A well-known symbol.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
pub enum KnownSymbol {
|
||||
/// ELF well-known linker symbol _GLOBAL_OFFSET_TABLE_
|
||||
ElfGlobalOffsetTable,
|
||||
}
|
||||
|
||||
impl fmt::Display for KnownSymbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for KnownSymbol {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ElfGlobalOffsetTable" => Ok(Self::ElfGlobalOffsetTable),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parsing() {
|
||||
assert_eq!(
|
||||
"ElfGlobalOffsetTable".parse(),
|
||||
Ok(KnownSymbol::ElfGlobalOffsetTable)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,8 @@ pub enum LibCall {
|
||||
|
||||
/// Elf __tls_get_addr
|
||||
ElfTlsGetAddr,
|
||||
/// Elf __tls_get_offset
|
||||
ElfTlsGetOffset,
|
||||
// When adding a new variant make sure to add it to `all_libcalls` too.
|
||||
}
|
||||
|
||||
@@ -104,6 +106,7 @@ impl FromStr for LibCall {
|
||||
"Memcmp" => Ok(Self::Memcmp),
|
||||
|
||||
"ElfTlsGetAddr" => Ok(Self::ElfTlsGetAddr),
|
||||
"ElfTlsGetOffset" => Ok(Self::ElfTlsGetOffset),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -173,6 +176,7 @@ impl LibCall {
|
||||
Memmove,
|
||||
Memcmp,
|
||||
ElfTlsGetAddr,
|
||||
ElfTlsGetOffset,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -214,7 +218,8 @@ impl LibCall {
|
||||
| LibCall::Memset
|
||||
| LibCall::Memmove
|
||||
| LibCall::Memcmp
|
||||
| LibCall::ElfTlsGetAddr => unimplemented!(),
|
||||
| LibCall::ElfTlsGetAddr
|
||||
| LibCall::ElfTlsGetOffset => unimplemented!(),
|
||||
}
|
||||
|
||||
sig
|
||||
|
||||
@@ -15,6 +15,7 @@ mod heap;
|
||||
pub mod immediates;
|
||||
pub mod instructions;
|
||||
pub mod jumptable;
|
||||
pub(crate) mod known_symbol;
|
||||
pub mod layout;
|
||||
pub(crate) mod libcall;
|
||||
mod memflags;
|
||||
@@ -50,6 +51,7 @@ pub use crate::ir::instructions::{
|
||||
InstructionData, Opcode, ValueList, ValueListPool, VariableArgs,
|
||||
};
|
||||
pub use crate::ir::jumptable::JumpTableData;
|
||||
pub use crate::ir::known_symbol::KnownSymbol;
|
||||
pub use crate::ir::layout::Layout;
|
||||
pub use crate::ir::libcall::{get_probestack_funcref, LibCall};
|
||||
pub use crate::ir::memflags::{Endianness, MemFlags};
|
||||
|
||||
Reference in New Issue
Block a user