summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputFiles.cpp10
-rw-r--r--lld/ELF/InputFiles.h8
-rw-r--r--lld/ELF/InputSection.cpp13
-rw-r--r--lld/ELF/InputSection.h1
-rw-r--r--lld/ELF/Target.cpp10
-rw-r--r--lld/test/ELF/mips-gprel32-relocs.test31
6 files changed, 71 insertions, 2 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index a68d83626d3..e0827a3ee43 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -93,6 +93,10 @@ typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
return this->getSymbolsHelper(true);
}
+template <class ELFT> uint32_t ObjectFile<ELFT>::getMipsGp0() const {
+ return MipsReginfo ? MipsReginfo->getGp0() : 0;
+}
+
template <class ELFT>
const typename ObjectFile<ELFT>::Elf_Sym *
ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) {
@@ -245,8 +249,10 @@ elf2::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// A MIPS object file has a special section that contains register
// usage info, which needs to be handled by the linker specially.
- if (Config->EMachine == EM_MIPS && Name == ".reginfo")
- return new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
+ if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
+ MipsReginfo = new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
+ return MipsReginfo;
+ }
if (Name == ".eh_frame")
return new (this->EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 8363acb9f2b..4e529c558cf 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -121,6 +121,11 @@ public:
const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
+ // Get MIPS GP0 value defined by this file. This value represents the gp value
+ // used to create the relocatable object and required to support
+ // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
+ uint32_t getMipsGp0() const;
+
private:
void initializeSections(llvm::DenseSet<StringRef> &Comdats);
void initializeSymbols();
@@ -134,6 +139,9 @@ private:
// List of all symbols referenced or defined by this file.
std::vector<SymbolBody *> SymbolBodies;
+ // MIPS .reginfo section defined by this file.
+ MipsReginfoInputSection<ELFT> *MipsReginfo = nullptr;
+
llvm::BumpPtrAllocator Alloc;
llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 1b45ec7a559..2548200feb6 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -187,6 +187,12 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
uintX_t A = getAddend<ELFT>(RI);
if (!Body) {
uintX_t SymVA = getLocalRelTarget(*File, RI, A);
+ // We need to adjust SymVA value in case of R_MIPS_GPREL16/32 relocations
+ // because they use the following expression to calculate the relocation's
+ // result for local symbol: S + A + GP0 - G.
+ if (Config->EMachine == EM_MIPS &&
+ (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
+ SymVA += File->getMipsGp0();
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
continue;
@@ -351,6 +357,13 @@ uint32_t MipsReginfoInputSection<ELFT>::getGeneralMask() const {
return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gprmask;
}
+template <class ELFT> uint32_t MipsReginfoInputSection<ELFT>::getGp0() const {
+ ArrayRef<uint8_t> D = this->getSectionData();
+ if (D.size() != sizeof(Elf_Mips_RegInfo))
+ error("Invalid size of .reginfo section");
+ return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gp_value;
+}
+
template <class ELFT>
bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 2f955c2f687..d4dc9864ae9 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -176,6 +176,7 @@ public:
MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
uint32_t getGeneralMask() const;
+ uint32_t getGp0() const;
static bool classof(const InputSectionBase<ELFT> *S);
};
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index a80c672b8d2..8d848d040c6 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -1382,6 +1382,16 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
write32<E>(Loc, (read32<E>(Loc) & 0xffff0000) | (V & 0xffff));
break;
}
+ case R_MIPS_GPREL16: {
+ uint32_t Instr = read32<E>(Loc);
+ int64_t V = SA + SignExtend64<16>(Instr & 0xffff) - getMipsGpAddr<ELFT>();
+ checkInt<16>(V, Type);
+ write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
+ break;
+ }
+ case R_MIPS_GPREL32:
+ write32<E>(Loc, SA + int32_t(read32<E>(Loc)) - getMipsGpAddr<ELFT>());
+ break;
case R_MIPS_HI16: {
uint32_t Instr = read32<E>(Loc);
if (PairedLoc) {
diff --git a/lld/test/ELF/mips-gprel32-relocs.test b/lld/test/ELF/mips-gprel32-relocs.test
new file mode 100644
index 00000000000..4f93d50363c
--- /dev/null
+++ b/lld/test/ELF/mips-gprel32-relocs.test
@@ -0,0 +1,31 @@
+# Check R_MIPS_GPREL32 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o
+# RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+ .text
+ .globl __start
+__start:
+ lw $t0,%call16(__start)($gp)
+foo:
+ nop
+bar:
+ nop
+
+ .section .rodata, "a"
+v1:
+ .gpword foo
+ .gpword bar
+
+# CHECK: Contents of section .rodata:
+# CHECK: 0114 fffe8014 fffe8018
+# ^ 0x10004 - 0x27ff0
+# ^ 0x10008 - 0x27ff0
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00010008 .text 00000000 bar
+# CHECK: 00010004 .text 00000000 foo
+# CHECK: 00027ff0 *ABS* 00000000 _gp
OpenPOWER on IntegriCloud