diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -996,8 +996,8 @@ cast(r.referent.dyn_cast()); } if (referentIsec->getSegName() != segment_names::text) - error("compact unwind references address in " + toString(referentIsec) + - " which is not in segment __TEXT"); + error(isec->getLocation(r.offset) + " references section " + + referentIsec->getName() + " which is not in segment __TEXT"); // The functionAddress relocations are typically section relocations. // However, unwind info operates on a per-symbol basis, so we search for // the function symbol here. diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -49,6 +49,8 @@ virtual uint64_t getOffset(uint64_t off) const = 0; // The offset from the beginning of the file. uint64_t getVA(uint64_t off) const; + // Return a user-friendly string for use in diagnostics. + std::string getLocation(uint64_t off) const; // Whether the data at \p off in this InputSection is live. virtual bool isLive(uint64_t off) const = 0; virtual void markLive(uint64_t off) = 0; diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -55,6 +55,28 @@ return sym->getVA(); } +std::string InputSection::getLocation(uint64_t off) const { + // First, try to find a symbol that's near the offset. Use it as a reference + // point. + for (size_t i = 0; i < symbols.size(); ++i) + if (symbols[i]->value <= off && + (i + 1 == symbols.size() || symbols[i + 1]->value > off)) + return (toString(getFile()) + ":(symbol " + symbols.front()->getName() + + "+0x" + Twine::utohexstr(off - symbols[i]->value) + ")") + .str(); + + // If that fails, use the section itself as a reference point. + for (const Subsection &subsec : section.subsections) { + if (subsec.isec == this) { + off += subsec.offset; + break; + } + } + return (toString(getFile()) + ":(" + getName() + "+0x" + + Twine::utohexstr(off) + ")") + .str(); +} + // ICF needs to hash any section that might potentially be duplicated so // that it can match on content rather than identity. bool ConcatInputSection::isHashableForICF() const { @@ -195,7 +217,7 @@ while (!s.empty()) { size_t end = s.find(0); if (end == StringRef::npos) - fatal(toString(this) + ": string is not null terminated"); + fatal(getLocation(off) + ": string is not null terminated"); size_t size = end + 1; uint32_t hash = config->dedupLiterals ? xxHash64(s.substr(0, size)) : 0; pieces.emplace_back(off, hash); diff --git a/lld/MachO/Relocations.cpp b/lld/MachO/Relocations.cpp --- a/lld/MachO/Relocations.cpp +++ b/lld/MachO/Relocations.cpp @@ -24,15 +24,15 @@ 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) { + auto message = [&](const Twine &diagnostic) { valid = false; - return (relocAttrs.name + " relocation " + diagnostic + " for `" + - sym->getName() + "' in " + toString(isec)) + return (isec->getLocation(r.offset) + ": " + relocAttrs.name + + " relocation " + diagnostic) .str(); }; if (relocAttrs.hasAttr(RelocAttrBits::TLV) != sym->isTlv()) - error(message(Twine("requires that variable ") + + error(message(Twine("requires that symbol ") + sym->getName() + " " + (sym->isTlv() ? "not " : "") + "be thread-local")); return valid; diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -279,11 +279,12 @@ // finalization of __DATA. Moreover, the finalization of unwind info depends on // the exact addresses that it references. So it is safe for compact unwind to // reference addresses in __TEXT, but not addresses in any other segment. -static ConcatInputSection *checkTextSegment(InputSection *isec) { +static ConcatInputSection * +checkTextSegment(InputSection *isec, InputSection *cuIsec, uint64_t off) { if (isec->getSegName() != segment_names::text) - error("compact unwind references address in " + toString(isec) + + error(cuIsec->getLocation(off) + " references section " + isec->getName() + " which is not in segment __TEXT"); - // __text should always be a ConcatInputSection. + // __TEXT should always contain ConcatInputSections. return cast(isec); } @@ -311,7 +312,7 @@ if (auto *referentSym = r.referent.dyn_cast()) { if (!isa(referentSym)) { if (auto *defined = dyn_cast(referentSym)) - checkTextSegment(defined->isec); + checkTextSegment(defined->isec, d->unwindEntry, r.offset); // At this point in the link, we may not yet know the final address of // the GOT, so we just encode the index. We make it a 1-based index so // that we can distinguish the null pointer case. @@ -319,7 +320,7 @@ } } else { auto *referentIsec = r.referent.get(); - checkTextSegment(referentIsec); + checkTextSegment(referentIsec, d->unwindEntry, r.offset); referentVA = referentIsec->getVA(r.addend); } writeAddress(buf + r.offset, referentVA, r.length); diff --git a/lld/test/MachO/invalid/bad-got-to-dylib-tlv-reference.s b/lld/test/MachO/invalid/bad-got-to-dylib-tlv-reference.s --- a/lld/test/MachO/invalid/bad-got-to-dylib-tlv-reference.s +++ b/lld/test/MachO/invalid/bad-got-to-dylib-tlv-reference.s @@ -8,7 +8,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o # RUN: not %lld -lSystem -L%t -ltlv -o /dev/null %t/test.o 2>&1 | FileCheck %s -DFILE=%t/test.o -# CHECK: error: GOT_LOAD relocation requires that variable not be thread-local for `_foo' in [[FILE]]:(__text) +# CHECK: error: [[FILE]]:(symbol _main+0x3): GOT_LOAD relocation requires that symbol _foo not be thread-local #--- libtlv.s .section __DATA,__thread_vars,thread_local_variables diff --git a/lld/test/MachO/invalid/bad-got-to-tlv-reference.s b/lld/test/MachO/invalid/bad-got-to-tlv-reference.s --- a/lld/test/MachO/invalid/bad-got-to-tlv-reference.s +++ b/lld/test/MachO/invalid/bad-got-to-tlv-reference.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o # RUN: not %lld -o /dev/null %t.o 2>&1 | FileCheck %s -DFILE=%t.o -# CHECK: error: GOT_LOAD relocation requires that variable not be thread-local for `_foo' in [[FILE]]:(__text) +# CHECK: error: [[FILE]]:(symbol _main+0x3): GOT_LOAD relocation requires that symbol _foo not be thread-local .text .globl _main diff --git a/lld/test/MachO/invalid/bad-tlv-relocation.s b/lld/test/MachO/invalid/bad-tlv-relocation.s --- a/lld/test/MachO/invalid/bad-tlv-relocation.s +++ b/lld/test/MachO/invalid/bad-tlv-relocation.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o # RUN: not %lld -o /dev/null %t.o 2>&1 | FileCheck %s -DFILE=%t.o -# CHECK: TLV relocation requires that variable be thread-local for `_foo' in [[FILE]]:(__text) +# CHECK: [[FILE]]:(symbol _main+0x3): TLV relocation requires that symbol _foo be thread-local .text .globl _main diff --git a/lld/test/MachO/invalid/compact-unwind-bad-reloc.s b/lld/test/MachO/invalid/compact-unwind-bad-reloc.s --- a/lld/test/MachO/invalid/compact-unwind-bad-reloc.s +++ b/lld/test/MachO/invalid/compact-unwind-bad-reloc.s @@ -2,9 +2,9 @@ # RUN: rm -rf %t; split-file %s %t # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/bad-function.s -o %t/bad-function.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/bad-personality.s -o %t/bad-personality.o -# RUN: not %lld -lSystem -lc++ %t/bad-function.o -o %t 2>&1 | FileCheck %s -DFILE=%t/bad-function.o -# RUN: not %lld -lSystem -lc++ %t/bad-personality.o -o %t 2>&1 | FileCheck %s -DFILE=%t/bad-personality.o -# CHECK: error: compact unwind references address in [[FILE]]:(__data) which is not in segment __TEXT +# RUN: not %lld -lSystem -lc++ %t/bad-function.o -o %t 2>&1 | FileCheck %s -DFILE=%t/bad-function.o -D#OFF=0x0 +# RUN: not %lld -lSystem -lc++ %t/bad-personality.o -o %t 2>&1 | FileCheck %s -DFILE=%t/bad-personality.o -D#OFF=0x10 +# CHECK: error: [[FILE]]:(__compact_unwind+0x[[#%x,OFF]]) references section __data which is not in segment __TEXT #--- bad-function.s .data diff --git a/lld/test/MachO/invalid/cstring-dedup.s b/lld/test/MachO/invalid/cstring-dedup.s --- a/lld/test/MachO/invalid/cstring-dedup.s +++ b/lld/test/MachO/invalid/cstring-dedup.s @@ -10,7 +10,7 @@ # RUN: not %lld -dylib --deduplicate-literals %t/not-terminated.o 2>&1 | FileCheck %s --check-prefix=TERM # RUN: not %lld -dylib --deduplicate-literals %t/relocs.o 2>&1 | FileCheck %s --check-prefix=RELOCS -# TERM: not-terminated.o:(__cstring): string is not null terminated +# TERM: not-terminated.o:(__cstring+0x4): string is not null terminated # RELOCS: relocs.o contains relocations in __TEXT,__cstring, so LLD cannot deduplicate literals. Try re-running without --deduplicate-literals. #--- not-terminated.s