Index: include/lld/ReaderWriter/ELFTargets.h =================================================================== --- include/lld/ReaderWriter/ELFTargets.h +++ include/lld/ReaderWriter/ELFTargets.h @@ -27,7 +27,6 @@ LLVM_TARGET(Hexagon) LLVM_TARGET(Mips) LLVM_TARGET(X86) -LLVM_TARGET(X86_64) #undef LLVM_TARGET Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -29,7 +29,6 @@ lldHexagonELFTarget lldMipsELFTarget lldX86ELFTarget - lldX86_64ELFTarget lldCore lldNative lldReaderWriter Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -330,7 +330,6 @@ LLVM_TARGET(Hexagon) LLVM_TARGET(Mips) LLVM_TARGET(X86) - LLVM_TARGET(X86_64) return nullptr; } #undef LLVM_TARGET Index: lib/ReaderWriter/ELF/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/CMakeLists.txt +++ lib/ReaderWriter/ELF/CMakeLists.txt @@ -13,7 +13,6 @@ include_directories(.) add_subdirectory(X86) -add_subdirectory(X86_64) add_subdirectory(Mips) add_subdirectory(Hexagon) add_subdirectory(AArch64) Index: lib/ReaderWriter/ELF/Makefile =================================================================== --- lib/ReaderWriter/ELF/Makefile +++ lib/ReaderWriter/ELF/Makefile @@ -14,6 +14,6 @@ CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF # these link against this lib -PARALLEL_DIRS := Hexagon X86 X86_64 Mips AArch64 ARM +PARALLEL_DIRS := Hexagon X86 Mips AArch64 ARM include $(LLD_LEVEL)/Makefile Index: lib/ReaderWriter/ELF/X86/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/X86/CMakeLists.txt +++ lib/ReaderWriter/ELF/X86/CMakeLists.txt @@ -1,4 +1,8 @@ add_llvm_library(lldX86ELFTarget + X86_64LinkingContext.cpp + X86_64TargetHandler.cpp + X86_64RelocationHandler.cpp + X86_64RelocationPass.cpp X86LinkingContext.cpp X86TargetHandler.cpp X86RelocationHandler.cpp Index: lib/ReaderWriter/ELF/X86/TODO.rst =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/TODO.rst @@ -0,0 +1,48 @@ +ELF x86-64 +~~~~~~~~~~ + +Unimplemented Features +###################### + +* Code models other than the small code model +* TLS strength reduction + +Unimplemented Relocations +######################### + +All of these relocations are defined in: +http://www.x86-64.org/documentation/abi.pdf + +Trivial Relocs +<<<<<<<<<<<<<< + +These are very simple relocation calculations to implement. +See lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp + +* R_X86_64_16 +* R_X86_64_PC16 +* R_X86_64_8 +* R_X86_64_PC8 +* R_X86_64_PC64 +* R_X86_64_SIZE32 +* R_X86_64_SIZE64 +* R_X86_64_GOTPC32 (this relocation requires there to be a __GLOBAL_OFFSET_TABLE__) + +Global Offset Table Relocs +<<<<<<<<<<<<<<<<<<<<<<<<<< + +* R_X86_64_GOTOFF32 +* R_X86_64_GOTOFF64 + +Global Dynamic Thread Local Storage Relocs +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +These relocations take more effort to implement, but some of them are done. +Their implementation lives in lib/ReaderWriter/ELF/X86_64/{X86_64RelocationPass.cpp,X86_64RelocationHandler.cpp}. + +Documentation on these relocations can be found in: +http://www.akkadia.org/drepper/tls.pdf + +* R_X86_64_GOTPC32_TLSDESC +* R_X86_64_TLSDESC_CALL +* R_X86_64_TLSDESC Index: lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp +++ lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "X86_64LinkingContext.h" #include "X86LinkingContext.h" #include "X86TargetHandler.h" #include "lld/Core/LLVM.h" @@ -20,6 +21,9 @@ if (triple.getArch() == llvm::Triple::x86) return std::unique_ptr( new elf::X86LinkingContext(triple)); + if (triple.getArch() == llvm::Triple::x86_64) + return std::unique_ptr( + new elf::X86_64LinkingContext(triple)); return nullptr; } Index: lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.h @@ -0,0 +1,69 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.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_LIBRARY_WRITER_H +#define X86_64_DYNAMIC_LIBRARY_WRITER_H + +#include "DynamicLibraryWriter.h" +#include "X86_64LinkingContext.h" +#include "X86_64TargetHandler.h" + +namespace lld { +namespace elf { + +template +class X86_64DynamicLibraryWriter : public DynamicLibraryWriter { +public: + X86_64DynamicLibraryWriter(X86_64LinkingContext &context, + X86_64TargetLayout &layout); + +protected: + // Add any runtime files and their atoms to the output + virtual bool createImplicitFiles(std::vector> &); + + virtual void finalizeDefaultAtomValues() { + return DynamicLibraryWriter::finalizeDefaultAtomValues(); + } + + virtual void addDefaultAtoms() { + return DynamicLibraryWriter::addDefaultAtoms(); + } + +private: + class GOTFile : public SimpleFile { + public: + GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} + llvm::BumpPtrAllocator _alloc; + }; + + std::unique_ptr _gotFile; + X86_64LinkingContext &_context; + X86_64TargetLayout &_x86_64Layout; +}; + +template +X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter( + X86_64LinkingContext &context, X86_64TargetLayout &layout) + : DynamicLibraryWriter(context, layout), + _gotFile(new GOTFile(context)), _context(context), _x86_64Layout(layout) { +} + +template +bool X86_64DynamicLibraryWriter::createImplicitFiles( + std::vector> &result) { + DynamicLibraryWriter::createImplicitFiles(result); + _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile)); + _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile)); + result.push_back(std::move(_gotFile)); + return true; +} + +} // namespace elf +} // namespace lld + +#endif Index: lib/ReaderWriter/ELF/X86/X86_64ELFFile.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64ELFFile.h @@ -0,0 +1,41 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64ELFFile.h ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H +#define LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H + +#include "ELFReader.h" + +namespace lld { +namespace elf { + +class X86_64LinkingContext; + +template class X86_64ELFFile : public ELFFile { +public: + X86_64ELFFile(std::unique_ptr mb, bool atomizeStrings) + : ELFFile(std::move(mb), atomizeStrings) {} + + static ErrorOr> + create(std::unique_ptr mb, bool atomizeStrings) { + return std::unique_ptr>( + new X86_64ELFFile(std::move(mb), atomizeStrings)); + } +}; + +template class X86_64DynamicFile : public DynamicFile { +public: + X86_64DynamicFile(const X86_64LinkingContext &context, StringRef name) + : DynamicFile(context, name) {} +}; + +} // elf +} // lld + +#endif // LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H Index: lib/ReaderWriter/ELF/X86/X86_64ELFReader.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64ELFReader.h @@ -0,0 +1,61 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64ELFReader.h -------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_X86_X86_64_ELF_READER_H +#define LLD_READER_WRITER_X86_X86_64_ELF_READER_H + +#include "ELFReader.h" +#include "X86_64ELFFile.h" + +namespace lld { +namespace elf { + +typedef llvm::object::ELFType X86_64ELFType; + +struct X86_64DynamicFileCreateELFTraits { + typedef llvm::ErrorOr> result_type; + + template + static result_type create(std::unique_ptr mb, + bool useUndefines) { + return lld::elf::X86_64DynamicFile::create(std::move(mb), + useUndefines); + } +}; + +struct X86_64ELFFileCreateELFTraits { + typedef llvm::ErrorOr> result_type; + + template + static result_type create(std::unique_ptr mb, + bool atomizeStrings) { + return lld::elf::X86_64ELFFile::create(std::move(mb), atomizeStrings); + } +}; + +class X86_64ELFObjectReader + : public ELFObjectReader { +public: + X86_64ELFObjectReader(bool atomizeStrings) + : ELFObjectReader( + atomizeStrings, llvm::ELF::EM_X86_64) {} +}; + +class X86_64ELFDSOReader + : public ELFDSOReader { +public: + X86_64ELFDSOReader(bool useUndefines) + : ELFDSOReader( + useUndefines, llvm::ELF::EM_X86_64) {} +}; + +} // namespace elf +} // namespace lld + +#endif // LLD_READER_WRITER_ELF_X86_64_X86_64_READER_H Index: lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h @@ -0,0 +1,68 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h ------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef X86_64_EXECUTABLE_WRITER_H +#define X86_64_EXECUTABLE_WRITER_H + +#include "ExecutableWriter.h" +#include "X86_64LinkingContext.h" + +namespace lld { +namespace elf { + +template +class X86_64ExecutableWriter : public ExecutableWriter { +public: + X86_64ExecutableWriter(X86_64LinkingContext &context, + X86_64TargetLayout &layout); + +protected: + // Add any runtime files and their atoms to the output + virtual bool createImplicitFiles(std::vector> &); + + virtual void finalizeDefaultAtomValues() { + return ExecutableWriter::finalizeDefaultAtomValues(); + } + + virtual void addDefaultAtoms() { + return ExecutableWriter::addDefaultAtoms(); + } + +private: + class GOTFile : public SimpleFile { + public: + GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} + llvm::BumpPtrAllocator _alloc; + }; + + std::unique_ptr _gotFile; + X86_64LinkingContext &_context; + X86_64TargetLayout &_x86_64Layout; +}; + +template +X86_64ExecutableWriter::X86_64ExecutableWriter( + X86_64LinkingContext &context, X86_64TargetLayout &layout) + : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)), + _context(context), _x86_64Layout(layout) {} + +template +bool X86_64ExecutableWriter::createImplicitFiles( + std::vector> &result) { + ExecutableWriter::createImplicitFiles(result); + _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile)); + if (_context.isDynamic()) + _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile)); + result.push_back(std::move(_gotFile)); + return true; +} + +} // namespace elf +} // namespace lld + +#endif Index: lib/ReaderWriter/ELF/X86/X86_64LinkingContext.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64LinkingContext.h @@ -0,0 +1,98 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64LinkingContext.h --------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_X86_X86_64_LINKING_CONTEXT_H +#define LLD_READER_WRITER_ELF_X86_X86_64_LINKING_CONTEXT_H + +#include "lld/ReaderWriter/ELFLinkingContext.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" + +namespace lld { +namespace elf { + +/// \brief x86-64 internal references. +enum { + /// \brief The 32 bit index of the relocation in the got this reference refers + /// to. + LLD_R_X86_64_GOTRELINDEX = 1024, +}; + +class X86_64LinkingContext final : public ELFLinkingContext { +public: + X86_64LinkingContext(llvm::Triple); + + void addPasses(PassManager &) override; + + uint64_t getBaseAddress() const override { + if (_baseAddress == 0) + return 0x400000; + return _baseAddress; + } + + bool isDynamicRelocation(const DefinedAtom &, + const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + switch (r.kindValue()) { + case llvm::ELF::R_X86_64_RELATIVE: + case llvm::ELF::R_X86_64_GLOB_DAT: + case llvm::ELF::R_X86_64_COPY: + case llvm::ELF::R_X86_64_DTPMOD64: + case llvm::ELF::R_X86_64_DTPOFF64: + return true; + default: + return false; + } + } + + bool isCopyRelocation(const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + if (r.kindValue() == llvm::ELF::R_X86_64_COPY) + return true; + return false; + } + + virtual bool isPLTRelocation(const DefinedAtom &, + const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + switch (r.kindValue()) { + case llvm::ELF::R_X86_64_JUMP_SLOT: + case llvm::ELF::R_X86_64_IRELATIVE: + return true; + default: + return false; + } + } + + /// \brief X86_64 has two relative relocations + /// a) for supporting IFUNC - R_X86_64_IRELATIVE + /// b) for supporting relative relocs - R_X86_64_RELATIVE + bool isRelativeReloc(const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + switch (r.kindValue()) { + case llvm::ELF::R_X86_64_IRELATIVE: + case llvm::ELF::R_X86_64_RELATIVE: + return true; + default: + return false; + } + } +}; +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/X86/X86_64LinkingContext.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64LinkingContext.cpp @@ -0,0 +1,25 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "X86_64LinkingContext.h" +#include "X86_64TargetHandler.h" +#include "X86_64RelocationPass.h" + +using namespace lld; + +elf::X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple) + : ELFLinkingContext(triple, std::unique_ptr( + new X86_64TargetHandler(*this))) {} + +void elf::X86_64LinkingContext::addPasses(PassManager &pm) { + auto pass = createX86_64RelocationPass(*this); + if (pass) + pm.add(std::move(pass)); + ELFLinkingContext::addPasses(pm); +} Index: lib/ReaderWriter/ELF/X86/X86_64RelocationHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64RelocationHandler.h @@ -0,0 +1,39 @@ +//===- lib/ReaderWriter/ELF/X86/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; + +template class X86_64TargetLayout; + +class X86_64TargetRelocationHandler final : public TargetRelocationHandler { +public: + X86_64TargetRelocationHandler(X86_64TargetLayout &layout) + : _tlsSize(0), _x86_64Layout(layout) {} + + std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, + const lld::AtomLayout &, + const Reference &) const override; + +private: + // Cached size of the TLS segment. + mutable uint64_t _tlsSize; + X86_64TargetLayout &_x86_64Layout; +}; + +} // end namespace elf +} // end namespace lld + +#endif // X86_64_RELOCATION_HANDLER_H Index: lib/ReaderWriter/ELF/X86/X86_64RelocationHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64RelocationHandler.cpp @@ -0,0 +1,130 @@ +//===- 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_64LinkingContext.h" +#include "X86_64TargetHandler.h" + +using namespace lld; +using namespace elf; + +/// \brief R_X86_64_64 - word64: S + A +static 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 +static 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 +static 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 +static 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. +} + +std::error_code X86_64TargetRelocationHandler::applyRelocation( + ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::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(); + + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return std::error_code(); + assert(ref.kindArch() == Reference::KindArch::x86_64); + switch (ref.kindValue()) { + case R_X86_64_NONE: + break; + case R_X86_64_64: + reloc64(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_X86_64_PC32: + case R_X86_64_GOTPCREL: + 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 = _x86_64Layout.getTLSSize(); + if (ref.kindValue() == R_X86_64_TPOFF32 || + ref.kindValue() == 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_TLSGD: { + relocPC32(location, relocVAddress, targetVAddress, ref.addend()); + 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->kindValue() == R_X86_64_JUMP_SLOT) { + uint32_t index; + if (!_x86_64Layout.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: + case R_X86_64_DTPMOD64: + case R_X86_64_DTPOFF64: + break; + default: + return make_unhandled_reloc_error(); + } + + return std::error_code(); +} Index: lib/ReaderWriter/ELF/X86/X86_64RelocationPass.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64RelocationPass.h @@ -0,0 +1,32 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64RelocationPass.h --------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Declares the relocation processing pass for x86-64. This includes +/// GOT and PLT entries, TLS, COPY, and ifunc. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_X86_X86_64_RELOCATION_PASS_H +#define LLD_READER_WRITER_ELF_X86_X86_64_RELOCATION_PASS_H + +#include + +namespace lld { +class Pass; +namespace elf { +class X86_64LinkingContext; + +/// \brief Create x86-64 relocation pass for the given linking context. +std::unique_ptr +createX86_64RelocationPass(const X86_64LinkingContext &); +} +} + +#endif Index: lib/ReaderWriter/ELF/X86/X86_64RelocationPass.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64RelocationPass.cpp @@ -0,0 +1,515 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp ---------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the relocation processing pass for x86-64. This includes +/// GOT and PLT entries, TLS, COPY, and ifunc. +/// +/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct, +/// 2013). +/// +/// This also includes aditional behaivor that gnu-ld and gold implement but +/// which is not specified anywhere. +/// +//===----------------------------------------------------------------------===// + +#include "X86_64RelocationPass.h" +#include "Atoms.h" +#include "X86_64LinkingContext.h" +#include "lld/Core/Simple.h" +#include "llvm/ADT/DenseMap.h" + +using namespace lld; +using namespace lld::elf; +using namespace llvm::ELF; + +namespace { +// .got values +const uint8_t x86_64GotAtomContent[8] = { 0 }; + +// .plt value (entry 0) +const uint8_t x86_64Plt0AtomContent[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 +}; + +// .plt values (other entries) +const uint8_t x86_64PltAtomContent[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] +}; + +// TLS GD Entry +static const uint8_t x86_64GotTlsGdAtomContent[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +/// \brief Atoms that are used by X86_64 dynamic linking +class X86_64GOTAtom : public GOTAtom { +public: + X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return ArrayRef(x86_64GotAtomContent, 8); + } +}; + +/// \brief X86_64 GOT TLS GD entry. +class GOTTLSGdAtom : public X86_64GOTAtom { +public: + GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(x86_64GotTlsGdAtomContent); + } +}; + +class X86_64PLT0Atom : public PLT0Atom { +public: + X86_64PLT0Atom(const File &f) : PLT0Atom(f) { +#ifndef NDEBUG + _name = ".PLT0"; +#endif + } + ArrayRef rawContent() const override { + return ArrayRef(x86_64Plt0AtomContent, 16); + } +}; + +class X86_64PLTAtom : public PLTAtom { +public: + X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return ArrayRef(x86_64PltAtomContent, 16); + } +}; + +class ELFPassFile : public SimpleFile { +public: + ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { + setOrdinal(eti.getNextOrdinalAndIncrement()); + } + + llvm::BumpPtrAllocator _alloc; +}; + +/// \brief CRTP base for handling relocations. +template class RelocationPass : public Pass { + /// \brief Handle a specific reference. + void handleReference(const DefinedAtom &atom, const Reference &ref) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::x86_64); + switch (ref.kindValue()) { + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_64: + case R_X86_64_PC32: + case R_X86_64_PC64: + static_cast(this)->handlePlain(ref); + break; + case R_X86_64_PLT32: + static_cast(this)->handlePLT32(ref); + break; + case R_X86_64_GOT32: + case R_X86_64_GOTPC32: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTOFF64: + static_cast(this)->handleGOT(ref); + break; + case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset + static_cast(this)->handleGOTTPOFF(ref); + break; + case R_X86_64_TLSGD: + static_cast(this)->handleTLSGd(ref); + break; + } + } + +protected: + /// \brief get the PLT entry for a given IFUNC Atom. + /// + /// If the entry does not exist. Both the GOT and PLT entry is created. + const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) { + auto plt = _pltMap.find(da); + if (plt != _pltMap.end()) + return plt->second; + auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); + ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0); + auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); + pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); +#ifndef NDEBUG + ga->_name = "__got_ifunc_"; + ga->_name += da->name(); + pa->_name = "__plt_ifunc_"; + pa->_name += da->name(); +#endif + _gotMap[da] = ga; + _pltMap[da] = pa; + _gotVector.push_back(ga); + _pltVector.push_back(pa); + return pa; + } + + /// \brief Redirect the call to the PLT stub for the target IFUNC. + /// + /// This create a PLT and GOT entry for the IFUNC if one does not exist. The + /// GOT entry and a IRELATIVE relocation to the original target resolver. + std::error_code handleIFUNC(const Reference &ref) { + auto target = dyn_cast_or_null(ref.target()); + if (target && target->contentType() == DefinedAtom::typeResolver) + const_cast(ref).setTarget(getIFUNCPLTEntry(target)); + return std::error_code(); + } + + /// \brief Create a GOT entry for the TP offset of a TLS atom. + const GOTAtom *getGOTTPOFF(const Atom *atom) { + auto got = _gotMap.find(atom); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); + g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 0, atom, 0); +#ifndef NDEBUG + g->_name = "__got_tls_"; + g->_name += atom->name(); +#endif + _gotMap[atom] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + + /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to + /// the GOT. + void handleGOTTPOFF(const Reference &ref) { + const_cast(ref).setTarget(getGOTTPOFF(ref.target())); + const_cast(ref).setKindValue(R_X86_64_PC32); + } + + /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations. + void handleTLSGd(const Reference &ref) { + const_cast(ref).setTarget(getTLSGdGOTEntry(ref.target())); + } + + /// \brief Create a GOT entry containing 0. + const GOTAtom *getNullGOT() { + if (!_null) { + _null = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); +#ifndef NDEBUG + _null->_name = "__got_null"; +#endif + } + return _null; + } + + const GOTAtom *getGOT(const DefinedAtom *da) { + auto got = _gotMap.find(da); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); + g->addReferenceELF_x86_64(R_X86_64_64, 0, da, 0); +#ifndef NDEBUG + g->_name = "__got_"; + g->_name += da->name(); +#endif + _gotMap[da] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + + const GOTAtom *getTLSGdGOTEntry(const Atom *a) { + auto got = _gotTLSGdMap.find(a); + if (got != _gotTLSGdMap.end()) + return got->second; + + auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got"); + _gotTLSGdMap[a] = ga; + + _tlsGotVector.push_back(ga); + ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0); + ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0); + + return ga; + } + +public: + RelocationPass(const ELFLinkingContext &ctx) + : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr), + _got1(nullptr) {} + + /// \brief Do the pass. + /// + /// The goal here is to first process each reference individually. Each call + /// to handleReference may modify the reference itself and/or create new + /// atoms which must be stored in one of the maps below. + /// + /// After all references are handled, the atoms created during that are all + /// added to mf. + void perform(std::unique_ptr &mf) override { + ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass"); + // Process all references. + for (const auto &atom : mf->defined()) + for (const auto &ref : *atom) + handleReference(*atom, *ref); + + // Add all created atoms to the link. + uint64_t ordinal = 0; + if (_PLT0) { + _PLT0->setOrdinal(ordinal++); + mf->addAtom(*_PLT0); + } + for (auto &plt : _pltVector) { + plt->setOrdinal(ordinal++); + mf->addAtom(*plt); + } + if (_null) { + _null->setOrdinal(ordinal++); + mf->addAtom(*_null); + } + if (_PLT0) { + _got0->setOrdinal(ordinal++); + _got1->setOrdinal(ordinal++); + mf->addAtom(*_got0); + mf->addAtom(*_got1); + } + for (auto &got : _gotVector) { + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + for (auto &got : _tlsGotVector) { + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + for (auto obj : _objectVector) { + obj->setOrdinal(ordinal++); + mf->addAtom(*obj); + } + } + +protected: + /// \brief Owner of all the Atoms created by this pass. + ELFPassFile _file; + const ELFLinkingContext &_ctx; + + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + + /// \brief Map Atoms to their PLT entries. + llvm::DenseMap _pltMap; + + /// \brief Map Atoms to TLS GD GOT entries. + llvm::DenseMap _gotTLSGdMap; + + /// \brief Map Atoms to their Object entries. + llvm::DenseMap _objectMap; + + /// \brief the list of GOT/PLT atoms + std::vector _gotVector; + std::vector _pltVector; + std::vector _objectVector; + + /// \brief the list of TLS GOT atoms. + std::vector _tlsGotVector; + + /// \brief GOT entry that is always 0. Used for undefined weaks. + GOTAtom *_null; + + /// \brief The got and plt entries for .PLT0. This is used to call into the + /// dynamic linker for symbol resolution. + /// @{ + PLT0Atom *_PLT0; + GOTAtom *_got0; + GOTAtom *_got1; + /// @} +}; + +/// This implements the static relocation model. Meaning GOT and PLT entries are +/// not created for references that can be directly resolved. These are +/// converted to a direct relocation. For entries that do require a GOT or PLT +/// entry, that entry is statically bound. +/// +/// TLS always assumes module 1 and attempts to remove indirection. +class StaticRelocationPass final + : public RelocationPass { +public: + StaticRelocationPass(const elf::X86_64LinkingContext &ctx) + : RelocationPass(ctx) {} + + std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); } + + std::error_code handlePLT32(const Reference &ref) { + // __tls_get_addr is handled elsewhere. + if (ref.target() && ref.target()->name() == "__tls_get_addr") { + const_cast(ref).setKindValue(R_X86_64_NONE); + return std::error_code(); + } + // Static code doesn't need PLTs. + const_cast(ref).setKindValue(R_X86_64_PC32); + // Handle IFUNC. + if (const DefinedAtom *da = + dyn_cast_or_null(ref.target())) + if (da->contentType() == DefinedAtom::typeResolver) + return handleIFUNC(ref); + return std::error_code(); + } + + std::error_code handleGOT(const Reference &ref) { + if (isa(ref.target())) + const_cast(ref).setTarget(getNullGOT()); + else if (const DefinedAtom *da = dyn_cast(ref.target())) + const_cast(ref).setTarget(getGOT(da)); + return std::error_code(); + } +}; + +class DynamicRelocationPass final + : public RelocationPass { +public: + DynamicRelocationPass(const elf::X86_64LinkingContext &ctx) + : RelocationPass(ctx) {} + + const PLT0Atom *getPLT0() { + if (_PLT0) + return _PLT0; + // Fill in the null entry. + getNullGOT(); + _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file); + _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); + _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); + _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4); + _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4); +#ifndef NDEBUG + _got0->_name = "__got0"; + _got1->_name = "__got1"; +#endif + return _PLT0; + } + + const PLTAtom *getPLTEntry(const Atom *a) { + auto plt = _pltMap.find(a); + if (plt != _pltMap.end()) + return plt->second; + auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); + ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0); + auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); + pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); + pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0); + pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4); + // Set the starting address of the got entry to the second instruction in + // the plt entry. + ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6); +#ifndef NDEBUG + ga->_name = "__got_"; + ga->_name += a->name(); + pa->_name = "__plt_"; + pa->_name += a->name(); +#endif + _gotMap[a] = ga; + _pltMap[a] = pa; + _gotVector.push_back(ga); + _pltVector.push_back(pa); + return pa; + } + + const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { + auto obj = _objectMap.find(a); + if (obj != _objectMap.end()) + return obj->second; + + auto oa = new (_file._alloc) ObjectAtom(_file); + // This needs to point to the atom that we just created. + oa->addReferenceELF_x86_64(R_X86_64_COPY, 0, oa, 0); + + oa->_name = a->name(); + oa->_size = a->size(); + + _objectMap[a] = oa; + _objectVector.push_back(oa); + return oa; + } + + std::error_code handlePlain(const Reference &ref) { + if (!ref.target()) + return std::error_code(); + if (auto sla = dyn_cast(ref.target())) { + if (sla->type() == SharedLibraryAtom::Type::Data) + const_cast(ref).setTarget(getObjectEntry(sla)); + else if (sla->type() == SharedLibraryAtom::Type::Code) + const_cast(ref).setTarget(getPLTEntry(sla)); + } else + return handleIFUNC(ref); + return std::error_code(); + } + + std::error_code handlePLT32(const Reference &ref) { + // Turn this into a PC32 to the PLT entry. + const_cast(ref).setKindValue(R_X86_64_PC32); + // Handle IFUNC. + if (const DefinedAtom *da = + dyn_cast_or_null(ref.target())) + if (da->contentType() == DefinedAtom::typeResolver) + return handleIFUNC(ref); + // If it is undefined at link time, push the work to the dynamic linker by + // creating a PLT entry + if (isa(ref.target()) || + isa(ref.target())) + const_cast(ref).setTarget(getPLTEntry(ref.target())); + return std::error_code(); + } + + const GOTAtom *getSharedGOT(const Atom *a) { + auto got = _gotMap.find(a); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got.dyn"); + g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0); +#ifndef NDEBUG + g->_name = "__got_"; + g->_name += a->name(); +#endif + _gotMap[a] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + + std::error_code handleGOT(const Reference &ref) { + if (const DefinedAtom *da = dyn_cast(ref.target())) + const_cast(ref).setTarget(getGOT(da)); + // Handle undefined atoms in the same way as shared lib atoms: to be + // resolved at run time. + else if (isa(ref.target()) || + isa(ref.target())) + const_cast(ref).setTarget(getSharedGOT(ref.target())); + return std::error_code(); + } +}; +} // end anon namespace + +std::unique_ptr +lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) { + switch (ctx.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + if (ctx.isDynamic()) + return std::unique_ptr(new DynamicRelocationPass(ctx)); + else + return std::unique_ptr(new StaticRelocationPass(ctx)); + case llvm::ELF::ET_DYN: + return std::unique_ptr(new DynamicRelocationPass(ctx)); + case llvm::ELF::ET_REL: + return std::unique_ptr(); + default: + llvm_unreachable("Unhandled output file type"); + } +} Index: lib/ReaderWriter/ELF/X86/X86_64TargetHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64TargetHandler.h @@ -0,0 +1,65 @@ +//===- lib/ReaderWriter/ELF/X86/X86_64TargetHandler.h ---------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_X86_X86_64_TARGET_HANDLER_H +#define LLD_READER_WRITER_ELF_X86_X86_64_TARGET_HANDLER_H + +#include "DefaultTargetHandler.h" +#include "TargetLayout.h" +#include "X86_64ELFFile.h" +#include "X86_64ELFReader.h" +#include "X86_64RelocationHandler.h" +#include "lld/Core/Simple.h" + +namespace lld { +namespace elf { +class X86_64LinkingContext; + +template class X86_64TargetLayout : public TargetLayout { +public: + X86_64TargetLayout(X86_64LinkingContext &context) + : TargetLayout(context) {} +}; + +class X86_64TargetHandler final + : public DefaultTargetHandler { +public: + X86_64TargetHandler(X86_64LinkingContext &context); + + X86_64TargetLayout &getTargetLayout() override { + return *(_x86_64TargetLayout.get()); + } + + void registerRelocationNames(Registry ®istry) override; + + const X86_64TargetRelocationHandler &getRelocationHandler() const override { + return *(_x86_64RelocationHandler.get()); + } + + std::unique_ptr getObjReader(bool atomizeStrings) override { + return std::unique_ptr(new X86_64ELFObjectReader(atomizeStrings)); + } + + std::unique_ptr getDSOReader(bool useShlibUndefines) override { + return std::unique_ptr(new X86_64ELFDSOReader(useShlibUndefines)); + } + + std::unique_ptr getWriter() override; + +private: + static const Registry::KindStrings kindStrings[]; + X86_64LinkingContext &_context; + std::unique_ptr> _x86_64TargetLayout; + std::unique_ptr _x86_64RelocationHandler; +}; + +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/X86/X86_64TargetHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/X86/X86_64TargetHandler.cpp @@ -0,0 +1,54 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp ----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Atoms.h" +#include "X86_64DynamicLibraryWriter.h" +#include "X86_64ExecutableWriter.h" +#include "X86_64LinkingContext.h" +#include "X86_64TargetHandler.h" + +using namespace lld; +using namespace elf; + +X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &context) + : _context(context), + _x86_64TargetLayout(new X86_64TargetLayout(context)), + _x86_64RelocationHandler(new X86_64TargetRelocationHandler( + *_x86_64TargetLayout.get())) {} + +void X86_64TargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::x86_64, kindStrings); +} + +std::unique_ptr X86_64TargetHandler::getWriter() { + switch (this->_context.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + return std::unique_ptr(new X86_64ExecutableWriter( + _context, *_x86_64TargetLayout.get())); + case llvm::ELF::ET_DYN: + return std::unique_ptr( + new X86_64DynamicLibraryWriter( + _context, *_x86_64TargetLayout.get())); + case llvm::ELF::ET_REL: + llvm_unreachable("TODO: support -r mode"); + default: + llvm_unreachable("unsupported output type"); + } +} + +#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), + +const Registry::KindStrings X86_64TargetHandler::kindStrings[] = { +#include "llvm/Support/ELFRelocs/x86_64.def" + LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX), + LLD_KIND_STRING_END +}; + +#undef ELF_RELOC Index: lib/ReaderWriter/ELF/X86_64/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/X86_64/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_llvm_library(lldX86_64ELFTarget - X86_64LinkingContext.cpp - X86_64TargetHandler.cpp - X86_64RelocationHandler.cpp - X86_64RelocationPass.cpp - LINK_LIBS - lldCore - lldELF - LLVMObject - LLVMSupport - ) Index: lib/ReaderWriter/ELF/X86_64/Makefile =================================================================== --- lib/ReaderWriter/ELF/X86_64/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -##===- lld/lib/ReaderWriter/ELF/X86_64/Makefile ----------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLD_LEVEL := ../../../.. -LIBRARYNAME := lldX86_64ELFTarget -USEDLIBS = lldCore.a -CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF - -include $(LLD_LEVEL)/Makefile Index: lib/ReaderWriter/ELF/X86_64/TODO.rst =================================================================== --- lib/ReaderWriter/ELF/X86_64/TODO.rst +++ /dev/null @@ -1,48 +0,0 @@ -ELF x86-64 -~~~~~~~~~~ - -Unimplemented Features -###################### - -* Code models other than the small code model -* TLS strength reduction - -Unimplemented Relocations -######################### - -All of these relocations are defined in: -http://www.x86-64.org/documentation/abi.pdf - -Trivial Relocs -<<<<<<<<<<<<<< - -These are very simple relocation calculations to implement. -See lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp - -* R_X86_64_16 -* R_X86_64_PC16 -* R_X86_64_8 -* R_X86_64_PC8 -* R_X86_64_PC64 -* R_X86_64_SIZE32 -* R_X86_64_SIZE64 -* R_X86_64_GOTPC32 (this relocation requires there to be a __GLOBAL_OFFSET_TABLE__) - -Global Offset Table Relocs -<<<<<<<<<<<<<<<<<<<<<<<<<< - -* R_X86_64_GOTOFF32 -* R_X86_64_GOTOFF64 - -Global Dynamic Thread Local Storage Relocs -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - -These relocations take more effort to implement, but some of them are done. -Their implementation lives in lib/ReaderWriter/ELF/X86_64/{X86_64RelocationPass.cpp,X86_64RelocationHandler.cpp}. - -Documentation on these relocations can be found in: -http://www.akkadia.org/drepper/tls.pdf - -* R_X86_64_GOTPC32_TLSDESC -* R_X86_64_TLSDESC_CALL -* R_X86_64_TLSDESC Index: lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h +++ /dev/null @@ -1,69 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.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_LIBRARY_WRITER_H -#define X86_64_DYNAMIC_LIBRARY_WRITER_H - -#include "DynamicLibraryWriter.h" -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" - -namespace lld { -namespace elf { - -template -class X86_64DynamicLibraryWriter : public DynamicLibraryWriter { -public: - X86_64DynamicLibraryWriter(X86_64LinkingContext &context, - X86_64TargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - virtual bool createImplicitFiles(std::vector> &); - - virtual void finalizeDefaultAtomValues() { - return DynamicLibraryWriter::finalizeDefaultAtomValues(); - } - - virtual void addDefaultAtoms() { - return DynamicLibraryWriter::addDefaultAtoms(); - } - -private: - class GOTFile : public SimpleFile { - public: - GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} - llvm::BumpPtrAllocator _alloc; - }; - - std::unique_ptr _gotFile; - X86_64LinkingContext &_context; - X86_64TargetLayout &_x86_64Layout; -}; - -template -X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter( - X86_64LinkingContext &context, X86_64TargetLayout &layout) - : DynamicLibraryWriter(context, layout), - _gotFile(new GOTFile(context)), _context(context), _x86_64Layout(layout) { -} - -template -bool X86_64DynamicLibraryWriter::createImplicitFiles( - std::vector> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile)); - _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile)); - result.push_back(std::move(_gotFile)); - return true; -} - -} // namespace elf -} // namespace lld - -#endif Index: lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h +++ /dev/null @@ -1,41 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h ------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H -#define LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H - -#include "ELFReader.h" - -namespace lld { -namespace elf { - -class X86_64LinkingContext; - -template class X86_64ELFFile : public ELFFile { -public: - X86_64ELFFile(std::unique_ptr mb, bool atomizeStrings) - : ELFFile(std::move(mb), atomizeStrings) {} - - static ErrorOr> - create(std::unique_ptr mb, bool atomizeStrings) { - return std::unique_ptr>( - new X86_64ELFFile(std::move(mb), atomizeStrings)); - } -}; - -template class X86_64DynamicFile : public DynamicFile { -public: - X86_64DynamicFile(const X86_64LinkingContext &context, StringRef name) - : DynamicFile(context, name) {} -}; - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H Index: lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h +++ /dev/null @@ -1,61 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H -#define LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H - -#include "ELFReader.h" -#include "X86_64ELFFile.h" - -namespace lld { -namespace elf { - -typedef llvm::object::ELFType X86_64ELFType; - -struct X86_64DynamicFileCreateELFTraits { - typedef llvm::ErrorOr> result_type; - - template - static result_type create(std::unique_ptr mb, - bool useUndefines) { - return lld::elf::X86_64DynamicFile::create(std::move(mb), - useUndefines); - } -}; - -struct X86_64ELFFileCreateELFTraits { - typedef llvm::ErrorOr> result_type; - - template - static result_type create(std::unique_ptr mb, - bool atomizeStrings) { - return lld::elf::X86_64ELFFile::create(std::move(mb), atomizeStrings); - } -}; - -class X86_64ELFObjectReader - : public ELFObjectReader { -public: - X86_64ELFObjectReader(bool atomizeStrings) - : ELFObjectReader( - atomizeStrings, llvm::ELF::EM_X86_64) {} -}; - -class X86_64ELFDSOReader - : public ELFDSOReader { -public: - X86_64ELFDSOReader(bool useUndefines) - : ELFDSOReader( - useUndefines, llvm::ELF::EM_X86_64) {} -}; - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_X86_64_X86_64_READER_H Index: lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h +++ /dev/null @@ -1,68 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef X86_64_EXECUTABLE_WRITER_H -#define X86_64_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" -#include "X86_64LinkingContext.h" - -namespace lld { -namespace elf { - -template -class X86_64ExecutableWriter : public ExecutableWriter { -public: - X86_64ExecutableWriter(X86_64LinkingContext &context, - X86_64TargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - virtual bool createImplicitFiles(std::vector> &); - - virtual void finalizeDefaultAtomValues() { - return ExecutableWriter::finalizeDefaultAtomValues(); - } - - virtual void addDefaultAtoms() { - return ExecutableWriter::addDefaultAtoms(); - } - -private: - class GOTFile : public SimpleFile { - public: - GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} - llvm::BumpPtrAllocator _alloc; - }; - - std::unique_ptr _gotFile; - X86_64LinkingContext &_context; - X86_64TargetLayout &_x86_64Layout; -}; - -template -X86_64ExecutableWriter::X86_64ExecutableWriter( - X86_64LinkingContext &context, X86_64TargetLayout &layout) - : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)), - _context(context), _x86_64Layout(layout) {} - -template -bool X86_64ExecutableWriter::createImplicitFiles( - std::vector> &result) { - ExecutableWriter::createImplicitFiles(result); - _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile)); - if (_context.isDynamic()) - _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile)); - result.push_back(std::move(_gotFile)); - return true; -} - -} // namespace elf -} // namespace lld - -#endif Index: lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h +++ /dev/null @@ -1,99 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -/// \brief x86-64 internal references. -enum { - /// \brief The 32 bit index of the relocation in the got this reference refers - /// to. - LLD_R_X86_64_GOTRELINDEX = 1024, -}; - -class X86_64LinkingContext final : public ELFLinkingContext { -public: - static std::unique_ptr create(llvm::Triple); - X86_64LinkingContext(llvm::Triple); - - void addPasses(PassManager &) override; - - uint64_t getBaseAddress() const override { - if (_baseAddress == 0) - return 0x400000; - return _baseAddress; - } - - bool isDynamicRelocation(const DefinedAtom &, - const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - switch (r.kindValue()) { - case llvm::ELF::R_X86_64_RELATIVE: - case llvm::ELF::R_X86_64_GLOB_DAT: - case llvm::ELF::R_X86_64_COPY: - case llvm::ELF::R_X86_64_DTPMOD64: - case llvm::ELF::R_X86_64_DTPOFF64: - return true; - default: - return false; - } - } - - bool isCopyRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - if (r.kindValue() == llvm::ELF::R_X86_64_COPY) - return true; - return false; - } - - virtual bool isPLTRelocation(const DefinedAtom &, - const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - switch (r.kindValue()) { - case llvm::ELF::R_X86_64_JUMP_SLOT: - case llvm::ELF::R_X86_64_IRELATIVE: - return true; - default: - return false; - } - } - - /// \brief X86_64 has two relative relocations - /// a) for supporting IFUNC - R_X86_64_IRELATIVE - /// b) for supporting relative relocs - R_X86_64_RELATIVE - bool isRelativeReloc(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::x86_64); - switch (r.kindValue()) { - case llvm::ELF::R_X86_64_IRELATIVE: - case llvm::ELF::R_X86_64_RELATIVE: - return true; - default: - return false; - } - } -}; -} // end namespace elf -} // end namespace lld - -#endif Index: lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" -#include "X86_64RelocationPass.h" - -using namespace lld; - -std::unique_ptr -elf::X86_64LinkingContext::create(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::x86_64) - return std::unique_ptr( - new elf::X86_64LinkingContext(triple)); - return nullptr; -} - -elf::X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, std::unique_ptr( - new X86_64TargetHandler(*this))) {} - -void elf::X86_64LinkingContext::addPasses(PassManager &pm) { - auto pass = createX86_64RelocationPass(*this); - if (pass) - pm.add(std::move(pass)); - ELFLinkingContext::addPasses(pm); -} Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- 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; - -template class X86_64TargetLayout; - -class X86_64TargetRelocationHandler final : public TargetRelocationHandler { -public: - X86_64TargetRelocationHandler(X86_64TargetLayout &layout) - : _tlsSize(0), _x86_64Layout(layout) {} - - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const lld::AtomLayout &, - const Reference &) const override; - -private: - // Cached size of the TLS segment. - mutable uint64_t _tlsSize; - X86_64TargetLayout &_x86_64Layout; -}; - -} // end namespace elf -} // end namespace lld - -#endif // X86_64_RELOCATION_HANDLER_H Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp +++ /dev/null @@ -1,130 +0,0 @@ -//===- 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_64LinkingContext.h" -#include "X86_64TargetHandler.h" - -using namespace lld; -using namespace elf; - -/// \brief R_X86_64_64 - word64: S + A -static 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 -static 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 -static 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 -static 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. -} - -std::error_code X86_64TargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::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(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::x86_64); - switch (ref.kindValue()) { - case R_X86_64_NONE: - break; - case R_X86_64_64: - reloc64(location, relocVAddress, targetVAddress, ref.addend()); - break; - case R_X86_64_PC32: - case R_X86_64_GOTPCREL: - 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 = _x86_64Layout.getTLSSize(); - if (ref.kindValue() == R_X86_64_TPOFF32 || - ref.kindValue() == 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_TLSGD: { - relocPC32(location, relocVAddress, targetVAddress, ref.addend()); - 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->kindValue() == R_X86_64_JUMP_SLOT) { - uint32_t index; - if (!_x86_64Layout.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: - case R_X86_64_DTPMOD64: - case R_X86_64_DTPOFF64: - break; - default: - return make_unhandled_reloc_error(); - } - - return std::error_code(); -} Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h +++ /dev/null @@ -1,32 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Declares the relocation processing pass for x86-64. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H - -#include - -namespace lld { -class Pass; -namespace elf { -class X86_64LinkingContext; - -/// \brief Create x86-64 relocation pass for the given linking context. -std::unique_ptr -createX86_64RelocationPass(const X86_64LinkingContext &); -} -} - -#endif Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp +++ /dev/null @@ -1,515 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines the relocation processing pass for x86-64. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct, -/// 2013). -/// -/// This also includes aditional behaivor that gnu-ld and gold implement but -/// which is not specified anywhere. -/// -//===----------------------------------------------------------------------===// - -#include "X86_64RelocationPass.h" -#include "Atoms.h" -#include "X86_64LinkingContext.h" -#include "lld/Core/Simple.h" -#include "llvm/ADT/DenseMap.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -namespace { -// .got values -const uint8_t x86_64GotAtomContent[8] = { 0 }; - -// .plt value (entry 0) -const uint8_t x86_64Plt0AtomContent[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 -}; - -// .plt values (other entries) -const uint8_t x86_64PltAtomContent[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] -}; - -// TLS GD Entry -static const uint8_t x86_64GotTlsGdAtomContent[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -/// \brief Atoms that are used by X86_64 dynamic linking -class X86_64GOTAtom : public GOTAtom { -public: - X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} - - ArrayRef rawContent() const override { - return ArrayRef(x86_64GotAtomContent, 8); - } -}; - -/// \brief X86_64 GOT TLS GD entry. -class GOTTLSGdAtom : public X86_64GOTAtom { -public: - GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {} - - ArrayRef rawContent() const override { - return llvm::makeArrayRef(x86_64GotTlsGdAtomContent); - } -}; - -class X86_64PLT0Atom : public PLT0Atom { -public: - X86_64PLT0Atom(const File &f) : PLT0Atom(f) { -#ifndef NDEBUG - _name = ".PLT0"; -#endif - } - ArrayRef rawContent() const override { - return ArrayRef(x86_64Plt0AtomContent, 16); - } -}; - -class X86_64PLTAtom : public PLTAtom { -public: - X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {} - - ArrayRef rawContent() const override { - return ArrayRef(x86_64PltAtomContent, 16); - } -}; - -class ELFPassFile : public SimpleFile { -public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { - setOrdinal(eti.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -/// \brief CRTP base for handling relocations. -template class RelocationPass : public Pass { - /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::x86_64); - switch (ref.kindValue()) { - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_PC32: - case R_X86_64_PC64: - static_cast(this)->handlePlain(ref); - break; - case R_X86_64_PLT32: - static_cast(this)->handlePLT32(ref); - break; - case R_X86_64_GOT32: - case R_X86_64_GOTPC32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTOFF64: - static_cast(this)->handleGOT(ref); - break; - case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset - static_cast(this)->handleGOTTPOFF(ref); - break; - case R_X86_64_TLSGD: - static_cast(this)->handleTLSGd(ref); - break; - } - } - -protected: - /// \brief get the PLT entry for a given IFUNC Atom. - /// - /// If the entry does not exist. Both the GOT and PLT entry is created. - const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) { - auto plt = _pltMap.find(da); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0); - auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); - pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); -#ifndef NDEBUG - ga->_name = "__got_ifunc_"; - ga->_name += da->name(); - pa->_name = "__plt_ifunc_"; - pa->_name += da->name(); -#endif - _gotMap[da] = ga; - _pltMap[da] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - /// \brief Redirect the call to the PLT stub for the target IFUNC. - /// - /// This create a PLT and GOT entry for the IFUNC if one does not exist. The - /// GOT entry and a IRELATIVE relocation to the original target resolver. - std::error_code handleIFUNC(const Reference &ref) { - auto target = dyn_cast_or_null(ref.target()); - if (target && target->contentType() == DefinedAtom::typeResolver) - const_cast(ref).setTarget(getIFUNCPLTEntry(target)); - return std::error_code(); - } - - /// \brief Create a GOT entry for the TP offset of a TLS atom. - const GOTAtom *getGOTTPOFF(const Atom *atom) { - auto got = _gotMap.find(atom); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 0, atom, 0); -#ifndef NDEBUG - g->_name = "__got_tls_"; - g->_name += atom->name(); -#endif - _gotMap[atom] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to - /// the GOT. - void handleGOTTPOFF(const Reference &ref) { - const_cast(ref).setTarget(getGOTTPOFF(ref.target())); - const_cast(ref).setKindValue(R_X86_64_PC32); - } - - /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations. - void handleTLSGd(const Reference &ref) { - const_cast(ref).setTarget(getTLSGdGOTEntry(ref.target())); - } - - /// \brief Create a GOT entry containing 0. - const GOTAtom *getNullGOT() { - if (!_null) { - _null = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); -#ifndef NDEBUG - _null->_name = "__got_null"; -#endif - } - return _null; - } - - const GOTAtom *getGOT(const DefinedAtom *da) { - auto got = _gotMap.find(da); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReferenceELF_x86_64(R_X86_64_64, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_"; - g->_name += da->name(); -#endif - _gotMap[da] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - const GOTAtom *getTLSGdGOTEntry(const Atom *a) { - auto got = _gotTLSGdMap.find(a); - if (got != _gotTLSGdMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got"); - _gotTLSGdMap[a] = ga; - - _tlsGotVector.push_back(ga); - ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0); - ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0); - - return ga; - } - -public: - RelocationPass(const ELFLinkingContext &ctx) - : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr), - _got1(nullptr) {} - - /// \brief Do the pass. - /// - /// The goal here is to first process each reference individually. Each call - /// to handleReference may modify the reference itself and/or create new - /// atoms which must be stored in one of the maps below. - /// - /// After all references are handled, the atoms created during that are all - /// added to mf. - void perform(std::unique_ptr &mf) override { - ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass"); - // Process all references. - for (const auto &atom : mf->defined()) - for (const auto &ref : *atom) - handleReference(*atom, *ref); - - // Add all created atoms to the link. - uint64_t ordinal = 0; - if (_PLT0) { - _PLT0->setOrdinal(ordinal++); - mf->addAtom(*_PLT0); - } - for (auto &plt : _pltVector) { - plt->setOrdinal(ordinal++); - mf->addAtom(*plt); - } - if (_null) { - _null->setOrdinal(ordinal++); - mf->addAtom(*_null); - } - if (_PLT0) { - _got0->setOrdinal(ordinal++); - _got1->setOrdinal(ordinal++); - mf->addAtom(*_got0); - mf->addAtom(*_got1); - } - for (auto &got : _gotVector) { - got->setOrdinal(ordinal++); - mf->addAtom(*got); - } - for (auto &got : _tlsGotVector) { - got->setOrdinal(ordinal++); - mf->addAtom(*got); - } - for (auto obj : _objectVector) { - obj->setOrdinal(ordinal++); - mf->addAtom(*obj); - } - } - -protected: - /// \brief Owner of all the Atoms created by this pass. - ELFPassFile _file; - const ELFLinkingContext &_ctx; - - /// \brief Map Atoms to their GOT entries. - llvm::DenseMap _gotMap; - - /// \brief Map Atoms to their PLT entries. - llvm::DenseMap _pltMap; - - /// \brief Map Atoms to TLS GD GOT entries. - llvm::DenseMap _gotTLSGdMap; - - /// \brief Map Atoms to their Object entries. - llvm::DenseMap _objectMap; - - /// \brief the list of GOT/PLT atoms - std::vector _gotVector; - std::vector _pltVector; - std::vector _objectVector; - - /// \brief the list of TLS GOT atoms. - std::vector _tlsGotVector; - - /// \brief GOT entry that is always 0. Used for undefined weaks. - GOTAtom *_null; - - /// \brief The got and plt entries for .PLT0. This is used to call into the - /// dynamic linker for symbol resolution. - /// @{ - PLT0Atom *_PLT0; - GOTAtom *_got0; - GOTAtom *_got1; - /// @} -}; - -/// This implements the static relocation model. Meaning GOT and PLT entries are -/// not created for references that can be directly resolved. These are -/// converted to a direct relocation. For entries that do require a GOT or PLT -/// entry, that entry is statically bound. -/// -/// TLS always assumes module 1 and attempts to remove indirection. -class StaticRelocationPass final - : public RelocationPass { -public: - StaticRelocationPass(const elf::X86_64LinkingContext &ctx) - : RelocationPass(ctx) {} - - std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); } - - std::error_code handlePLT32(const Reference &ref) { - // __tls_get_addr is handled elsewhere. - if (ref.target() && ref.target()->name() == "__tls_get_addr") { - const_cast(ref).setKindValue(R_X86_64_NONE); - return std::error_code(); - } - // Static code doesn't need PLTs. - const_cast(ref).setKindValue(R_X86_64_PC32); - // Handle IFUNC. - if (const DefinedAtom *da = - dyn_cast_or_null(ref.target())) - if (da->contentType() == DefinedAtom::typeResolver) - return handleIFUNC(ref); - return std::error_code(); - } - - std::error_code handleGOT(const Reference &ref) { - if (isa(ref.target())) - const_cast(ref).setTarget(getNullGOT()); - else if (const DefinedAtom *da = dyn_cast(ref.target())) - const_cast(ref).setTarget(getGOT(da)); - return std::error_code(); - } -}; - -class DynamicRelocationPass final - : public RelocationPass { -public: - DynamicRelocationPass(const elf::X86_64LinkingContext &ctx) - : RelocationPass(ctx) {} - - const PLT0Atom *getPLT0() { - if (_PLT0) - return _PLT0; - // Fill in the null entry. - getNullGOT(); - _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file); - _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4); - _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4); -#ifndef NDEBUG - _got0->_name = "__got0"; - _got1->_name = "__got1"; -#endif - return _PLT0; - } - - const PLTAtom *getPLTEntry(const Atom *a) { - auto plt = _pltMap.find(a); - if (plt != _pltMap.end()) - return plt->second; - auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0); - auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); - pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); - pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0); - pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4); - // Set the starting address of the got entry to the second instruction in - // the plt entry. - ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6); -#ifndef NDEBUG - ga->_name = "__got_"; - ga->_name += a->name(); - pa->_name = "__plt_"; - pa->_name += a->name(); -#endif - _gotMap[a] = ga; - _pltMap[a] = pa; - _gotVector.push_back(ga); - _pltVector.push_back(pa); - return pa; - } - - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { - auto obj = _objectMap.find(a); - if (obj != _objectMap.end()) - return obj->second; - - auto oa = new (_file._alloc) ObjectAtom(_file); - // This needs to point to the atom that we just created. - oa->addReferenceELF_x86_64(R_X86_64_COPY, 0, oa, 0); - - oa->_name = a->name(); - oa->_size = a->size(); - - _objectMap[a] = oa; - _objectVector.push_back(oa); - return oa; - } - - std::error_code handlePlain(const Reference &ref) { - if (!ref.target()) - return std::error_code(); - if (auto sla = dyn_cast(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Data) - const_cast(ref).setTarget(getObjectEntry(sla)); - else if (sla->type() == SharedLibraryAtom::Type::Code) - const_cast(ref).setTarget(getPLTEntry(sla)); - } else - return handleIFUNC(ref); - return std::error_code(); - } - - std::error_code handlePLT32(const Reference &ref) { - // Turn this into a PC32 to the PLT entry. - const_cast(ref).setKindValue(R_X86_64_PC32); - // Handle IFUNC. - if (const DefinedAtom *da = - dyn_cast_or_null(ref.target())) - if (da->contentType() == DefinedAtom::typeResolver) - return handleIFUNC(ref); - // If it is undefined at link time, push the work to the dynamic linker by - // creating a PLT entry - if (isa(ref.target()) || - isa(ref.target())) - const_cast(ref).setTarget(getPLTEntry(ref.target())); - return std::error_code(); - } - - const GOTAtom *getSharedGOT(const Atom *a) { - auto got = _gotMap.find(a); - if (got == _gotMap.end()) { - auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got.dyn"); - g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0); -#ifndef NDEBUG - g->_name = "__got_"; - g->_name += a->name(); -#endif - _gotMap[a] = g; - _gotVector.push_back(g); - return g; - } - return got->second; - } - - std::error_code handleGOT(const Reference &ref) { - if (const DefinedAtom *da = dyn_cast(ref.target())) - const_cast(ref).setTarget(getGOT(da)); - // Handle undefined atoms in the same way as shared lib atoms: to be - // resolved at run time. - else if (isa(ref.target()) || - isa(ref.target())) - const_cast(ref).setTarget(getSharedGOT(ref.target())); - return std::error_code(); - } -}; -} // end anon namespace - -std::unique_ptr -lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - if (ctx.isDynamic()) - return std::unique_ptr(new DynamicRelocationPass(ctx)); - else - return std::unique_ptr(new StaticRelocationPass(ctx)); - case llvm::ELF::ET_DYN: - return std::unique_ptr(new DynamicRelocationPass(ctx)); - case llvm::ELF::ET_REL: - return std::unique_ptr(); - default: - llvm_unreachable("Unhandled output file type"); - } -} Index: lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ /dev/null @@ -1,65 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H - -#include "DefaultTargetHandler.h" -#include "TargetLayout.h" -#include "X86_64ELFFile.h" -#include "X86_64ELFReader.h" -#include "X86_64RelocationHandler.h" -#include "lld/Core/Simple.h" - -namespace lld { -namespace elf { -class X86_64LinkingContext; - -template class X86_64TargetLayout : public TargetLayout { -public: - X86_64TargetLayout(X86_64LinkingContext &context) - : TargetLayout(context) {} -}; - -class X86_64TargetHandler final - : public DefaultTargetHandler { -public: - X86_64TargetHandler(X86_64LinkingContext &context); - - X86_64TargetLayout &getTargetLayout() override { - return *(_x86_64TargetLayout.get()); - } - - void registerRelocationNames(Registry ®istry) override; - - const X86_64TargetRelocationHandler &getRelocationHandler() const override { - return *(_x86_64RelocationHandler.get()); - } - - std::unique_ptr getObjReader(bool atomizeStrings) override { - return std::unique_ptr(new X86_64ELFObjectReader(atomizeStrings)); - } - - std::unique_ptr getDSOReader(bool useShlibUndefines) override { - return std::unique_ptr(new X86_64ELFDSOReader(useShlibUndefines)); - } - - std::unique_ptr getWriter() override; - -private: - static const Registry::KindStrings kindStrings[]; - X86_64LinkingContext &_context; - std::unique_ptr> _x86_64TargetLayout; - std::unique_ptr _x86_64RelocationHandler; -}; - -} // end namespace elf -} // end namespace lld - -#endif Index: lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "X86_64DynamicLibraryWriter.h" -#include "X86_64ExecutableWriter.h" -#include "X86_64LinkingContext.h" -#include "X86_64TargetHandler.h" - -using namespace lld; -using namespace elf; - -X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &context) - : _context(context), - _x86_64TargetLayout(new X86_64TargetLayout(context)), - _x86_64RelocationHandler(new X86_64TargetRelocationHandler( - *_x86_64TargetLayout.get())) {} - -void X86_64TargetHandler::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, - Reference::KindArch::x86_64, kindStrings); -} - -std::unique_ptr X86_64TargetHandler::getWriter() { - switch (this->_context.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return std::unique_ptr(new X86_64ExecutableWriter( - _context, *_x86_64TargetLayout.get())); - case llvm::ELF::ET_DYN: - return std::unique_ptr( - new X86_64DynamicLibraryWriter( - _context, *_x86_64TargetLayout.get())); - case llvm::ELF::ET_REL: - llvm_unreachable("TODO: support -r mode"); - default: - llvm_unreachable("unsupported output type"); - } -} - -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), - -const Registry::KindStrings X86_64TargetHandler::kindStrings[] = { -#include "llvm/Support/ELFRelocs/x86_64.def" - LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX), - LLD_KIND_STRING_END -}; - -#undef ELF_RELOC Index: tools/lld/Makefile =================================================================== --- tools/lld/Makefile +++ tools/lld/Makefile @@ -23,7 +23,7 @@ lldELF.a lldMachO.a lldPasses.a lldPECOFF.a lldYAML.a \ lldReaderWriter.a lldCore.a lldNative.a \ lldHexagonELFTarget.a lldMipsELFTarget.a \ - lldX86ELFTarget.a lldX86_64ELFTarget.a lldAArch64ELFTarget.a \ + lldX86ELFTarget.a lldAArch64ELFTarget.a \ lldARMELFTarget.a \ LLVMOption.a