forked from OSchip/llvm-project
[ELF][MIPS] Always resolve MIPS GP-relative relocations to 'local' definitions
In case of MIPS, GP-relative relocations always resolve to a definition in a regular input file, ignoring the one-definition rule. Such relocations are used to setup GP relative offsets in a function's prologue. So we, for example, should not attempt to create a dynamic relocation even if the target symbol is preemptible. Fixes bug 27880. Differential Revision: http://reviews.llvm.org/D20664 llvm-svn: 271100
This commit is contained in:
parent
9be88629d5
commit
9a9a3169e3
|
@ -65,6 +65,22 @@ static bool refersToGotEntry(RelExpr Expr) {
|
|||
Expr == R_TLSGD_PC;
|
||||
}
|
||||
|
||||
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
|
||||
// In case of MIPS GP-relative relocations always resolve to a definition
|
||||
// in a regular input file, ignoring the one-definition rule. So we,
|
||||
// for example, should not attempt to create a dynamic relocation even
|
||||
// if the target symbol is preemptible. There are two two MIPS GP-relative
|
||||
// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
|
||||
// can be against a preemptible symbol.
|
||||
// To get MIPS relocation type we apply 0xf mask. In case of O32 ABI all
|
||||
// relocation types occupy eight bit. In case of N64 ABI we extract first
|
||||
// relocation from 3-in-1 packet because only the first relocation can
|
||||
// be against a real symbol.
|
||||
if (Config->EMachine == EM_MIPS && (Type & 0xf) == R_MIPS_GPREL16)
|
||||
return false;
|
||||
return Body.isPreemptible();
|
||||
}
|
||||
|
||||
// Returns the number of relocations processed.
|
||||
template <class ELFT>
|
||||
static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
||||
|
@ -116,7 +132,7 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
|
||||
// Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
|
||||
// depending on the symbol being locally defined or not.
|
||||
if (Body.isPreemptible()) {
|
||||
if (isPreemptible(Body, Type)) {
|
||||
C.Relocations.push_back(
|
||||
{R_RELAX_TLS_GD_TO_IE, Type, Offset, Addend, &Body});
|
||||
if (!Body.isInGot()) {
|
||||
|
@ -135,7 +151,7 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
// Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
|
||||
// defined.
|
||||
if (Target->isTlsInitialExecRel(Type) && !Config->Shared &&
|
||||
!Body.isPreemptible()) {
|
||||
!isPreemptible(Body, Type)) {
|
||||
C.Relocations.push_back(
|
||||
{R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
|
||||
return 1;
|
||||
|
@ -246,7 +262,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
|
|||
if (E == R_GOT || E == R_PLT)
|
||||
return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
|
||||
|
||||
if (Body.isPreemptible())
|
||||
if (isPreemptible(Body, Type))
|
||||
return false;
|
||||
|
||||
if (!Config->Pic)
|
||||
|
@ -348,7 +364,7 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
|
|||
const uint8_t *Data, typename ELFT::uint Offset) {
|
||||
if (Target->needsThunk(Type, File, Body))
|
||||
return R_THUNK;
|
||||
bool Preemptible = Body.isPreemptible();
|
||||
bool Preemptible = isPreemptible(Body, Type);
|
||||
if (Body.isGnuIFunc()) {
|
||||
Expr = toPlt(Expr);
|
||||
} else if (!Preemptible) {
|
||||
|
@ -485,7 +501,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
if (Offset == (uintX_t)-1)
|
||||
continue;
|
||||
|
||||
bool Preemptible = Body.isPreemptible();
|
||||
bool Preemptible = isPreemptible(Body, Type);
|
||||
Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf, Offset);
|
||||
if (HasError)
|
||||
continue;
|
||||
|
@ -504,7 +520,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
}
|
||||
|
||||
if (needsPlt(Expr) || Expr == R_THUNK || refersToGotEntry(Expr) ||
|
||||
!Body.isPreemptible()) {
|
||||
!isPreemptible(Body, Type)) {
|
||||
// If the relocation points to something in the file, we can process it.
|
||||
bool Constant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body);
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Check setup of GP relative offsets in a function's prologue.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
|
||||
# RUN: ld.lld %t.o -shared -o %t.so
|
||||
# RUN: llvm-objdump -d -t %t.so | FileCheck %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# CHECK: Disassembly of section .text:
|
||||
# CHECK-NEXT: foo:
|
||||
# CHECK-NEXT: 10000: 3c 1c 00 01 lui $gp, 1
|
||||
# CHECK-NEXT: 10004: 03 99 e0 2d daddu $gp, $gp, $25
|
||||
# CHECK-NEXT: 10008: 67 9c 7f f0 daddiu $gp, $gp, 32752
|
||||
|
||||
# CHECK: 0000000000027ff0 .got 00000000 .hidden _gp
|
||||
# CHECK: 0000000000010000 .text 00000000 foo
|
||||
|
||||
.text
|
||||
.global foo
|
||||
foo:
|
||||
lui $gp,%hi(%neg(%gp_rel(foo)))
|
||||
daddu $gp,$gp,$t9
|
||||
daddiu $gp,$gp,%lo(%neg(%gp_rel(foo)))
|
Loading…
Reference in New Issue