1fe6060f1SDimitry Andric //===- Relocations.cpp ----------------------------------------------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #include "Relocations.h" 1081ad6265SDimitry Andric #include "ConcatOutputSection.h" 11fe6060f1SDimitry Andric #include "Symbols.h" 12fe6060f1SDimitry Andric #include "SyntheticSections.h" 13fe6060f1SDimitry Andric #include "Target.h" 14fe6060f1SDimitry Andric 15fe6060f1SDimitry Andric #include "lld/Common/ErrorHandler.h" 16fe6060f1SDimitry Andric 17fe6060f1SDimitry Andric using namespace llvm; 18fe6060f1SDimitry Andric using namespace lld; 19fe6060f1SDimitry Andric using namespace lld::macho; 20fe6060f1SDimitry Andric 21349cc55cSDimitry Andric static_assert(sizeof(void *) != 8 || sizeof(Reloc) == 24, 22349cc55cSDimitry Andric "Try to minimize Reloc's size; we create many instances"); 23349cc55cSDimitry Andric 2406c3fb27SDimitry Andric InputSection *Reloc::getReferentInputSection() const { 2506c3fb27SDimitry Andric if (const auto *sym = referent.dyn_cast<Symbol *>()) { 2606c3fb27SDimitry Andric if (const auto *d = dyn_cast<Defined>(sym)) 27*0fca6ea1SDimitry Andric return d->isec(); 2806c3fb27SDimitry Andric return nullptr; 2906c3fb27SDimitry Andric } else { 3006c3fb27SDimitry Andric return referent.get<InputSection *>(); 3106c3fb27SDimitry Andric } 3206c3fb27SDimitry Andric } 3306c3fb27SDimitry Andric 34fe6060f1SDimitry Andric bool macho::validateSymbolRelocation(const Symbol *sym, 35fe6060f1SDimitry Andric const InputSection *isec, const Reloc &r) { 36fe6060f1SDimitry Andric const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type); 37fe6060f1SDimitry Andric bool valid = true; 3881ad6265SDimitry Andric auto message = [&](const Twine &diagnostic) { 39fe6060f1SDimitry Andric valid = false; 4081ad6265SDimitry Andric return (isec->getLocation(r.offset) + ": " + relocAttrs.name + 4181ad6265SDimitry Andric " relocation " + diagnostic) 42fe6060f1SDimitry Andric .str(); 43fe6060f1SDimitry Andric }; 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric if (relocAttrs.hasAttr(RelocAttrBits::TLV) != sym->isTlv()) 4681ad6265SDimitry Andric error(message(Twine("requires that symbol ") + sym->getName() + " " + 47fe6060f1SDimitry Andric (sym->isTlv() ? "not " : "") + "be thread-local")); 48fe6060f1SDimitry Andric 49fe6060f1SDimitry Andric return valid; 50fe6060f1SDimitry Andric } 51fe6060f1SDimitry Andric 5281ad6265SDimitry Andric // Given an offset in the output buffer, figure out which ConcatInputSection (if 5381ad6265SDimitry Andric // any) maps to it. At the same time, update the offset such that it is relative 5481ad6265SDimitry Andric // to the InputSection rather than to the output buffer. 5581ad6265SDimitry Andric // 5681ad6265SDimitry Andric // Obtaining the InputSection allows us to have better error diagnostics. 5781ad6265SDimitry Andric // However, many of our relocation-handling methods do not take the InputSection 5881ad6265SDimitry Andric // as a parameter. Since we are already passing the buffer offsets to our Target 5981ad6265SDimitry Andric // methods, this function allows us to emit better errors without threading an 6081ad6265SDimitry Andric // additional InputSection argument through the call stack. 6181ad6265SDimitry Andric // 6281ad6265SDimitry Andric // This is implemented as a slow linear search through OutputSegments, 6381ad6265SDimitry Andric // OutputSections, and finally the InputSections themselves. However, this 6481ad6265SDimitry Andric // function should be called only on error paths, so some overhead is fine. 65bdd1243dSDimitry Andric InputSection *macho::offsetToInputSection(uint64_t *off) { 6681ad6265SDimitry Andric for (OutputSegment *seg : outputSegments) { 6781ad6265SDimitry Andric if (*off < seg->fileOff || *off >= seg->fileOff + seg->fileSize) 6881ad6265SDimitry Andric continue; 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric const std::vector<OutputSection *> §ions = seg->getSections(); 7181ad6265SDimitry Andric size_t osecIdx = 0; 7281ad6265SDimitry Andric for (; osecIdx < sections.size(); ++osecIdx) 7381ad6265SDimitry Andric if (*off < sections[osecIdx]->fileOff) 7481ad6265SDimitry Andric break; 7581ad6265SDimitry Andric assert(osecIdx > 0); 7681ad6265SDimitry Andric // We should be only calling this function on offsets that belong to 7781ad6265SDimitry Andric // ConcatOutputSections. 7881ad6265SDimitry Andric auto *osec = cast<ConcatOutputSection>(sections[osecIdx - 1]); 7981ad6265SDimitry Andric *off -= osec->fileOff; 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric size_t isecIdx = 0; 8281ad6265SDimitry Andric for (; isecIdx < osec->inputs.size(); ++isecIdx) { 8381ad6265SDimitry Andric const ConcatInputSection *isec = osec->inputs[isecIdx]; 8481ad6265SDimitry Andric if (*off < isec->outSecOff) 8581ad6265SDimitry Andric break; 8681ad6265SDimitry Andric } 8781ad6265SDimitry Andric assert(isecIdx > 0); 8881ad6265SDimitry Andric ConcatInputSection *isec = osec->inputs[isecIdx - 1]; 8981ad6265SDimitry Andric *off -= isec->outSecOff; 9081ad6265SDimitry Andric return isec; 9181ad6265SDimitry Andric } 9281ad6265SDimitry Andric return nullptr; 9381ad6265SDimitry Andric } 9481ad6265SDimitry Andric 9581ad6265SDimitry Andric void macho::reportRangeError(void *loc, const Reloc &r, const Twine &v, 9681ad6265SDimitry Andric uint8_t bits, int64_t min, uint64_t max) { 97fe6060f1SDimitry Andric std::string hint; 9881ad6265SDimitry Andric uint64_t off = reinterpret_cast<const uint8_t *>(loc) - in.bufferStart; 9981ad6265SDimitry Andric const InputSection *isec = offsetToInputSection(&off); 10081ad6265SDimitry Andric std::string locStr = isec ? isec->getLocation(off) : "(invalid location)"; 101fe6060f1SDimitry Andric if (auto *sym = r.referent.dyn_cast<Symbol *>()) 102fe6060f1SDimitry Andric hint = "; references " + toString(*sym); 10381ad6265SDimitry Andric error(locStr + ": relocation " + target->getRelocAttrs(r.type).name + 104fe6060f1SDimitry Andric " is out of range: " + v + " is not in [" + Twine(min) + ", " + 105fe6060f1SDimitry Andric Twine(max) + "]" + hint); 106fe6060f1SDimitry Andric } 107fe6060f1SDimitry Andric 10881ad6265SDimitry Andric void macho::reportRangeError(void *loc, SymbolDiagnostic d, const Twine &v, 10981ad6265SDimitry Andric uint8_t bits, int64_t min, uint64_t max) { 11081ad6265SDimitry Andric // FIXME: should we use `loc` somehow to provide a better error message? 111fe6060f1SDimitry Andric std::string hint; 112fe6060f1SDimitry Andric if (d.symbol) 113fe6060f1SDimitry Andric hint = "; references " + toString(*d.symbol); 114fe6060f1SDimitry Andric error(d.reason + " is out of range: " + v + " is not in [" + Twine(min) + 115fe6060f1SDimitry Andric ", " + Twine(max) + "]" + hint); 116fe6060f1SDimitry Andric } 117fe6060f1SDimitry Andric 118fe6060f1SDimitry Andric const RelocAttrs macho::invalidRelocAttrs{"INVALID", RelocAttrBits::_0}; 119