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(Reloc) == 24, 22 "Try to minimize Reloc's size; we create many instances"); 23 24 bool macho::validateSymbolRelocation(const Symbol *sym, 25 const InputSection *isec, const Reloc &r) { 26 const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type); 27 bool valid = true; 28 auto message = [&](const Twine &diagnostic) { 29 valid = false; 30 return (isec->getLocation(r.offset) + ": " + relocAttrs.name + 31 " relocation " + diagnostic) 32 .str(); 33 }; 34 35 if (relocAttrs.hasAttr(RelocAttrBits::TLV) != sym->isTlv()) 36 error(message(Twine("requires that symbol ") + sym->getName() + " " + 37 (sym->isTlv() ? "not " : "") + "be thread-local")); 38 39 return valid; 40 } 41 42 // Given an offset in the output buffer, figure out which ConcatInputSection (if 43 // any) maps to it. At the same time, update the offset such that it is relative 44 // to the InputSection rather than to the output buffer. 45 // 46 // Obtaining the InputSection allows us to have better error diagnostics. 47 // However, many of our relocation-handling methods do not take the InputSection 48 // as a parameter. Since we are already passing the buffer offsets to our Target 49 // methods, this function allows us to emit better errors without threading an 50 // additional InputSection argument through the call stack. 51 // 52 // This is implemented as a slow linear search through OutputSegments, 53 // OutputSections, and finally the InputSections themselves. However, this 54 // function should be called only on error paths, so some overhead is fine. 55 InputSection *macho::offsetToInputSection(uint64_t *off) { 56 for (OutputSegment *seg : outputSegments) { 57 if (*off < seg->fileOff || *off >= seg->fileOff + seg->fileSize) 58 continue; 59 60 const std::vector<OutputSection *> §ions = seg->getSections(); 61 size_t osecIdx = 0; 62 for (; osecIdx < sections.size(); ++osecIdx) 63 if (*off < sections[osecIdx]->fileOff) 64 break; 65 assert(osecIdx > 0); 66 // We should be only calling this function on offsets that belong to 67 // ConcatOutputSections. 68 auto *osec = cast<ConcatOutputSection>(sections[osecIdx - 1]); 69 *off -= osec->fileOff; 70 71 size_t isecIdx = 0; 72 for (; isecIdx < osec->inputs.size(); ++isecIdx) { 73 const ConcatInputSection *isec = osec->inputs[isecIdx]; 74 if (*off < isec->outSecOff) 75 break; 76 } 77 assert(isecIdx > 0); 78 ConcatInputSection *isec = osec->inputs[isecIdx - 1]; 79 *off -= isec->outSecOff; 80 return isec; 81 } 82 return nullptr; 83 } 84 85 void macho::reportRangeError(void *loc, const Reloc &r, const Twine &v, 86 uint8_t bits, int64_t min, uint64_t max) { 87 std::string hint; 88 uint64_t off = reinterpret_cast<const uint8_t *>(loc) - in.bufferStart; 89 const InputSection *isec = offsetToInputSection(&off); 90 std::string locStr = isec ? isec->getLocation(off) : "(invalid location)"; 91 if (auto *sym = r.referent.dyn_cast<Symbol *>()) 92 hint = "; references " + toString(*sym); 93 error(locStr + ": relocation " + target->getRelocAttrs(r.type).name + 94 " is out of range: " + v + " is not in [" + Twine(min) + ", " + 95 Twine(max) + "]" + hint); 96 } 97 98 void macho::reportRangeError(void *loc, SymbolDiagnostic d, const Twine &v, 99 uint8_t bits, int64_t min, uint64_t max) { 100 // FIXME: should we use `loc` somehow to provide a better error message? 101 std::string hint; 102 if (d.symbol) 103 hint = "; references " + toString(*d.symbol); 104 error(d.reason + " is out of range: " + v + " is not in [" + Twine(min) + 105 ", " + Twine(max) + "]" + hint); 106 } 107 108 const RelocAttrs macho::invalidRelocAttrs{"INVALID", RelocAttrBits::_0}; 109