[ELF][MIPS] Put local GOT entries accessed via a 16-bit index first
Some MIPS relocations used to access GOT entries are able to manipulate 16-bit index. The other ones like R_MIPS_CALL_HI16/LO16 can handle 32-bit indexes. 16-bit relocations are generated by default. The 32-bit relocations are generated by -mxgot flag passed to compiler. Usually these relocation are not mixed in the same code but files like crt*.o contain 16-bit relocations so even if all "user's" code compiled with -mxgot flag a few 16-bit relocations might come to the linking phase. Now LLD does not differentiate local GOT entries accessed via a 16-bit and 32-bit indexes. That might lead to relocation's overflow if 16-bit entries are allocated to far from the beginning of the GOT. The patch introduces new "part" of MIPS GOT dedicated to the local GOT entries accessed by 32-bit relocations. That allows to put local GOT entries accessed via a 16-bit index first and escape relocation's overflow. Differential revision: https://reviews.llvm.org/D25833 llvm-svn: 284809
This commit is contained in:
parent
c1db0db864
commit
bed04bf1df
|
@ -325,6 +325,7 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
|
|||
// of sum the symbol's value and the addend.
|
||||
return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
|
||||
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.
|
||||
|
|
|
@ -202,8 +202,15 @@ void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
|
|||
// Ignore addends for preemptible symbols. They got single GOT entry anyway.
|
||||
AddEntry(Sym, 0, MipsGlobal);
|
||||
Sym.IsInGlobalMipsGot = true;
|
||||
} else
|
||||
} else if (Expr == R_MIPS_GOT_OFF32) {
|
||||
AddEntry(Sym, Addend, MipsLocal32);
|
||||
Sym.Is32BitMipsGot = true;
|
||||
} else {
|
||||
// Hold local GOT entries accessed via a 16-bit index separately.
|
||||
// That allows to write them in the beginning of the GOT and keep
|
||||
// their indexes as less as possible to escape relocation's overflow.
|
||||
AddEntry(Sym, Addend, MipsLocal);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
|
||||
|
@ -250,6 +257,8 @@ GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
|
|||
GotBlockOff = getMipsTlsOffset();
|
||||
else if (B.IsInGlobalMipsGot)
|
||||
GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t);
|
||||
else if (B.Is32BitMipsGot)
|
||||
GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t);
|
||||
else
|
||||
GotBlockOff = MipsPageEntries * sizeof(uintX_t);
|
||||
// Calculate index of the GOT entry in the block.
|
||||
|
@ -288,7 +297,7 @@ const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
|
|||
|
||||
template <class ELFT>
|
||||
unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
|
||||
return MipsPageEntries + MipsLocal.size();
|
||||
return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::finalize() {
|
||||
|
@ -347,6 +356,7 @@ template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
|
|||
writeUint<ELFT>(Entry, VA);
|
||||
};
|
||||
std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
|
||||
std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry);
|
||||
std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
|
||||
// Initialize TLS-related GOT entries. If the entry has a corresponding
|
||||
// dynamic relocations, leave it initialized by zero. Write down adjusted
|
||||
|
|
|
@ -217,6 +217,7 @@ private:
|
|||
typedef std::vector<MipsGotEntry> MipsGotEntries;
|
||||
llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
|
||||
MipsGotEntries MipsLocal;
|
||||
MipsGotEntries MipsLocal32;
|
||||
MipsGotEntries MipsGlobal;
|
||||
|
||||
// Write MIPS-specific parts of the GOT.
|
||||
|
|
|
@ -62,10 +62,11 @@ namespace elf {
|
|||
|
||||
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_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;
|
||||
Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_GOT_OFF32 ||
|
||||
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;
|
||||
}
|
||||
|
||||
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
|
||||
|
@ -303,11 +304,11 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
|
|||
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_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_CALL || E == R_TLSDESC_PAGE || E == R_HINT ||
|
||||
E == R_THUNK_PC || E == R_THUNK_PLT_PC)
|
||||
E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF ||
|
||||
E == R_MIPS_GOT_OFF32 || 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_CALL || E == R_TLSDESC_PAGE ||
|
||||
E == R_HINT || E == R_THUNK_PC || E == R_THUNK_PLT_PC)
|
||||
return true;
|
||||
|
||||
// These never do, except if the entire file is position dependent or if
|
||||
|
|
|
@ -36,6 +36,7 @@ enum RelExpr {
|
|||
R_HINT,
|
||||
R_MIPS_GOT_LOCAL_PAGE,
|
||||
R_MIPS_GOT_OFF,
|
||||
R_MIPS_GOT_OFF32,
|
||||
R_MIPS_TLSGD,
|
||||
R_MIPS_TLSLD,
|
||||
R_NEG_TLS,
|
||||
|
|
|
@ -93,13 +93,13 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
|
|||
SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
|
||||
uint8_t Type)
|
||||
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
|
||||
IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
|
||||
NameOffset(NameOffset) {}
|
||||
IsInGlobalMipsGot(false), Is32BitMipsGot(false), Type(Type),
|
||||
StOther(StOther), NameOffset(NameOffset) {}
|
||||
|
||||
SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
|
||||
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
|
||||
IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
|
||||
Name({Name.data(), Name.size()}) {}
|
||||
IsInGlobalMipsGot(false), Is32BitMipsGot(false), Type(Type),
|
||||
StOther(StOther), Name({Name.data(), Name.size()}) {}
|
||||
|
||||
StringRef SymbolBody::getName() const {
|
||||
assert(!isLocal());
|
||||
|
|
|
@ -120,6 +120,9 @@ public:
|
|||
// True if this symbol has an entry in the global part of MIPS GOT.
|
||||
unsigned IsInGlobalMipsGot : 1;
|
||||
|
||||
// True if this symbol is referenced by 32-bit GOT relocations.
|
||||
unsigned Is32BitMipsGot : 1;
|
||||
|
||||
// The following fields have the same meaning as the ELF symbol attributes.
|
||||
uint8_t Type; // symbol type
|
||||
uint8_t StOther; // st_other field value
|
||||
|
|
|
@ -1940,13 +1940,14 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
|
|||
return R_MIPS_GOT_LOCAL_PAGE;
|
||||
// fallthrough
|
||||
case R_MIPS_CALL16:
|
||||
case R_MIPS_CALL_HI16:
|
||||
case R_MIPS_CALL_LO16:
|
||||
case R_MIPS_GOT_DISP:
|
||||
case R_MIPS_GOT_HI16:
|
||||
case R_MIPS_GOT_LO16:
|
||||
case R_MIPS_TLS_GOTTPREL:
|
||||
return R_MIPS_GOT_OFF;
|
||||
case R_MIPS_CALL_HI16:
|
||||
case R_MIPS_CALL_LO16:
|
||||
case R_MIPS_GOT_HI16:
|
||||
case R_MIPS_GOT_LO16:
|
||||
return R_MIPS_GOT_OFF32;
|
||||
case R_MIPS_GOT_PAGE:
|
||||
return R_MIPS_GOT_LOCAL_PAGE;
|
||||
case R_MIPS_TLS_GD:
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# Check that GOT entries accessed via 16-bit indexing are allocated
|
||||
# in the beginning of the GOT.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t.exe
|
||||
# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# CHECK: Disassembly of section .text:
|
||||
# CHECK-NEXT: __start:
|
||||
# CHECK-NEXT: 20000: 3c 02 00 00 lui $2, 0
|
||||
# CHECK-NEXT: 20004: 8c 42 80 20 lw $2, -32736($2)
|
||||
# CHECK-NEXT: 20008: 3c 02 00 00 lui $2, 0
|
||||
# CHECK-NEXT: 2000c: 8c 42 80 24 lw $2, -32732($2)
|
||||
#
|
||||
# CHECK: bar:
|
||||
# CHECK-NEXT: 20010: 8c 42 80 1c lw $2, -32740($2)
|
||||
# CHECK-NEXT: 20014: 8c 42 80 18 lw $2, -32744($2)
|
||||
# CHECK-NEXT: 20018: 20 42 00 00 addi $2, $2, 0
|
||||
|
||||
# CHECK: Contents of section .got:
|
||||
# CHECK-NEXT: 30000 00000000 80000000 00040000 00020010
|
||||
# ^ %hi(loc)
|
||||
# ^ %got(bar)
|
||||
# CHECK-NEXT: 30010 00020000 00040000
|
||||
# ^ %got_hi/lo(start)
|
||||
# ^ %got_hi/lo(loc)
|
||||
|
||||
# CHECK: 00040000 .data 00000000 loc
|
||||
# CHECK: 00020000 .text 00000000 __start
|
||||
# CHECK: 00020010 .text 00000000 bar
|
||||
|
||||
.text
|
||||
.global __start, bar
|
||||
__start:
|
||||
lui $2, %got_hi(__start)
|
||||
lw $2, %got_lo(__start)($2)
|
||||
lui $2, %got_hi(loc)
|
||||
lw $2, %got_lo(loc)($2)
|
||||
bar:
|
||||
lw $2, %got(bar)($2)
|
||||
lw $2, %got(loc)($2)
|
||||
addi $2, $2, %lo(loc)
|
||||
|
||||
.data
|
||||
loc:
|
||||
.word 0
|
Loading…
Reference in New Issue