[lld] r287832 - [ELF][MIPS] Fix handling of _gp/_gp_disp/__gnu_local_gp symbols
Simon Atanasyan via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 23 14:22:17 PST 2016
Author: atanasyan
Date: Wed Nov 23 16:22:16 2016
New Revision: 287832
URL: http://llvm.org/viewvc/llvm-project?rev=287832&view=rev
Log:
[ELF][MIPS] Fix handling of _gp/_gp_disp/__gnu_local_gp symbols
Offset between beginning of a .got section and _gp symbols used in MIPS
GOT relocations calculations. Usually the expression looks like
VA + Offset - GP, where VA is the .got section address, Offset - offset
of the GOT entry, GP - offset between .got and _gp. Also there two "magic"
symbols _gp_disp and __gnu_local_gp which hold the offset mentioned above.
These symbols might be referenced by MIPS relocations.
Now the linker always defines _gp symbol and uses hardcoded value for
its initialization. So offset between .got and _gp is 0x7ff0. The _gp_disp
and __gnu_local_gp defined if required and initialized by 0x7ff0.
In fact that is not correct because _gp symbol might be defined by a linker
script and holds arbitrary value. In that case we need to use this value
in relocation calculation and initialize _gp_disp and __gnu_local_gp
properly.
The patch fixes the problem and completes fixing the bug #30311.
https://llvm.org/bugs/show_bug.cgi?id=30311
Differential revision: https://reviews.llvm.org/D27036
Added:
lld/trunk/test/ELF/mips-gp-ext.s
Modified:
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/SyntheticSections.cpp
lld/trunk/ELF/SyntheticSections.h
lld/trunk/ELF/Target.h
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=287832&r1=287831&r2=287832&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed Nov 23 16:22:16 2016
@@ -389,21 +389,26 @@ static typename ELFT::uint getSymVA(uint
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
- return In<ELFT>::MipsGot->getPageEntryOffset(Body.getVA<ELFT>(A));
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getPageEntryOffset(Body.getVA<ELFT>(A)) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
// should be applied to the GOT entry content not to the GOT entry offset.
// That is why we use separate expression type.
- return In<ELFT>::MipsGot->getBodyEntryOffset(Body, A);
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_GOTREL:
- return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getVA() - MipsGPOffset;
+ return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSGD:
- return In<ELFT>::MipsGot->getGlobalDynOffset(Body) +
- In<ELFT>::MipsGot->getTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSLD:
- return In<ELFT>::MipsGot->getTlsIndexOff() +
- In<ELFT>::MipsGot->getTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
case R_PPC_OPD: {
uint64_t SymVA = Body.getVA<ELFT>(A);
// If we have an undefined weak symbol, we might get here with a symbol
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=287832&r1=287831&r2=287832&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Wed Nov 23 16:22:16 2016
@@ -361,8 +361,10 @@ template <class ELFT> struct ElfSym {
static DefinedRegular<ELFT> *End;
static DefinedRegular<ELFT> *End2;
- // The content for _gp_disp symbol for MIPS target.
- static SymbolBody *MipsGpDisp;
+ // The content for _gp_disp/__gnu_local_gp symbols for MIPS target.
+ static DefinedRegular<ELFT> *MipsGpDisp;
+ static DefinedRegular<ELFT> *MipsLocalGp;
+ static SymbolBody *MipsGp;
};
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart;
@@ -372,7 +374,9 @@ template <class ELFT> DefinedRegular<ELF
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
-template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGpDisp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp;
+template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGp;
// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
// always one Symbol for each symbol name. The resolver updates the SymbolBody
Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=287832&r1=287831&r2=287832&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Wed Nov 23 16:22:16 2016
@@ -177,7 +177,7 @@ template <class ELFT> void MipsOptionsSe
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getVA() + MipsGPOffset;
+ Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
memcpy(Buf + sizeof(typename ELFT::uint), &Reginfo, sizeof(Reginfo));
}
@@ -233,7 +233,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSec
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getVA() + MipsGPOffset;
+ Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
@@ -546,7 +546,7 @@ MipsGotSection<ELFT>::getPageEntryOffset
size_t NewIndex = PageIndexMap.size() + 2;
auto P = PageIndexMap.insert(std::make_pair(EntryValue, NewIndex));
assert(!P.second || PageIndexMap.size() <= PageEntriesNum);
- return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
+ return (uintX_t)P.first->second * sizeof(uintX_t);
}
template <class ELFT>
@@ -572,7 +572,7 @@ MipsGotSection<ELFT>::getBodyEntryOffset
assert(It != EntryIndexMap.end());
GotIndex = It->second;
}
- return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset;
+ return GotBlockOff + GotIndex * sizeof(uintX_t);
}
template <class ELFT>
@@ -614,6 +614,10 @@ template <class ELFT> void MipsGotSectio
Size = EntriesNum * sizeof(uintX_t);
}
+template <class ELFT> unsigned MipsGotSection<ELFT>::getGp() const {
+ return ElfSym<ELFT>::MipsGp->template getVA<ELFT>(0);
+}
+
template <class ELFT>
static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
typedef typename ELFT::uint uintX_t;
Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=287832&r1=287831&r2=287832&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Wed Nov 23 16:22:16 2016
@@ -122,6 +122,8 @@ public:
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
+ unsigned getGp() const;
+
private:
// MIPS GOT consists of three parts: local, global and tls. Each part
// contains different types of entries. Here is a layout of GOT:
Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=287832&r1=287831&r2=287832&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Wed Nov 23 16:22:16 2016
@@ -105,8 +105,6 @@ public:
std::string toString(uint32_t RelType);
uint64_t getPPC64TocBase();
-const unsigned MipsGPOffset = 0x7ff0;
-
extern TargetInfo *Target;
TargetInfo *createTarget();
}
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=287832&r1=287831&r2=287832&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Nov 23 16:22:16 2016
@@ -605,22 +605,22 @@ template <class ELFT> void Writer<ELFT>:
if (Config->EMachine == EM_MIPS) {
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
// so that it points to an absolute address which is relative to GOT.
+ // Default offset is 0x7ff0.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- addRegular("_gp", In<ELFT>::MipsGot, MipsGPOffset);
+ ElfSym<ELFT>::MipsGp = addRegular("_gp", In<ELFT>::MipsGot, 0x7ff0)->body();
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
// start of function and 'gp' pointer into GOT.
- Symbol *Sym =
- addOptionalRegular("_gp_disp", In<ELFT>::MipsGot, MipsGPOffset);
- if (Sym)
- ElfSym<ELFT>::MipsGpDisp = Sym->body();
+ if (Symbol *S = addOptionalRegular("_gp_disp", In<ELFT>::MipsGot, 0))
+ ElfSym<ELFT>::MipsGpDisp = cast<DefinedRegular<ELFT>>(S->body());
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// pointer. This symbol is used in the code generated by .cpload pseudo-op
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
- addOptionalRegular("__gnu_local_gp", In<ELFT>::MipsGot, MipsGPOffset);
+ if (Symbol *S = addOptionalRegular("__gnu_local_gp", In<ELFT>::MipsGot, 0))
+ ElfSym<ELFT>::MipsLocalGp = cast<DefinedRegular<ELFT>>(S->body());
}
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
@@ -1413,6 +1413,16 @@ template <class ELFT> void Writer<ELFT>:
else
Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
}
+
+ // Setup MIPS _gp_disp/__gnu_local_gp symbols which should
+ // be equal to the _gp symbol's value.
+ if (Config->EMachine == EM_MIPS) {
+ uintX_t GpDisp = In<ELFT>::MipsGot->getGp() - In<ELFT>::MipsGot->getVA();
+ if (ElfSym<ELFT>::MipsGpDisp)
+ ElfSym<ELFT>::MipsGpDisp->Value = GpDisp;
+ if (ElfSym<ELFT>::MipsLocalGp)
+ ElfSym<ELFT>::MipsLocalGp->Value = GpDisp;
+ }
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
Added: lld/trunk/test/ELF/mips-gp-ext.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-gp-ext.s?rev=287832&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-gp-ext.s (added)
+++ lld/trunk/test/ELF/mips-gp-ext.s Wed Nov 23 16:22:16 2016
@@ -0,0 +1,41 @@
+# Check that the linker use a value of _gp symbol defined
+# in a linker script to calculate GOT relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: _gp = . + 0x100; \
+# RUN: .got : { *(.got) } }" > %t.script
+# RUN: ld.lld -shared -o %t.so --script %t.script %t.o
+# RUN: llvm-objdump -s -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 0000 3c080000 2108010c 8f82ffe4
+# ^-- %hi(_gp_disp)
+# ^-- %lo(_gp_disp)
+# ^-- 8 - (0x10c - 0xe8)
+# G - (GP - .got)
+
+# CHECK: Contents of section .reginfo:
+# CHECK-NEXT: 0028 10000104 00000000 00000000 00000000
+# CHECK-NEXT: 0038 00000000 0000010c
+# ^-- _gp
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 0100 fffffef4
+# ^-- 0-0x10c
+
+# CHECK: 00000000 .text 00000000 foo
+# CHECK: 0000010c .got 00000000 .hidden _gp_disp
+# CHECK: 0000010c .text 00000000 .hidden _gp
+
+ .text
+foo:
+ lui $t0, %hi(_gp_disp)
+ addi $t0, $t0, %lo(_gp_disp)
+ lw $v0, %call16(bar)($gp)
+
+ .data
+ .gpword foo
More information about the llvm-commits
mailing list