| 1 | //===- Relocations.cpp ----------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "Relocations.h" |
| 10 | #include "ConcatOutputSection.h" |
| 11 | #include "Symbols.h" |
| 12 | #include "SyntheticSections.h" |
| 13 | #include "Target.h" |
| 14 | |
| 15 | #include "lld/Common/ErrorHandler.h" |
| 16 | |
| 17 | using namespace llvm; |
| 18 | using namespace lld; |
| 19 | using namespace lld::macho; |
| 20 | |
| 21 | static_assert(sizeof(void *) != 8 || sizeof(Relocation) == 24, |
| 22 | "Try to minimize Reloc's size; we create many instances" ); |
| 23 | |
| 24 | InputSection *Relocation::getReferentInputSection() const { |
| 25 | if (const auto *sym = dyn_cast<Symbol *>(Val: referent)) { |
| 26 | if (const auto *d = dyn_cast<Defined>(Val: sym)) |
| 27 | return d->isec(); |
| 28 | return nullptr; |
| 29 | } else { |
| 30 | return cast<InputSection *>(Val: referent); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | StringRef Relocation::getReferentString() const { |
| 35 | if (auto *isec = dyn_cast<InputSection *>(Val: referent)) { |
| 36 | const auto *cisec = dyn_cast<CStringInputSection>(Val: isec); |
| 37 | assert(cisec && "referent must be a CStringInputSection" ); |
| 38 | return cisec->getStringRefAtOffset(off: addend); |
| 39 | } |
| 40 | |
| 41 | auto *sym = dyn_cast<Defined>(Val: cast<Symbol *>(Val: referent)); |
| 42 | assert(sym && "referent must be a Defined symbol" ); |
| 43 | |
| 44 | auto *symIsec = sym->isec(); |
| 45 | auto symOffset = sym->value + addend; |
| 46 | |
| 47 | if (auto *s = dyn_cast_or_null<CStringInputSection>(Val: symIsec)) |
| 48 | return s->getStringRefAtOffset(off: symOffset); |
| 49 | |
| 50 | if (isa<ConcatInputSection>(Val: symIsec)) { |
| 51 | auto strData = symIsec->data.slice(N: symOffset); |
| 52 | const char *pszData = reinterpret_cast<const char *>(strData.data()); |
| 53 | return StringRef(pszData, strnlen(string: pszData, maxlen: strData.size())); |
| 54 | } |
| 55 | |
| 56 | llvm_unreachable("unknown reference section in getReferentString" ); |
| 57 | } |
| 58 | |
| 59 | bool macho::validateSymbolRelocation(const Symbol *sym, |
| 60 | const InputSection *isec, |
| 61 | const Relocation &r) { |
| 62 | const RelocAttrs &relocAttrs = target->getRelocAttrs(type: r.type); |
| 63 | bool valid = true; |
| 64 | auto message = [&](const Twine &diagnostic) { |
| 65 | valid = false; |
| 66 | return (isec->getLocation(off: r.offset) + ": " + relocAttrs.name + |
| 67 | " relocation " + diagnostic) |
| 68 | .str(); |
| 69 | }; |
| 70 | |
| 71 | // A GOT relocation against a thread-local is valid: the slot holds the |
| 72 | // address of the TLV descriptor, which is what such a reference asks for. |
| 73 | // Branch and unsigned relocations can likewise refer to the descriptor via |
| 74 | // a stub or pointer. ld-prime accepts all three kinds. |
| 75 | // |
| 76 | // A direct relocation against an imported TLV is not valid because an |
| 77 | // imported descriptor has no link-time address. Conversely, a TLV |
| 78 | // relocation against a symbol known not to be thread-local would interpret |
| 79 | // the referent's first word as a resolver function. Keep rejecting both. |
| 80 | // |
| 81 | // A dynamic-lookup symbol has no defining dylib, and Mach-O cannot express |
| 82 | // thread-locality on an undefined reference, so its kind is unknowable here. |
| 83 | // dyld resolves it at load time; rejecting it would refuse a valid link. |
| 84 | const auto *dysym = dyn_cast<DylibSymbol>(Val: sym); |
| 85 | const bool tlvKindIsKnown = !(dysym && dysym->isDynamicLookup()); |
| 86 | const bool isTlvReloc = relocAttrs.hasAttr(b: RelocAttrBits::TLV); |
| 87 | const bool permitsTlvDescriptor = isTlvReloc || |
| 88 | relocAttrs.hasAttr(b: RelocAttrBits::GOT) || |
| 89 | relocAttrs.hasAttr(b: RelocAttrBits::BRANCH) || |
| 90 | relocAttrs.hasAttr(b: RelocAttrBits::UNSIGNED); |
| 91 | const bool isImportedTlv = dysym && sym->isTlv(); |
| 92 | |
| 93 | if (tlvKindIsKnown) { |
| 94 | if (isTlvReloc && !sym->isTlv()) |
| 95 | error(msg: message(Twine("requires that symbol " ) + sym->getName() + |
| 96 | " be thread-local" )); |
| 97 | else if (isImportedTlv && !permitsTlvDescriptor) |
| 98 | error(msg: message(Twine("cannot reference imported thread-local symbol " ) + |
| 99 | sym->getName() + |
| 100 | "; its TLV descriptor has no address at link time" )); |
| 101 | } |
| 102 | |
| 103 | return valid; |
| 104 | } |
| 105 | |
| 106 | // Given an offset in the output buffer, figure out which ConcatInputSection (if |
| 107 | // any) maps to it. At the same time, update the offset such that it is relative |
| 108 | // to the InputSection rather than to the output buffer. |
| 109 | // |
| 110 | // Obtaining the InputSection allows us to have better error diagnostics. |
| 111 | // However, many of our relocation-handling methods do not take the InputSection |
| 112 | // as a parameter. Since we are already passing the buffer offsets to our Target |
| 113 | // methods, this function allows us to emit better errors without threading an |
| 114 | // additional InputSection argument through the call stack. |
| 115 | // |
| 116 | // This is implemented as a slow linear search through OutputSegments, |
| 117 | // OutputSections, and finally the InputSections themselves. However, this |
| 118 | // function should be called only on error paths, so some overhead is fine. |
| 119 | InputSection *macho::offsetToInputSection(uint64_t *off) { |
| 120 | for (OutputSegment *seg : outputSegments) { |
| 121 | if (*off < seg->fileOff || *off >= seg->fileOff + seg->fileSize) |
| 122 | continue; |
| 123 | |
| 124 | const std::vector<OutputSection *> §ions = seg->getSections(); |
| 125 | size_t osecIdx = 0; |
| 126 | for (; osecIdx < sections.size(); ++osecIdx) |
| 127 | if (*off < sections[osecIdx]->fileOff) |
| 128 | break; |
| 129 | assert(osecIdx > 0); |
| 130 | // We should be only calling this function on offsets that belong to |
| 131 | // ConcatOutputSections. |
| 132 | auto *osec = cast<ConcatOutputSection>(Val: sections[osecIdx - 1]); |
| 133 | *off -= osec->fileOff; |
| 134 | |
| 135 | size_t isecIdx = 0; |
| 136 | for (; isecIdx < osec->inputs.size(); ++isecIdx) { |
| 137 | const ConcatInputSection *isec = osec->inputs[isecIdx]; |
| 138 | if (*off < isec->outSecOff) |
| 139 | break; |
| 140 | } |
| 141 | assert(isecIdx > 0); |
| 142 | ConcatInputSection *isec = osec->inputs[isecIdx - 1]; |
| 143 | *off -= isec->outSecOff; |
| 144 | return isec; |
| 145 | } |
| 146 | return nullptr; |
| 147 | } |
| 148 | |
| 149 | void macho::reportRangeError(void *loc, const Relocation &r, const Twine &v, |
| 150 | uint8_t bits, int64_t min, uint64_t max) { |
| 151 | std::string hint; |
| 152 | uint64_t off = reinterpret_cast<const uint8_t *>(loc) - in.bufferStart; |
| 153 | const InputSection *isec = offsetToInputSection(off: &off); |
| 154 | std::string locStr = isec ? isec->getLocation(off) : "(invalid location)" ; |
| 155 | if (auto *sym = r.referent.dyn_cast<Symbol *>()) |
| 156 | hint = "; references " + toString(*sym); |
| 157 | error(msg: locStr + ": relocation " + target->getRelocAttrs(type: r.type).name + |
| 158 | " is out of range: " + v + " is not in [" + Twine(min) + ", " + |
| 159 | Twine(max) + "]" + hint); |
| 160 | } |
| 161 | |
| 162 | void macho::reportRangeError(void *loc, SymbolDiagnostic d, const Twine &v, |
| 163 | uint8_t bits, int64_t min, uint64_t max) { |
| 164 | // FIXME: should we use `loc` somehow to provide a better error message? |
| 165 | std::string hint; |
| 166 | if (d.symbol) |
| 167 | hint = "; references " + toString(*d.symbol); |
| 168 | error(msg: d.reason + " is out of range: " + v + " is not in [" + Twine(min) + |
| 169 | ", " + Twine(max) + "]" + hint); |
| 170 | } |
| 171 | |
| 172 | const RelocAttrs macho::invalidRelocAttrs{.name: "INVALID" , .bits: RelocAttrBits::_0}; |
| 173 | |