diff options
author | Simon Atanasyan <simon@atanasyan.com> | 2014-05-05 05:56:06 +0000 |
---|---|---|
committer | Simon Atanasyan <simon@atanasyan.com> | 2014-05-05 05:56:06 +0000 |
commit | e22ca466811a619d0d8c30ddd2eeffc2d735d8d9 (patch) | |
tree | a41b3239ec57743c76f0e3b24b2eb0a4ff5fbe6e | |
parent | 527040e0c87ac8d6cdde46be51c1a93e098bb5fd (diff) | |
download | bcm5719-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.h | 61 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp | 11 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp | 35 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp | 1 | ||||
-rw-r--r-- | lld/test/elf/Mips/rel-gprel32.test | 84 |
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 |