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 @@ -49,7 +49,7 @@ #define B(x) RelocAttrBits::x {"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4) | B(BYTE8)}, - {"SUBTRACTOR", B(SUBTRAHEND) | B(BYTE4) | B(BYTE8)}, + {"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)}, {"BRANCH26", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)}, {"PAGE21", B(PCREL) | B(EXTERN) | B(BYTE4)}, {"PAGEOFF12", B(ABSOLUTE) | B(EXTERN) | B(BYTE4)}, diff --git a/lld/MachO/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp --- a/lld/MachO/Arch/ARM64Common.cpp +++ b/lld/MachO/Arch/ARM64Common.cpp @@ -47,7 +47,6 @@ void ARM64Common::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value, uint64_t pc) const { uint32_t base = ((r.length == 2) ? read32le(loc) : 0); - value += r.addend; switch (r.type) { case ARM64_RELOC_BRANCH26: value = encodeBranch26(r, base, value - pc); diff --git a/lld/MachO/Arch/ARM64_32.cpp b/lld/MachO/Arch/ARM64_32.cpp --- a/lld/MachO/Arch/ARM64_32.cpp +++ b/lld/MachO/Arch/ARM64_32.cpp @@ -44,7 +44,7 @@ static const std::array relocAttrsArray{{ #define B(x) RelocAttrBits::x {"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4)}, - {"SUBTRACTOR", B(SUBTRAHEND) | B(BYTE4)}, + {"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4)}, {"BRANCH26", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)}, {"PAGE21", B(PCREL) | B(EXTERN) | B(BYTE4)}, {"PAGEOFF12", B(ABSOLUTE) | B(EXTERN) | B(BYTE4)}, diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -51,7 +51,7 @@ {"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)}, {"GOT_LOAD", B(PCREL) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)}, {"GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)}, - {"SUBTRACTOR", B(SUBTRAHEND) | B(BYTE4) | B(BYTE8)}, + {"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)}, {"SIGNED_1", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)}, {"SIGNED_2", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)}, {"SIGNED_4", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)}, @@ -94,7 +94,6 @@ void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value, uint64_t relocVA) const { - value += r.addend; if (r.pcrel) { uint64_t pc = relocVA + 4 + pcrelOffset(r.type); value -= pc; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -280,6 +280,8 @@ if (relInfo.r_address & R_SCATTERED) fatal("TODO: Scattered relocations not supported"); + bool isSubtrahend = + target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND); int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec.offset, relInfo); assert(!(embeddedAddend && pairedAddend)); int64_t totalAddend = pairedAddend + embeddedAddend; @@ -290,9 +292,9 @@ r.offset = relInfo.r_address; if (relInfo.r_extern) { r.referent = symbols[relInfo.r_symbolnum]; - r.addend = totalAddend; + r.addend = isSubtrahend ? 0 : totalAddend; } else { - SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1]; + assert(!isSubtrahend); const Section &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; uint64_t referentOffset; if (relInfo.r_pcrel) { @@ -309,6 +311,7 @@ // The addend for a non-pcrel relocation is its absolute address. referentOffset = totalAddend - referentSec.addr; } + SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1]; r.referent = findContainingSubsection(referentSubsecMap, &referentOffset); r.addend = referentOffset; } @@ -316,15 +319,26 @@ InputSection *subsec = findContainingSubsection(subsecMap, &r.offset); subsec->relocs.push_back(r); - if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) { + if (isSubtrahend) { relInfo = relInfos[++i]; // SUBTRACTOR relocations should always be followed by an UNSIGNED one - // indicating the minuend symbol. + // relocating the same address; that indicates the minuend. assert(target->hasAttr(relInfo.r_type, RelocAttrBits::UNSIGNED) && - relInfo.r_extern); + relInfo.r_address == r.offset); Reloc p; p.type = relInfo.r_type; - p.referent = symbols[relInfo.r_symbolnum]; + if (relInfo.r_extern) { + p.referent = symbols[relInfo.r_symbolnum]; + p.addend = totalAddend; + } else { + const Section &referentSec = sectionHeaders[relInfo.r_symbolnum - 1]; + assert(!relInfo.r_pcrel); + uint64_t referentOffset = totalAddend - referentSec.addr; + SubsectionMap &referentSubsecMap = subsections[relInfo.r_symbolnum - 1]; + p.referent = + findContainingSubsection(referentSubsecMap, &referentOffset); + p.addend = referentOffset; + } subsec->relocs.push_back(p); } } diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -62,8 +62,13 @@ uint64_t referentVA = 0; if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) { const Symbol *fromSym = r.referent.get(); - const Symbol *toSym = relocs[++i].referent.get(); - referentVA = toSym->getVA() - fromSym->getVA(); + const Reloc &minuend = relocs[++i]; + uint64_t minuendVA; + if (const Symbol *toSym = minuend.referent.dyn_cast()) + minuendVA = toSym->getVA(); + else + minuendVA = minuend.referent.get()->getVA(); + referentVA = minuendVA - fromSym->getVA() + minuend.addend; } else if (auto *referentSym = r.referent.dyn_cast()) { if (target->hasAttr(r.type, RelocAttrBits::LOAD) && !referentSym->isInGot()) @@ -81,7 +86,7 @@ } else if (auto *referentIsec = r.referent.dyn_cast()) { referentVA = referentIsec->getVA(); } - target->relocateOne(loc, r, referentVA, getVA() + r.offset); + target->relocateOne(loc, r, referentVA + r.addend, getVA() + r.offset); } } 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 @@ -1,37 +1,47 @@ # REQUIRES: x86, aarch64 -# RUN: rm -rf %t; mkdir %t -# 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: rm -rf %t; split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/x86_64.o +# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/test.s -o %t/arm64.o +# RUN: %lld -lSystem %t/x86_64.o -o %t/x86_64 -order_file %t/order-file # RUN: llvm-objdump --syms --full-contents --rebase %t/x86_64 | FileCheck %s -# RUN: %lld -arch arm64 -lSystem %t/arm64.o -o %t/arm64 +# RUN: %lld -arch arm64 -lSystem %t/arm64.o -o %t/arm64 -order_file %t/order-file # RUN: llvm-objdump --syms --full-contents --rebase %t/arm64 | FileCheck %s # CHECK-LABEL: SYMBOL TABLE: -# CHECK: {{0*}}[[#%x, SUB1ADDR:]] l {{.*}} __DATA,__data _sub1 -# CHECK: {{0*}}[[#%x, SUB2ADDR:]] l {{.*}} __DATA,__data _sub2 -# CHECK: {{0*}}[[#%x, SUB3ADDR:]] l {{.*}} __DATA,__data _sub3 -# CHECK: {{0*}}[[#%x, SUB4ADDR:]] l {{.*}} __DATA,__data _sub4 -# CHECK-LABEL: Contents of section __DATA,__data: +# CHECK: {{0*}}[[#%x, SUB1ADDR:]] l {{.*}} __DATA,bar _sub1 +# CHECK: {{0*}}[[#%x, SUB2ADDR:]] l {{.*}} __DATA,bar _sub2 +# CHECK: {{0*}}[[#%x, SUB3ADDR:]] l {{.*}} __DATA,bar _sub3 +# CHECK: {{0*}}[[#%x, SUB4ADDR:]] l {{.*}} __DATA,bar _sub4 +# CHECK: {{0*}}[[#%x, SUB5ADDR:]] l {{.*}} __DATA,bar _sub5 +# CHECK-LABEL: Contents of section __DATA,bar: # CHECK: [[#SUB1ADDR]] 10000000 # CHECK-NEXT: [[#SUB2ADDR]] f2ffffff # CHECK-NEXT: [[#SUB3ADDR]] 14000000 00000000 # CHECK-NEXT: [[#SUB4ADDR]] f6ffffff ffffffff +# CHECK-NEXT: [[#SUB5ADDR]] f1ffffff ffffffff # CHECK: Rebase table: # CHECK-NEXT: segment section address type # CHECK-EMPTY: +#--- test.s + .globl _main, _subtrahend_1, _subtrahend_2, _minuend1, _minuend2 -.data -_subtrahend_1: +.section __DATA,foo + .space 16 +L_.minuend: .space 16 + +.section __DATA,bar _minuend_1: .space 16 _minuend_2: .space 16 +_subtrahend_1: + .space 16 _subtrahend_2: .space 16 + _sub1: .long _minuend_1 - _subtrahend_1 .space 12 @@ -43,8 +53,22 @@ .space 8 _sub4: .quad _minuend_2 - _subtrahend_2 + 6 + .space 8 +_sub5: + .quad L_.minuend - _subtrahend_1 + 1 + .space 8 .text .p2align 2 _main: ret + +.subsections_via_symbols + +#--- order-file +## Reorder the symbols to make sure that the addends are being associated with +## the minuend (and not the subtrahend) relocation. +_subtrahend_1 +_minuend_1 +_minuend_2 +_subtrahend_2