summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2014-05-05 05:56:06 +0000
committerSimon Atanasyan <simon@atanasyan.com>2014-05-05 05:56:06 +0000
commite22ca466811a619d0d8c30ddd2eeffc2d735d8d9 (patch)
treea41b3239ec57743c76f0e3b24b2eb0a4ff5fbe6e
parent527040e0c87ac8d6cdde46be51c1a93e098bb5fd (diff)
downloadbcm5719-llvm-e22ca466811a619d0d8c30ddd2eeffc2d735d8d9.tar.gz
bcm5719-llvm-e22ca466811a619d0d8c30ddd2eeffc2d735d8d9.zip
[Mips] R_MIPS_GPREL32 relocation support.
llvm-svn: 207949
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h61
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp11
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp35
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp1
-rw-r--r--lld/test/elf/Mips/rel-gprel32.test84
5 files changed, 187 insertions, 5 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
index 34c938673a4..735a4c0f112 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
@@ -12,6 +12,31 @@
#include "ELFReader.h"
#include "MipsLinkingContext.h"
+namespace llvm {
+namespace object {
+
+template <class ELFT>
+struct Elf_RegInfo;
+
+template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
+struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, false>> {
+ LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, false)
+ Elf_Word ri_gprmask; // bit-mask of used general registers
+ Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
+ Elf_Sword ri_gp_value; // gp register value
+};
+
+template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
+struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, true>> {
+ LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, true)
+ Elf_Word ri_gprmask; // bit-mask of used general registers
+ Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
+ Elf_Sword ri_gp_value; // gp register value
+};
+
+} // end namespace object.
+} // end namespace llvm.
+
namespace lld {
namespace elf {
@@ -44,7 +69,7 @@ public:
MipsELFFile(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings,
error_code &ec)
- : ELFFile<ELFT>(std::move(mb), atomizeStrings, ec) {}
+ : ELFFile<ELFT>(std::move(mb), atomizeStrings, ec), _gp0(0) {}
static ErrorOr<std::unique_ptr<MipsELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
@@ -76,6 +101,10 @@ public:
if ((ec = file->createAtoms()))
return ec;
+ // Retrieve registry usage descriptor and GP value.
+ if ((ec = file->readRegInfo()))
+ return ec;
+
return std::move(file);
}
@@ -83,12 +112,17 @@ public:
return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
}
+ /// \brief gp register value stored in the .reginfo section.
+ int64_t getGP0() const { return _gp0; }
+
private:
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
+ int64_t _gp0;
+
ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(
StringRef symName, StringRef sectionName, const Elf_Sym *sym,
const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData,
@@ -99,6 +133,30 @@ private:
referenceStart, referenceEnd, referenceList);
}
+ error_code readRegInfo() {
+ typedef llvm::object::Elf_RegInfo<ELFT> Elf_RegInfo;
+
+ for (auto sit = this->_objFile->begin_sections(),
+ sie = this->_objFile->end_sections();
+ sit != sie; ++sit) {
+ if (sit->sh_type != llvm::ELF::SHT_MIPS_REGINFO)
+ continue;
+
+ auto contents = this->getSectionContents(&*sit);
+ if (error_code ec = contents.getError())
+ return ec;
+
+ // FIXME (simon): Show error in case of invalid section size.
+ if (contents.get().size() == sizeof(Elf_RegInfo)) {
+ const auto *regInfo =
+ reinterpret_cast<const Elf_RegInfo *>(contents.get().data());
+ _gp0 = regInfo->ri_gp_value;
+ }
+ break;
+ }
+ return error_code::success();
+ }
+
void createRelocationReferences(const Elf_Sym &symbol,
ArrayRef<uint8_t> symContent,
ArrayRef<uint8_t> secContent,
@@ -129,6 +187,7 @@ private:
const uint8_t *ap = content.data() + ri.r_offset;
switch (ri.getType(isMips64EL())) {
case llvm::ELF::R_MIPS_32:
+ case llvm::ELF::R_MIPS_GPREL32:
case llvm::ELF::R_MIPS_PC32:
return *(int32_t *)ap;
case llvm::ELF::R_MIPS_26:
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
index aa9f56ed78c..36913dfa4cc 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -101,6 +101,14 @@ static void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
applyReloc(location, G, 0xffff);
}
+/// \brief R_MIPS_GPREL32
+/// local: rel32 A + S + GP0 – GP (truncate)
+static void relocGPRel32(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
+ uint64_t GP) {
+ int32_t result = A + S + 0 - GP;
+ applyReloc(location, result, 0xffffffff);
+}
+
/// \brief LLD_R_MIPS_32_HI16
static void reloc32hi16(uint8_t *location, uint64_t S, int64_t A) {
applyReloc(location, (S + A) & 0xffff0000, 0xffffffff);
@@ -154,6 +162,9 @@ error_code MipsTargetRelocationHandler::applyRelocation(
case R_MIPS_CALL16:
relocCall16(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
break;
+ case R_MIPS_GPREL32:
+ relocGPRel32(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
+ break;
case R_MIPS_JALR:
// We do not do JALR optimization now.
break;
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index e280735b00a..8bd398ba998 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -194,7 +194,7 @@ private:
std::vector<LA25Atom *> _la25Vector;
/// \brief Handle a specific reference.
- void handleReference(Reference &ref);
+ void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
/// \brief Collect information about the reference to use it
/// later in the handleReference() routine.
@@ -204,6 +204,7 @@ private:
void handlePlain(Reference &ref);
void handle26(Reference &ref);
void handleGOT(Reference &ref);
+ void handleGPRel(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
const GOTAtom *getLocalGOTEntry(const Reference &ref);
const GOTAtom *getGlobalGOTEntry(const Atom *a);
@@ -243,7 +244,8 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
// Process all references.
for (const auto &atom : mf->defined())
for (const auto &ref : *atom)
- handleReference(const_cast<Reference &>(*ref));
+ handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom),
+ const_cast<Reference &>(*ref));
// Create R_MIPS_REL32 relocations.
for (auto *ref : _rel32Candidates) {
@@ -298,7 +300,8 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
}
template <typename ELFT>
-void RelocationPass<ELFT>::handleReference(Reference &ref) {
+void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
if (!ref.target())
return;
if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
@@ -319,6 +322,23 @@ void RelocationPass<ELFT>::handleReference(Reference &ref) {
case R_MIPS_CALL16:
handleGOT(ref);
break;
+ case R_MIPS_GPREL32:
+ handleGPRel(atom, ref);
+ break;
+ }
+}
+
+template <typename ELFT>
+static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
+ if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
+ return false;
+ switch (ref.kindValue()) {
+ case R_MIPS_NONE:
+ case R_MIPS_JALR:
+ case R_MIPS_GPREL32:
+ return false;
+ default:
+ return true;
}
}
@@ -330,7 +350,7 @@ RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
return;
if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
return;
- if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
+ if (!isConstrainSym(atom, ref))
return;
if (mightBeDynamic(atom, ref))
@@ -481,6 +501,13 @@ template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
}
template <typename ELFT>
+void RelocationPass<ELFT>::handleGPRel(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ assert(ref.kindValue() == R_MIPS_GPREL32);
+ ref.setAddend(ref.addend() + atom.file().getGP0());
+}
+
+template <typename ELFT>
bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
Atom::Scope scope;
if (auto *da = dyn_cast<DefinedAtom>(a))
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
index 3a6dbbc88d3..69a675329fa 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -55,6 +55,7 @@ const Registry::KindStrings MipsTargetHandler::kindStrings[] = {
LLD_KIND_STRING_ENTRY(R_MIPS_LO16),
LLD_KIND_STRING_ENTRY(R_MIPS_GOT16),
LLD_KIND_STRING_ENTRY(R_MIPS_CALL16),
+ LLD_KIND_STRING_ENTRY(R_MIPS_GPREL32),
LLD_KIND_STRING_ENTRY(R_MIPS_JALR),
LLD_KIND_STRING_ENTRY(R_MIPS_COPY),
LLD_KIND_STRING_ENTRY(R_MIPS_JUMP_SLOT),
diff --git a/lld/test/elf/Mips/rel-gprel32.test b/lld/test/elf/Mips/rel-gprel32.test
new file mode 100644
index 00000000000..73ae6f16197
--- /dev/null
+++ b/lld/test/elf/Mips/rel-gprel32.test
@@ -0,0 +1,84 @@
+# Check R_MIPS_GPREL32 relocation handling.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-readobj -symbols %t-exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t-exe | FileCheck -check-prefix=SEC %s
+
+# SYM: Name: $L1 (1)
+# SYM-NEXT: Value: 0x400108
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Local (0x0)
+# SYM-NEXT: Type: Function (0x2)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .text (0x5)
+#
+# SYM: Name: _gp (212)
+# SYM-NEXT: Value: 0x408FF0
+# SYM-NEXT: Size: 0
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: Object (0x1)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: Absolute (0xFFF1)
+
+# 0x08FF711B == 0x8000001 (addend) + 0x400108 ($L1) +
+# 0x1000002 (GP0) - 0x408FF0 (_gp)
+# SEC: Contents of section .rodata:
+# SEC-NEXT: 400118 1b71ff08 00000000 00000000 00000000 .q..............
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+- Type: SHT_PROGBITS
+ Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: 00000000000000000000000000000000
+
+- Type: SHT_PROGBITS
+ Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x04
+ Content: 01000008000000000000000000000000
+
+- Type: SHT_REL
+ Name: .rel.rodata
+ Type: SHT_REL
+ Link: .symtab
+ Info: .rodata
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: $L1
+ Type: R_MIPS_GPREL32
+
+- Type: SHT_MIPS_REGINFO
+ Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Content: 000000000000000000000000000000000000000002000001
+
+Symbols:
+ Local:
+ - Name: $L1
+ Section: .text
+ Value: 0x00
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ Global:
+ - Name: __start
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x04
+ Size: 12
+ - Name: _gp_disp
OpenPOWER on IntegriCloud