diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index e938e175f25e..dbdaa1d425ae 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -13,8 +13,6 @@ #include "OutputSections.h" #include "Target.h" -#include "llvm/Support/raw_ostream.h" - using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; @@ -26,57 +24,6 @@ template InputSection::InputSection(ObjectFile *F, const Elf_Shdr *Header) : File(F), Header(Header) {} -template -void InputSection::relocateOne(uint8_t *Buf, const Elf_Rel &Rel, - uint32_t Type, uintX_t BaseAddr, - uintX_t SymVA) { - uintX_t Offset = Rel.r_offset; - uint8_t *Location = Buf + Offset; - uint32_t Addend = *(support::ulittle32_t *)Location; - switch (Type) { - case R_386_PC32: - support::endian::write32le(Location, SymVA + Addend - (BaseAddr + Offset)); - break; - case R_386_32: - support::endian::write32le(Location, SymVA + Addend); - break; - default: - llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n'; - break; - } -} - -template -void InputSection::relocateOne(uint8_t *Buf, const Elf_Rela &Rel, - uint32_t Type, uintX_t BaseAddr, - uintX_t SymVA) { - uintX_t Offset = Rel.r_offset; - uint8_t *Location = Buf + Offset; - switch (Type) { - case R_X86_64_PC32: - support::endian::write32le(Location, - SymVA + Rel.r_addend - (BaseAddr + Offset)); - break; - case R_X86_64_64: - support::endian::write64le(Location, SymVA + Rel.r_addend); - break; - case R_X86_64_32: { - case R_X86_64_32S: - uint64_t VA = SymVA + Rel.r_addend; - if (Type == R_X86_64_32 && !isUInt<32>(VA)) - error("R_X86_64_32 out of range"); - else if (!isInt<32>(VA)) - error("R_X86_64_32S out of range"); - - support::endian::write32le(Location, VA); - break; - } - default: - llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n'; - break; - } -} - template template void InputSection::relocate( @@ -134,7 +81,8 @@ void InputSection::relocate( } } - relocateOne(Buf, RI, Type, BaseAddr, SymVA); + Target->relocateOne(Buf, reinterpret_cast(&RI), Type, + BaseAddr, SymVA); } } diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 930da4a65156..b8a7b7531a7f 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -60,11 +60,6 @@ public: SmallVector RelocSections; private: - void relocateOne(uint8_t *Buf, const Elf_Rela &Rel, uint32_t Type, - uintX_t BaseAddr, uintX_t SymVA); - void relocateOne(uint8_t *Buf, const Elf_Rel &Rel, uint32_t Type, - uintX_t BaseAddr, uintX_t SymVA); - template void relocate(uint8_t *Buf, llvm::iterator_range< diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index ffebf1025e9c..48fd636bc6d1 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -40,7 +40,9 @@ void SymbolTable::addFile(std::unique_ptr File) { } template void SymbolTable::init(uint16_t EMachine) { - if (EMachine == EM_X86_64) + if (EMachine == EM_PPC64) + Target.reset(new PPC64TargetInfo()); + else if (EMachine == EM_X86_64) Target.reset(new X86_64TargetInfo()); else Target.reset(new X86TargetInfo()); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 69a6dc6b2aaf..a72d7ce94357 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -8,12 +8,15 @@ //===----------------------------------------------------------------------===// #include "Target.h" +#include "Error.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ELF.h" using namespace llvm; +using namespace llvm::object; using namespace llvm::ELF; namespace lld { @@ -59,6 +62,27 @@ bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const { } } +void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type, + uint64_t BaseAddr, uint64_t SymVA) const { + typedef ELFFile::Elf_Rel Elf_Rel; + auto &Rel = *reinterpret_cast(RelP); + + uint32_t Offset = Rel.r_offset; + uint8_t *Location = Buf + Offset; + uint32_t Addend = *(support::ulittle32_t *)Location; + switch (Type) { + case R_386_PC32: + support::endian::write32le(Location, SymVA + Addend - (BaseAddr + Offset)); + break; + case R_386_32: + support::endian::write32le(Location, SymVA + Addend); + break; + default: + error(Twine("unrecognized reloc ") + Twine(Type)); + break; + } +} + X86_64TargetInfo::X86_64TargetInfo() { PCRelReloc = R_X86_64_PC32; } void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, @@ -96,5 +120,48 @@ bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const { return true; } } + +void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, + uint32_t Type, uint64_t BaseAddr, + uint64_t SymVA) const { + typedef ELFFile::Elf_Rela Elf_Rela; + auto &Rel = *reinterpret_cast(RelP); + + uint64_t Offset = Rel.r_offset; + uint8_t *Location = Buf + Offset; + switch (Type) { + case R_X86_64_PC32: + support::endian::write32le(Location, + SymVA + Rel.r_addend - (BaseAddr + Offset)); + break; + case R_X86_64_64: + support::endian::write64le(Location, SymVA + Rel.r_addend); + break; + case R_X86_64_32: { + case R_X86_64_32S: + uint64_t VA = SymVA + Rel.r_addend; + if (Type == R_X86_64_32 && !isUInt<32>(VA)) + error("R_X86_64_32 out of range"); + else if (!isInt<32>(VA)) + error("R_X86_64_32S out of range"); + + support::endian::write32le(Location, VA); + break; + } + default: + error(Twine("unrecognized reloc ") + Twine(Type)); + break; + } +} + +PPC64TargetInfo::PPC64TargetInfo() { + // PCRelReloc = FIXME +} +void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {} +bool PPC64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; } +bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; } +void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type, + uint64_t BaseAddr, uint64_t SymVA) const {} } } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index d45e88c30454..a93b639b8cc1 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -23,6 +23,9 @@ public: uint64_t PltEntryAddr) const = 0; virtual bool relocNeedsGot(uint32_t Type) const = 0; virtual bool relocNeedsPlt(uint32_t Type) const = 0; + virtual void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type, + uint64_t BaseAddr, uint64_t SymVA) const = 0; + virtual ~TargetInfo(); protected: @@ -36,6 +39,8 @@ public: uint64_t PltEntryAddr) const override; bool relocNeedsGot(uint32_t Type) const override; bool relocNeedsPlt(uint32_t Type) const override; + void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type, + uint64_t BaseAddr, uint64_t SymVA) const override; }; class X86_64TargetInfo final : public TargetInfo { @@ -45,6 +50,19 @@ public: uint64_t PltEntryAddr) const override; bool relocNeedsGot(uint32_t Type) const override; bool relocNeedsPlt(uint32_t Type) const override; + void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type, + uint64_t BaseAddr, uint64_t SymVA) const override; +}; + +class PPC64TargetInfo final : public TargetInfo { +public: + PPC64TargetInfo(); + void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; + bool relocNeedsGot(uint32_t Type) const override; + bool relocNeedsPlt(uint32_t Type) const override; + void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type, + uint64_t BaseAddr, uint64_t SymVA) const override; }; extern std::unique_ptr Target;