diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp --- a/lld/MachO/Arch/ARM64.cpp +++ b/lld/MachO/Arch/ARM64.cpp @@ -39,7 +39,7 @@ uint64_t entryAddr) const override; void relaxGotLoad(uint8_t *loc, uint8_t type) const override; - const TargetInfo::RelocAttrs &getRelocAttrs(uint8_t type) const override; + const RelocAttrs &getRelocAttrs(uint8_t type) const override; uint64_t getPageSize() const override { return 16 * 1024; } }; @@ -52,8 +52,8 @@ // are weird -- it results in the value of the GOT slot being written, instead // of the address. Let's not support it unless we find a real-world use case. -const TargetInfo::RelocAttrs &ARM64::getRelocAttrs(uint8_t type) const { - static const std::array relocAttrsArray{{ +const RelocAttrs &ARM64::getRelocAttrs(uint8_t type) const { + static const std::array relocAttrsArray{{ #define B(x) RelocAttrBits::x {"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(DYSYM8) | B(BYTE4) | B(BYTE8)}, @@ -73,7 +73,7 @@ }}; assert(type < relocAttrsArray.size() && "invalid relocation type"); if (type >= relocAttrsArray.size()) - return TargetInfo::invalidRelocAttrs; + return invalidRelocAttrs; return relocAttrsArray[type]; } diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -36,14 +36,14 @@ uint64_t entryAddr) const override; void relaxGotLoad(uint8_t *loc, uint8_t type) const override; - const TargetInfo::RelocAttrs &getRelocAttrs(uint8_t type) const override; + const RelocAttrs &getRelocAttrs(uint8_t type) const override; uint64_t getPageSize() const override { return 4 * 1024; } }; } // namespace -const TargetInfo::RelocAttrs &X86_64::getRelocAttrs(uint8_t type) const { - static const std::array relocAttrsArray{{ +const RelocAttrs &X86_64::getRelocAttrs(uint8_t type) const { + static const std::array relocAttrsArray{{ #define B(x) RelocAttrBits::x {"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(DYSYM8) | B(BYTE4) | B(BYTE8)}, @@ -60,7 +60,7 @@ }}; assert(type < relocAttrsArray.size() && "invalid relocation type"); if (type >= relocAttrsArray.size()) - return TargetInfo::invalidRelocAttrs; + return invalidRelocAttrs; return relocAttrsArray[type]; } diff --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt --- a/lld/MachO/CMakeLists.txt +++ b/lld/MachO/CMakeLists.txt @@ -19,6 +19,7 @@ ObjC.cpp OutputSection.cpp OutputSegment.cpp + Relocations.cpp SymbolTable.cpp Symbols.cpp SyntheticSections.cpp diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -203,7 +203,7 @@ static bool validateRelocationInfo(InputFile *file, const section_64 &sec, relocation_info rel) { - const TargetInfo::RelocAttrs &relocAttrs = target->getRelocAttrs(rel.r_type); + const RelocAttrs &relocAttrs = target->getRelocAttrs(rel.r_type); bool valid = true; auto message = [relocAttrs, file, sec, rel, &valid](const Twine &diagnostic) { valid = false; diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -9,9 +9,10 @@ #ifndef LLD_MACHO_INPUT_SECTION_H #define LLD_MACHO_INPUT_SECTION_H +#include "Relocations.h" + #include "lld/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/PointerUnion.h" #include "llvm/BinaryFormat/MachO.h" namespace lld { @@ -23,19 +24,6 @@ class Symbol; class Defined; -struct Reloc { - uint8_t type = llvm::MachO::GENERIC_RELOC_INVALID; - bool pcrel = false; - uint8_t length = 0; - // The offset from the start of the subsection that this relocation belongs - // to. - uint32_t offset = 0; - // Adding this offset to the address of the referent symbol or subsection - // gives the destination that this relocation refers to. - uint64_t addend = 0; - llvm::PointerUnion referent = nullptr; -}; - class InputSection { public: virtual ~InputSection() = default; diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -36,7 +36,7 @@ static uint64_t resolveSymbolVA(uint8_t *loc, const lld::macho::Symbol &sym, uint8_t type) { - const TargetInfo::RelocAttrs &relocAttrs = target->getRelocAttrs(type); + const RelocAttrs &relocAttrs = target->getRelocAttrs(type); if (relocAttrs.hasAttr(RelocAttrBits::BRANCH)) { if (sym.isInStubs()) return in.stubs->addr + sym.stubsIndex * target->stubSize; diff --git a/lld/MachO/Relocations.h b/lld/MachO/Relocations.h new file mode 100644 --- /dev/null +++ b/lld/MachO/Relocations.h @@ -0,0 +1,74 @@ +//===- Relocations.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_MACHO_RELOCATIONS_H +#define LLD_MACHO_RELOCATIONS_H + +#include "llvm/ADT/BitmaskEnum.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/BinaryFormat/MachO.h" + +#include +#include + +namespace lld { +namespace macho { +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class Symbol; +class InputSection; + +enum class RelocAttrBits { + _0 = 0, // invalid + PCREL = 1 << 0, // Value is PC-relative offset + ABSOLUTE = 1 << 1, // Value is an absolute address or fixed offset + BYTE4 = 1 << 2, // 4 byte datum + BYTE8 = 1 << 3, // 8 byte datum + EXTERN = 1 << 4, // Can have an external symbol + LOCAL = 1 << 5, // Can have a local symbol + ADDEND = 1 << 6, // *_ADDEND paired prefix reloc + SUBTRAHEND = 1 << 7, // *_SUBTRACTOR paired prefix reloc + BRANCH = 1 << 8, // Value is branch target + GOT = 1 << 9, // References a symbol in the Global Offset Table + TLV = 1 << 10, // References a thread-local symbol + DYSYM8 = 1 << 11, // Requires DySym width to be 8 bytes + LOAD = 1 << 12, // Relaxable indirect load + POINTER = 1 << 13, // Non-relaxable indirect load (pointer is taken) + UNSIGNED = 1 << 14, // *_UNSIGNED relocs + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 15) - 1), +}; +// Note: SUBTRACTOR always pairs with UNSIGNED (a delta between two symbols). + +struct RelocAttrs { + llvm::StringRef name; + RelocAttrBits bits; + bool hasAttr(RelocAttrBits b) const { return (bits & b) == b; } +}; + +struct Reloc { + uint8_t type = llvm::MachO::GENERIC_RELOC_INVALID; + bool pcrel = false; + uint8_t length = 0; + // The offset from the start of the subsection that this relocation belongs + // to. + uint32_t offset = 0; + // Adding this offset to the address of the referent symbol or subsection + // gives the destination that this relocation refers to. + uint64_t addend = 0; + llvm::PointerUnion referent = nullptr; +}; + +bool validateSymbolRelocation(const Symbol *, const InputSection *, + const Reloc &); + +extern const RelocAttrs invalidRelocAttrs; + +} // namespace macho +} // namespace lld + +#endif diff --git a/lld/MachO/Target.cpp b/lld/MachO/Relocations.cpp copy from lld/MachO/Target.cpp copy to lld/MachO/Relocations.cpp --- a/lld/MachO/Target.cpp +++ b/lld/MachO/Relocations.cpp @@ -1,4 +1,4 @@ -//===- Target.cpp ---------------------------------------------------------===// +//===- Relocations.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,10 +6,10 @@ // //===----------------------------------------------------------------------===// -#include "Target.h" -#include "InputSection.h" +#include "Relocations.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "Target.h" #include "lld/Common/ErrorHandler.h" @@ -17,13 +17,9 @@ using namespace lld; using namespace lld::macho; -const TargetInfo::RelocAttrs TargetInfo::invalidRelocAttrs{"INVALID", - RelocAttrBits::_0}; - -bool TargetInfo::validateSymbolRelocation(const Symbol *sym, - const InputSection *isec, - const Reloc &r) { - const RelocAttrs &relocAttrs = getRelocAttrs(r.type); +bool macho::validateSymbolRelocation(const Symbol *sym, + const InputSection *isec, const Reloc &r) { + const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type); bool valid = true; auto message = [relocAttrs, sym, isec, &valid](const Twine &diagnostic) { valid = false; @@ -43,4 +39,4 @@ return valid; } -TargetInfo *macho::target = nullptr; +const RelocAttrs macho::invalidRelocAttrs{"INVALID", RelocAttrBits::_0}; diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h --- a/lld/MachO/Target.h +++ b/lld/MachO/Target.h @@ -9,6 +9,8 @@ #ifndef LLD_MACHO_TARGET_H #define LLD_MACHO_TARGET_H +#include "Relocations.h" + #include "llvm/ADT/BitmaskEnum.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/MemoryBuffer.h" @@ -23,7 +25,6 @@ class Symbol; class DylibSymbol; class InputSection; -struct Reloc; enum : uint64_t { // We are currently only supporting 64-bit targets since macOS and iOS are @@ -33,36 +34,8 @@ MaxAlignmentPowerOf2 = 32, }; -enum class RelocAttrBits { - _0 = 0, // invalid - PCREL = 1 << 0, // Value is PC-relative offset - ABSOLUTE = 1 << 1, // Value is an absolute address or fixed offset - BYTE4 = 1 << 2, // 4 byte datum - BYTE8 = 1 << 3, // 8 byte datum - EXTERN = 1 << 4, // Can have an external symbol - LOCAL = 1 << 5, // Can have a local symbol - ADDEND = 1 << 6, // *_ADDEND paired prefix reloc - SUBTRAHEND = 1 << 7, // *_SUBTRACTOR paired prefix reloc - BRANCH = 1 << 8, // Value is branch target - GOT = 1 << 9, // References a symbol in the Global Offset Table - TLV = 1 << 10, // References a thread-local symbol - DYSYM8 = 1 << 11, // Requires DySym width to be 8 bytes - LOAD = 1 << 12, // Relaxable indirect load - POINTER = 1 << 13, // Non-relaxable indirect load (pointer is taken) - UNSIGNED = 1 << 14, // *_UNSIGNED relocs - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 15) - 1), -}; -// Note: SUBTRACTOR always pairs with UNSIGNED (a delta between two symbols). - class TargetInfo { public: - struct RelocAttrs { - llvm::StringRef name; - RelocAttrBits bits; - bool hasAttr(RelocAttrBits b) const { return (bits & b) == b; } - }; - static const RelocAttrs invalidRelocAttrs; - virtual ~TargetInfo() = default; // Validate the relocation structure and get its addend. @@ -97,8 +70,6 @@ bool validateRelocationInfo(llvm::MemoryBufferRef, const llvm::MachO::section_64 &sec, llvm::MachO::relocation_info); - bool validateSymbolRelocation(const Symbol *, const InputSection *isec, - const Reloc &); void prepareSymbolRelocation(Symbol *, const InputSection *, const Reloc &); uint32_t cpuType; diff --git a/lld/MachO/Target.cpp b/lld/MachO/Target.cpp --- a/lld/MachO/Target.cpp +++ b/lld/MachO/Target.cpp @@ -7,40 +7,8 @@ //===----------------------------------------------------------------------===// #include "Target.h" -#include "InputSection.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "lld/Common/ErrorHandler.h" - -using namespace llvm; using namespace lld; using namespace lld::macho; -const TargetInfo::RelocAttrs TargetInfo::invalidRelocAttrs{"INVALID", - RelocAttrBits::_0}; - -bool TargetInfo::validateSymbolRelocation(const Symbol *sym, - const InputSection *isec, - const Reloc &r) { - const RelocAttrs &relocAttrs = getRelocAttrs(r.type); - bool valid = true; - auto message = [relocAttrs, sym, isec, &valid](const Twine &diagnostic) { - valid = false; - return (relocAttrs.name + " relocation " + diagnostic + " for `" + - sym->getName() + "' in " + toString(isec)) - .str(); - }; - - if (relocAttrs.hasAttr(RelocAttrBits::TLV) != sym->isTlv()) - error(message(Twine("requires that variable ") + - (sym->isTlv() ? "not " : "") + "be thread-local")); - if (relocAttrs.hasAttr(RelocAttrBits::DYSYM8) && isa(sym) && - r.length != 3) - error(message("has width " + std::to_string(1 << r.length) + - " bytes, but must be 8 bytes")); - - return valid; -} - TargetInfo *macho::target = nullptr; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -444,7 +444,7 @@ static void prepareSymbolRelocation(lld::macho::Symbol *sym, const InputSection *isec, const Reloc &r) { - const TargetInfo::RelocAttrs &relocAttrs = target->getRelocAttrs(r.type); + const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type); if (relocAttrs.hasAttr(RelocAttrBits::BRANCH)) { prepareBranchTarget(sym); @@ -484,8 +484,7 @@ if (auto *undefined = dyn_cast(sym)) treatUndefinedSymbol(*undefined); // treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check. - if (!isa(sym) && - target->validateSymbolRelocation(sym, isec, r)) + if (!isa(sym) && validateSymbolRelocation(sym, isec, r)) prepareSymbolRelocation(sym, isec, r); } else { assert(r.referent.is());