From f9a7933d9091194d55d7f16dbea8bd657670bd58 Mon Sep 17 00:00:00 2001 From: Shankar Easwaran Date: Fri, 17 May 2013 04:19:53 +0000 Subject: [PATCH] [lld][ELF][X86_64] Reorganize X86_64 Target specific code This patch splits X86_64Target specific code so that the dynamic atoms and the Relocation handlers are in seperate files for easier maintenace. The files are sure to grow and this makes it easier to work with. * There is no change in functionality * llvm-svn: 182076 --- .../ReaderWriter/ELF/X86_64/CMakeLists.txt | 1 + .../ELF/X86_64/X86_64DynamicAtoms.h | 73 +++++++++ .../ELF/X86_64/X86_64RelocationHandler.cpp | 146 ++++++++++++++++++ .../ELF/X86_64/X86_64RelocationHandler.h | 42 +++++ .../ELF/X86_64/X86_64TargetHandler.cpp | 130 ---------------- .../ELF/X86_64/X86_64TargetHandler.h | 19 +-- .../ELF/X86_64/X86_64TargetInfo.cpp | 61 +------- 7 files changed, 266 insertions(+), 206 deletions(-) create mode 100644 lld/lib/ReaderWriter/ELF/X86_64/X86_64DynamicAtoms.h create mode 100644 lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp create mode 100644 lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h diff --git a/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt index 18336739b155..d899aba17876 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt +++ b/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt @@ -1,6 +1,7 @@ add_lld_library(lldX86_64ELFTarget X86_64TargetInfo.cpp X86_64TargetHandler.cpp + X86_64RelocationHandler.cpp ) target_link_libraries(lldX86_64ELFTarget diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64DynamicAtoms.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64DynamicAtoms.h new file mode 100644 index 000000000000..c7a1bcdd701a --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64DynamicAtoms.h @@ -0,0 +1,73 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64DynamicAtoms.h -------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef X86_64_DYNAMIC_ATOMS_H +#define X86_64_DYNAMIC_ATOMS_H + +#include "Atoms.h" +#include "X86_64TargetInfo.h" + +namespace lld { +namespace elf { + +class X86_64GOTAtom : public GOTAtom { + static const uint8_t _defaultContent[8]; + +public: + X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} + + virtual ArrayRef rawContent() const { + return ArrayRef(_defaultContent, 8); + } +}; + +const uint8_t X86_64GOTAtom::_defaultContent[8] = { 0 }; + +class X86_64PLTAtom : public PLTAtom { + static const uint8_t _defaultContent[16]; + +public: + X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {} + + virtual ArrayRef rawContent() const { + return ArrayRef(_defaultContent, 16); + } +}; + +const uint8_t X86_64PLTAtom::_defaultContent[16] = { + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip) + 0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index + 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1] +}; + +class X86_64PLT0Atom : public PLT0Atom { + static const uint8_t _plt0Content[16]; + +public: + X86_64PLT0Atom(const File &f) : PLT0Atom(f) { +#ifndef NDEBUG + _name = ".PLT0"; +#endif + } + + virtual ArrayRef rawContent() const { + return ArrayRef(_plt0Content, 16); + } +}; + +const uint8_t X86_64PLT0Atom::_plt0Content[16] = { + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip) + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip) + 0x90, 0x90, 0x90, 0x90 // nopnopnop +}; + +} // elf +} // lld + +#endif diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp new file mode 100644 index 000000000000..5d27f11779fb --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp @@ -0,0 +1,146 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp ------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "X86_64TargetHandler.h" +#include "X86_64TargetInfo.h" + +using namespace lld; +using namespace elf; + +namespace { +/// \brief R_X86_64_64 - word64: S + A +void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + uint64_t result = S + A; + *reinterpret_cast(location) = + result | + (uint64_t) * reinterpret_cast(location); +} + +/// \brief R_X86_64_PC32 - word32: S + A - P +void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + *reinterpret_cast(location) = + result + + (uint32_t) * reinterpret_cast(location); +} + +/// \brief R_X86_64_32 - word32: S + A +void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + int32_t result = (uint32_t)(S + A); + *reinterpret_cast(location) = + result | + (uint32_t) * reinterpret_cast(location); + // TODO: Make sure that the result zero extends to the 64bit value. +} + +/// \brief R_X86_64_32S - word32: S + A +void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + int32_t result = (int32_t)(S + A); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); + // TODO: Make sure that the result sign extends to the 64bit value. +} +} // end anon namespace + +int64_t X86_64TargetRelocationHandler::relocAddend(const Reference &ref) const { + switch (ref.kind()) { + case R_X86_64_PC32: + return 4; + default: + return 0; + } + return 0; +} + +ErrorOr X86_64TargetRelocationHandler::applyRelocation( + ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, + const Reference &ref) const { + uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; + uint8_t *location = atomContent + ref.offsetInAtom(); + uint64_t targetVAddress = writer.addressOfAtom(ref.target()); + uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); + + switch (ref.kind()) { + case R_X86_64_NONE: + break; + case R_X86_64_64: + reloc64(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_X86_64_PC32: + relocPC32(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_X86_64_32: + reloc32(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_X86_64_32S: + reloc32S(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_X86_64_TPOFF64: + case R_X86_64_DTPOFF32: + case R_X86_64_TPOFF32: { + _tlsSize = _targetInfo.getTargetHandler().targetLayout() + .getTLSSize(); + if (ref.kind() == R_X86_64_TPOFF32 || ref.kind() == R_X86_64_DTPOFF32) { + int32_t result = (int32_t)(targetVAddress - _tlsSize); + *reinterpret_cast(location) = result; + } else { + int64_t result = (int64_t)(targetVAddress - _tlsSize); + *reinterpret_cast(location) = result; + } + break; + } + case R_X86_64_TLSLD: { + // Rewrite to move %fs:0 into %rax. Technically we should verify that the + // next relocation is a PC32 to __tls_get_addr... + static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25, + 0x00, 0x00, 0x00, 0x00 }; + std::memcpy(location - 3, instr, sizeof(instr)); + break; + } + case LLD_R_X86_64_GOTRELINDEX: { + const DefinedAtom *target = cast(ref.target()); + for (const Reference *r : *target) { + if (r->kind() == R_X86_64_JUMP_SLOT) { + uint32_t index; + if (!_targetInfo.getTargetHandler().targetLayout() + .getPLTRelocationTable()->getRelocationIndex(*r, index)) + llvm_unreachable("Relocation doesn't exist"); + reloc32(location, 0, index, 0); + break; + } + } + break; + } + // Runtime only relocations. Ignore here. + case R_X86_64_RELATIVE: + case R_X86_64_IRELATIVE: + case R_X86_64_JUMP_SLOT: + case R_X86_64_GLOB_DAT: + break; + + case lld::Reference::kindLayoutAfter: + case lld::Reference::kindLayoutBefore: + case lld::Reference::kindInGroup: + break; + + default: { + std::string str; + llvm::raw_string_ostream s(str); + auto name = _targetInfo.stringFromRelocKind(ref.kind()); + s << "Unhandled relocation: " << atom._atom->file().path() << ":" + << atom._atom->name() << "@" << ref.offsetInAtom() << " " + << (name ? *name : "") << " (" << ref.kind() << ")"; + s.flush(); + llvm_unreachable(str.c_str()); + } + } + + return error_code::success(); +} diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h new file mode 100644 index 000000000000..25703408d2c3 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h @@ -0,0 +1,42 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h +//------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef X86_64_RELOCATION_HANDLER_H +#define X86_64_RELOCATION_HANDLER_H + +#include "X86_64TargetHandler.h" + +namespace lld { +namespace elf { +typedef llvm::object::ELFType X86_64ELFType; +class X86_64TargetInfo; + +class X86_64TargetRelocationHandler LLVM_FINAL + : public TargetRelocationHandler { +public: + X86_64TargetRelocationHandler(const X86_64TargetInfo &ti) + : _tlsSize(0), _targetInfo(ti) {} + + virtual ErrorOr applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, + const AtomLayout &, + const Reference &) const; + + virtual int64_t relocAddend(const Reference &) const; + +private: + // Cached size of the TLS segment. + mutable uint64_t _tlsSize; + const X86_64TargetInfo &_targetInfo; +}; + +} // end namespace elf +} // end namespace lld + +#endif diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp index 2cc66aaf920a..d64203fffd1c 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp @@ -14,140 +14,10 @@ using namespace lld; using namespace elf; -using namespace llvm::ELF; - X86_64TargetHandler::X86_64TargetHandler(X86_64TargetInfo &targetInfo) : DefaultTargetHandler(targetInfo), _gotFile(targetInfo), _relocationHandler(targetInfo), _targetLayout(targetInfo) {} -namespace { -/// \brief R_X86_64_64 - word64: S + A -void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - uint64_t result = S + A; - *reinterpret_cast(location) = result | - (uint64_t)*reinterpret_cast(location); -} - -/// \brief R_X86_64_PC32 - word32: S + A - P -void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - uint32_t result = (uint32_t)((S + A) - P); - *reinterpret_cast(location) = result + - (uint32_t)*reinterpret_cast(location); -} - -/// \brief R_X86_64_32 - word32: S + A -void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - int32_t result = (uint32_t)(S + A); - *reinterpret_cast(location) = result | - (uint32_t)*reinterpret_cast(location); - // TODO: Make sure that the result zero extends to the 64bit value. -} - -/// \brief R_X86_64_32S - word32: S + A -void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A); - *reinterpret_cast(location) = result | - (int32_t)*reinterpret_cast(location); - // TODO: Make sure that the result sign extends to the 64bit value. -} -} // end anon namespace - -int64_t X86_64TargetRelocationHandler::relocAddend(const Reference &ref) const { - switch (ref.kind()) { - case R_X86_64_PC32: - return 4; - default: - return 0; - } - return 0; -} - -ErrorOr X86_64TargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *location = atomContent + ref.offsetInAtom(); - uint64_t targetVAddress = writer.addressOfAtom(ref.target()); - uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); - - switch (ref.kind()) { - case R_X86_64_NONE: - break; - case R_X86_64_64: - reloc64(location, relocVAddress, targetVAddress, ref.addend()); - break; - case R_X86_64_PC32: - relocPC32(location, relocVAddress, targetVAddress, ref.addend()); - break; - case R_X86_64_32: - reloc32(location, relocVAddress, targetVAddress, ref.addend()); - break; - case R_X86_64_32S: - reloc32S(location, relocVAddress, targetVAddress, ref.addend()); - break; - case R_X86_64_TPOFF64: - case R_X86_64_DTPOFF32: - case R_X86_64_TPOFF32: { - _tlsSize = _targetInfo.getTargetHandler().targetLayout() - .getTLSSize(); - if (ref.kind() == R_X86_64_TPOFF32 || ref.kind() == R_X86_64_DTPOFF32) { - int32_t result = (int32_t)(targetVAddress - _tlsSize); - *reinterpret_cast(location) = result; - } else { - int64_t result = (int64_t)(targetVAddress - _tlsSize); - *reinterpret_cast(location) = result; - } - break; - } - case R_X86_64_TLSLD: { - // Rewrite to move %fs:0 into %rax. Technically we should verify that the - // next relocation is a PC32 to __tls_get_addr... - static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25, - 0x00, 0x00, 0x00, 0x00 }; - std::memcpy(location - 3, instr, sizeof(instr)); - break; - } - case LLD_R_X86_64_GOTRELINDEX: { - const DefinedAtom *target = cast(ref.target()); - for (const Reference *r : *target) { - if (r->kind() == R_X86_64_JUMP_SLOT) { - uint32_t index; - if (!_targetInfo.getTargetHandler().targetLayout() - .getPLTRelocationTable()->getRelocationIndex(*r, index)) - llvm_unreachable("Relocation doesn't exist"); - reloc32(location, 0, index, 0); - break; - } - } - break; - } - // Runtime only relocations. Ignore here. - case R_X86_64_RELATIVE: - case R_X86_64_IRELATIVE: - case R_X86_64_JUMP_SLOT: - case R_X86_64_GLOB_DAT: - break; - - case lld::Reference::kindLayoutAfter: - case lld::Reference::kindLayoutBefore: - case lld::Reference::kindInGroup: - break; - - default : { - std::string str; - llvm::raw_string_ostream s(str); - auto name = _targetInfo.stringFromRelocKind(ref.kind()); - s << "Unhandled relocation: " << atom._atom->file().path() << ":" - << atom._atom->name() << "@" << ref.offsetInAtom() << " " - << (name ? *name : "") << " (" << ref.kind() << ")"; - s.flush(); - llvm_unreachable(str.c_str()); - } - } - - return error_code::success(); -} - void X86_64TargetHandler::addFiles(InputFiles &f) { _gotFile.addAtom(*new (_gotFile._alloc) GLOBAL_OFFSET_TABLEAtom(_gotFile)); _gotFile.addAtom(*new (_gotFile._alloc) TLSGETADDRAtom(_gotFile)); diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h index 1d4047260e48..b823446f4e9b 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h @@ -11,6 +11,7 @@ #define LLD_READER_WRITER_ELF_X86_64_TARGET_HANDLER_H #include "DefaultTargetHandler.h" +#include "X86_64RelocationHandler.h" #include "TargetLayout.h" #include "lld/ReaderWriter/Simple.h" @@ -20,24 +21,6 @@ namespace elf { typedef llvm::object::ELFType X86_64ELFType; class X86_64TargetInfo; -class X86_64TargetRelocationHandler LLVM_FINAL - : public TargetRelocationHandler { -public: - X86_64TargetRelocationHandler(const X86_64TargetInfo &ti) - : _tlsSize(0), _targetInfo(ti) {} - - virtual ErrorOr - applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const AtomLayout &, - const Reference &)const; - - virtual int64_t relocAddend(const Reference &)const; - -private: - // Cached size of the TLS segment. - mutable uint64_t _tlsSize; - const X86_64TargetInfo &_targetInfo; -}; - class X86_64TargetHandler LLVM_FINAL : public DefaultTargetHandler { public: diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp index cad8dd2809f6..45f4f4dd3102 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Atoms.h" +#include "X86_64DynamicAtoms.h" #include "X86_64TargetInfo.h" #include "lld/Core/File.h" @@ -25,61 +25,6 @@ using namespace lld::elf; namespace { using namespace llvm::ELF; -class X86_64GOTAtom : public GOTAtom { - static const uint8_t _defaultContent[8]; - -public: - X86_64GOTAtom(const File &f, StringRef secName) - : GOTAtom(f, secName) { - } - - virtual ArrayRef rawContent() const { - return ArrayRef(_defaultContent, 8); - } -}; - -const uint8_t X86_64GOTAtom::_defaultContent[8] = { 0 }; - -class X86_64PLTAtom : public PLTAtom { - static const uint8_t _defaultContent[16]; - -public: - X86_64PLTAtom(const File &f, StringRef secName) - : PLTAtom(f, secName) { - } - - virtual ArrayRef rawContent() const { - return ArrayRef(_defaultContent, 16); - } -}; - -const uint8_t X86_64PLTAtom::_defaultContent[16] = { - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip) - 0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index - 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1] -}; - -class X86_64PLT0Atom : public PLT0Atom { - static const uint8_t _plt0Content[16]; - -public: - X86_64PLT0Atom(const File &f) : PLT0Atom(f) { -#ifndef NDEBUG - _name = ".PLT0"; -#endif - } - - virtual ArrayRef rawContent() const { - return ArrayRef(_plt0Content, 16); - } -}; - -const uint8_t X86_64PLT0Atom::_plt0Content[16] = { - 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip) - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip) - 0x90, 0x90, 0x90, 0x90 // nopnopnop -}; - class ELFPassFile : public SimpleFile { public: ELFPassFile(const ELFTargetInfo &eti) : SimpleFile(eti, "ELFPassFile") {} @@ -420,7 +365,7 @@ void elf::X86_64TargetInfo::addPasses(PassManager &pm) const { #define LLD_CASE(name) .Case(#name, llvm::ELF::name) -ErrorOr +ErrorOr elf::X86_64TargetInfo::relocKindFromString(StringRef str) const { int32_t ret = llvm::StringSwitch(str) LLD_CASE(R_X86_64_NONE) @@ -473,7 +418,7 @@ elf::X86_64TargetInfo::relocKindFromString(StringRef str) const { #define LLD_CASE(name) case llvm::ELF::name: return std::string(#name); -ErrorOr +ErrorOr elf::X86_64TargetInfo::stringFromRelocKind(Reference::Kind kind) const { switch (kind) { LLD_CASE(R_X86_64_NONE)