summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp2
-rw-r--r--lld/ELF/OutputSections.cpp22
-rw-r--r--lld/ELF/OutputSections.h3
-rw-r--r--lld/ELF/Target.cpp8
-rw-r--r--lld/ELF/Target.h2
-rw-r--r--lld/test/elf2/ppc64-shared-rel-toc.s27
6 files changed, 47 insertions, 17 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 8a0a5898e03..90823a8e755 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -57,7 +57,7 @@ void InputSection<ELFT>::relocate(
// resolved so we don't allocate a SymbolBody.
const Elf_Shdr *SymTab = File.getSymbolTable();
if (SymIndex < SymTab->sh_info) {
- uintX_t SymVA = getLocalRelTarget(File, RI);
+ uintX_t SymVA = getLocalRelTarget(File, RI, Type);
relocateOne(Buf, BufEnd, RI, Type, BaseAddr, SymVA);
continue;
}
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 7f7b970a72f..a8545c301ed 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -126,7 +126,7 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
if (Body)
Addend += getSymVA<ELFT>(cast<ELFSymbolBody<ELFT>>(*Body));
else
- Addend += getLocalRelTarget(File, RI);
+ Addend += getLocalRelTarget(File, RI, Type);
}
P->setSymbolAndType(0, Target->getRelativeReloc(), IsMips64EL);
}
@@ -424,15 +424,19 @@ typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) {
template <class ELFT>
typename ELFFile<ELFT>::uintX_t
lld::elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
- const typename ELFFile<ELFT>::Elf_Rel &RI) {
+ const typename ELFFile<ELFT>::Elf_Rel &RI,
+ uint32_t Type) {
+ // PPC64 has a special relocation representing the TOC base pointer
+ // that does not have a corresponding symbol.
+ if (Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
+ return getPPC64TocBase();
+
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
const Elf_Sym *Sym =
File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
- // For certain special relocations, such as R_PPC64_TOC, there's no
- // corresponding symbol. Just return 0 in that case.
if (!Sym)
- return 0;
+ error("Unsupported relocation without symbol");
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
@@ -743,19 +747,19 @@ template ELFFile<ELF64BE>::uintX_t getSymVA<ELF64BE>(const SymbolBody &);
template ELFFile<ELF32LE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF32LE> &,
- const ELFFile<ELF32LE>::Elf_Rel &);
+ const ELFFile<ELF32LE>::Elf_Rel &, uint32_t);
template ELFFile<ELF32BE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF32BE> &,
- const ELFFile<ELF32BE>::Elf_Rel &);
+ const ELFFile<ELF32BE>::Elf_Rel &, uint32_t);
template ELFFile<ELF64LE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF64LE> &,
- const ELFFile<ELF64LE>::Elf_Rel &);
+ const ELFFile<ELF64LE>::Elf_Rel &, uint32_t);
template ELFFile<ELF64BE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF64BE> &,
- const ELFFile<ELF64BE>::Elf_Rel &);
+ const ELFFile<ELF64BE>::Elf_Rel &, uint32_t);
template bool includeInSymtab<ELF32LE>(const SymbolBody &);
template bool includeInSymtab<ELF32BE>(const SymbolBody &);
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 0892ce81834..4c62f70d863 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -38,7 +38,8 @@ typename llvm::object::ELFFile<ELFT>::uintX_t getSymVA(const SymbolBody &S);
template <class ELFT>
typename llvm::object::ELFFile<ELFT>::uintX_t
getLocalRelTarget(const ObjectFile<ELFT> &File,
- const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Sym);
+ const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Sym,
+ uint32_t Type);
bool canBePreempted(const SymbolBody *Body, bool NeedsGot);
template <class ELFT> bool includeInSymtab(const SymbolBody &B);
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 4ecc80b592c..f45b6c54c2c 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -345,7 +345,7 @@ PPC64TargetInfo::PPC64TargetInfo() {
VAStart = 0x10000000;
}
-static uint64_t getPPC64TocBase() {
+uint64_t getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that
// order. The TOC starts where the first of these sections starts.
@@ -426,11 +426,6 @@ void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
uint64_t P = BaseAddr + Rel.r_offset;
uint64_t TB = getPPC64TocBase();
- if (Type == R_PPC64_TOC) {
- write64be(L, TB);
- return;
- }
-
// For a TOC-relative relocation, adjust the addend and proceed in terms of
// the corresponding ADDR16 relocation type.
switch (Type) {
@@ -536,6 +531,7 @@ void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
write64be(L, SA - P);
break;
case R_PPC64_ADDR64:
+ case R_PPC64_TOC:
write64be(L, SA);
break;
default:
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index ff770e1a477..1faaf02931d 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -58,6 +58,8 @@ protected:
unsigned PltEntrySize = 8;
};
+uint64_t getPPC64TocBase();
+
extern std::unique_ptr<TargetInfo> Target;
TargetInfo *createTarget();
}
diff --git a/lld/test/elf2/ppc64-shared-rel-toc.s b/lld/test/elf2/ppc64-shared-rel-toc.s
new file mode 100644
index 00000000000..2b3ad51afa0
--- /dev/null
+++ b/lld/test/elf2/ppc64-shared-rel-toc.s
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld2 -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+// REQUIRES: ppc
+
+// When we create the TOC reference in the shared library, make sure that the
+// R_PPC64_RELATIVE relocation uses the correct (non-zero) offset.
+
+ .globl foo
+ .align 2
+ .type foo,@function
+ .section .opd,"aw",@progbits
+foo: # @foo
+ .align 3
+ .quad .Lfunc_begin0
+ .quad .TOC.@tocbase
+ .quad 0
+ .text
+.Lfunc_begin0:
+ blr
+
+// CHECK: 0x20090 R_PPC64_RELATIVE - 0x10000
+// CHECK: 0x20098 R_PPC64_RELATIVE - 0x8000
+
+// CHECK: Name: foo (20)
+// CHECK-NEXT: Value: 0x20090
+
OpenPOWER on IntegriCloud