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 @@ -47,7 +47,6 @@ // Random notes on reloc types: // ADDEND always pairs with BRANCH26, PAGE21, or PAGEOFF12 -// SUBTRACTOR always pairs with UNSIGNED (a delta between two sections) // POINTER_TO_GOT: ld64 supports a 4-byte pc-relative form as well as an 8-byte // absolute version of this relocation. The semantics of the absolute relocation // are weird -- it results in the value of the GOT slot being written, instead diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -287,6 +287,10 @@ p.type = relInfo.r_type; p.referent = symbols[relInfo.r_symbolnum]; relInfo = relInfos[++i]; + // SUBTRACTOR relocations should always be followed by an UNSIGNED one + // indicating the minuend symbol. + assert(target->hasAttr(relInfo.r_type, RelocAttrBits::UNSIGNED) && + relInfo.r_extern); } Reloc r; r.type = relInfo.r_type; @@ -317,8 +321,7 @@ } InputSection *subsec = findContainingSubsection(subsecMap, &r.offset); - if (p.type != GENERIC_RELOC_INVALID && - target->hasAttr(p.type, RelocAttrBits::SUBTRAHEND)) + if (p.type != GENERIC_RELOC_INVALID) subsec->relocs.push_back(p); subsec->relocs.push_back(r); } diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -59,13 +59,13 @@ for (size_t i = 0; i < relocs.size(); i++) { auto *fromSym = target->hasAttr(relocs[i].type, RelocAttrBits::SUBTRAHEND) - ? relocs[i++].referent.dyn_cast() + ? relocs[i++].referent.get() : nullptr; const Reloc &r = relocs[i]; uint8_t *loc = buf + r.offset; uint64_t referentVA = 0; if (fromSym) { - auto *toSym = r.referent.dyn_cast(); + auto *toSym = r.referent.get(); referentVA = toSym->getVA() - fromSym->getVA(); } else if (auto *referentSym = r.referent.dyn_cast()) { if (target->hasAttr(r.type, RelocAttrBits::LOAD) && diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h --- a/lld/MachO/Target.h +++ b/lld/MachO/Target.h @@ -52,6 +52,7 @@ 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: diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -449,9 +449,16 @@ continue; } - for (Reloc &r : isec->relocs) { - if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) + for (auto it = isec->relocs.begin(); it != isec->relocs.end(); ++it) { + Reloc &r = *it; + if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) { + // Skip over the following UNSIGNED relocation -- it's just there as the + // minuend, and doesn't have the usual UNSIGNED semantics. We don't want + // to emit rebase opcodes for it. + it = std::next(it); + assert(isa(it->referent.dyn_cast())); continue; + } if (auto *sym = r.referent.dyn_cast()) { if (auto *undefined = dyn_cast(sym)) treatUndefinedSymbol(*undefined); diff --git a/lld/test/MachO/reloc-subtractor.s b/lld/test/MachO/reloc-subtractor.s --- a/lld/test/MachO/reloc-subtractor.s +++ b/lld/test/MachO/reloc-subtractor.s @@ -3,9 +3,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/x86_64.o # RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t/arm64.o # RUN: %lld -lSystem %t/x86_64.o -o %t/x86_64 -# RUN: llvm-objdump --syms --full-contents %t/x86_64 | FileCheck %s +# RUN: llvm-objdump --syms --full-contents --rebase %t/x86_64 | FileCheck %s # RUN: %lld -arch arm64 -lSystem %t/arm64.o -o %t/arm64 -# RUN: llvm-objdump --syms --full-contents %t/arm64 | FileCheck %s +# RUN: llvm-objdump --syms --full-contents --rebase %t/arm64 | FileCheck %s # CHECK-LABEL: SYMBOL TABLE: # CHECK: {{0*}}[[#%x, SUB1ADDR:]] l {{.*}} __DATA,__data _sub1 @@ -17,6 +17,9 @@ # CHECK-NEXT: [[#SUB2ADDR]] f0ffffff # CHECK-NEXT: [[#SUB3ADDR]] 10000000 00000000 # CHECK-NEXT: [[#SUB4ADDR]] f0ffffff ffffffff +# CHECK: Rebase table: +# CHECK-NEXT: segment section address type +# CHECK-EMPTY: .globl _main, _subtrahend_1, _subtrahend_2, _minued1, _minued2