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

@@ -121,6 +121,7 @@ pub struct ObjectModule {
relocs: Vec<SymbolRelocs>,
libcalls: HashMap<ir::LibCall, SymbolId>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
known_symbols: HashMap<ir::KnownSymbol, SymbolId>,
function_alignment: u64,
per_function_section: bool,
anon_func_number: u64,
@@ -141,6 +142,7 @@ impl ObjectModule {
relocs: Vec::new(),
libcalls: HashMap::new(),
libcall_names: builder.libcall_names,
known_symbols: HashMap::new(),
function_alignment: builder.function_alignment,
per_function_section: builder.per_function_section,
anon_func_number: 0,
@@ -547,6 +549,28 @@ impl ObjectModule {
symbol
}
}
// These are "magic" names well-known to the linker.
// They require special treatment.
ir::ExternalName::KnownSymbol(ref known_symbol) => {
if let Some(symbol) = self.known_symbols.get(known_symbol) {
*symbol
} else {
let symbol = match known_symbol {
ir::KnownSymbol::ElfGlobalOffsetTable => self.object.add_symbol(Symbol {
name: "_GLOBAL_OFFSET_TABLE_".as_bytes().to_vec(),
value: 0,
size: 0,
kind: SymbolKind::Data,
scope: SymbolScope::Unknown,
weak: false,
section: SymbolSection::Undefined,
flags: SymbolFlags::None,
}),
};
self.known_symbols.insert(*known_symbol, symbol);
symbol
}
}
_ => panic!("invalid ExternalName {}", name),
}
}