[ELF][MIPS] Support MIPS TLS relocations
The patch adds one more partition to the MIPS GOT. This time it is for
TLS related GOT entries. Such entries are located after 'local' and 'global'
ones. We cannot get a final offset for these entries at the time of
creation because we do not know size of 'local' and 'global' partitions.
So we have to adjust the offset later using `getMipsTlsOffset()` method.
All MIPS TLS relocations which need GOT entries operates MIPS style GOT
offset - 'offset from the GOT's beginning' - MipsGPOffset constant. That
is why I add new types of relocation expressions.
One more difference from othe ABIs is that the MIPS ABI does not support
any TLS relocation relaxations. I decided to make a separate function
`handleMipsTlsRelocation` and put MIPS TLS relocation handling code
there. It is similar to `handleTlsRelocation` routine and duplicates its
code. But it allows to make the code cleaner and prevent pollution of
the `handleTlsRelocation` by MIPS 'if' statements.
Differential Revision: http://reviews.llvm.org/D21606
llvm-svn: 273569
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 5cf0a61..a54c449 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -60,7 +60,8 @@
static bool refersToGotEntry(RelExpr Expr) {
return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE ||
- Expr == R_MIPS_GOT_OFF || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
+ Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD ||
+ Expr == R_MIPS_TLSLD || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC ||
Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
}
@@ -81,6 +82,39 @@
return Body.isPreemptible();
}
+// This function is similar to the `handleTlsRelocation`. MIPS does not support
+// any relaxations for TLS relocations so by factoring out MIPS handling into
+// the separate function we can simplify the code and does not pollute
+// `handleTlsRelocation` by MIPS `ifs` statements.
+template <class ELFT>
+static unsigned
+handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase<ELFT> &C, typename ELFT::uint Offset,
+ typename ELFT::uint Addend, RelExpr Expr) {
+ if (Expr == R_MIPS_TLSLD) {
+ if (Out<ELFT>::Got->addTlsIndex())
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
+ Out<ELFT>::Got->getTlsIndexOff(), false,
+ nullptr, 0});
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+ if (Target->isTlsGlobalDynamicRel(Type)) {
+ if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+ typedef typename ELFT::uint uintX_t;
+ uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+ Off + (uintX_t)sizeof(uintX_t), false,
+ &Body, 0});
+ }
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+ return 0;
+}
+
// Returns the number of relocations processed.
template <class ELFT>
static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
@@ -95,6 +129,9 @@
typedef typename ELFT::uint uintX_t;
+ if (Config->EMachine == EM_MIPS)
+ return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+
if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
Config->Shared) {
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
@@ -254,9 +291,9 @@
const SymbolBody &Body) {
// These expressions always compute a constant
if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
- E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_GOT_PAGE_PC ||
- E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || E == R_TLSGD ||
- E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
+ E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD ||
+ E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC ||
+ E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
return true;
// These never do, except if the entire file is position dependent or if
@@ -603,6 +640,9 @@
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+ if (Body.isTls())
+ AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+ !Preemptible, &Body, 0});
continue;
}