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;
|
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.
|
// Returns the number of relocations processed.
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
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
|
// Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
|
||||||
// depending on the symbol being locally defined or not.
|
// depending on the symbol being locally defined or not.
|
||||||
if (Body.isPreemptible()) {
|
if (isPreemptible(Body, Type)) {
|
||||||
C.Relocations.push_back(
|
C.Relocations.push_back(
|
||||||
{R_RELAX_TLS_GD_TO_IE, Type, Offset, Addend, &Body});
|
{R_RELAX_TLS_GD_TO_IE, Type, Offset, Addend, &Body});
|
||||||
if (!Body.isInGot()) {
|
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
|
// Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
|
||||||
// defined.
|
// defined.
|
||||||
if (Target->isTlsInitialExecRel(Type) && !Config->Shared &&
|
if (Target->isTlsInitialExecRel(Type) && !Config->Shared &&
|
||||||
!Body.isPreemptible()) {
|
!isPreemptible(Body, Type)) {
|
||||||
C.Relocations.push_back(
|
C.Relocations.push_back(
|
||||||
{R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
|
{R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -246,7 +262,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
|
||||||
if (E == R_GOT || E == R_PLT)
|
if (E == R_GOT || E == R_PLT)
|
||||||
return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
|
return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
|
||||||
|
|
||||||
if (Body.isPreemptible())
|
if (isPreemptible(Body, Type))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!Config->Pic)
|
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) {
|
const uint8_t *Data, typename ELFT::uint Offset) {
|
||||||
if (Target->needsThunk(Type, File, Body))
|
if (Target->needsThunk(Type, File, Body))
|
||||||
return R_THUNK;
|
return R_THUNK;
|
||||||
bool Preemptible = Body.isPreemptible();
|
bool Preemptible = isPreemptible(Body, Type);
|
||||||
if (Body.isGnuIFunc()) {
|
if (Body.isGnuIFunc()) {
|
||||||
Expr = toPlt(Expr);
|
Expr = toPlt(Expr);
|
||||||
} else if (!Preemptible) {
|
} else if (!Preemptible) {
|
||||||
|
@ -485,7 +501,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
if (Offset == (uintX_t)-1)
|
if (Offset == (uintX_t)-1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool Preemptible = Body.isPreemptible();
|
bool Preemptible = isPreemptible(Body, Type);
|
||||||
Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf, Offset);
|
Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf, Offset);
|
||||||
if (HasError)
|
if (HasError)
|
||||||
continue;
|
continue;
|
||||||
|
@ -504,7 +520,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsPlt(Expr) || Expr == R_THUNK || refersToGotEntry(Expr) ||
|
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.
|
// If the relocation points to something in the file, we can process it.
|
||||||
bool Constant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body);
|
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