The minuend (but not the subtrahend) can reference a section.
Note that we do not yet properly validate that the subtrahend isn't
referencing a section; I've filed PR50034 to track that.
I've also extended the reloc-subtractor.s test to reorder symbols, to
make sure that the addends are being associated with the minuend (and not
the subtrahend) relocation.
Fixes PR49999.
Reviewed By: #lld-macho, thakis
Differential Revision: https://reviews.llvm.org/D100804
#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)},
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);
static const std::array<RelocAttrs, 11> 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)},
{"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)},
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;
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;
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) {
// 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;
}
InputSection *subsec = findContainingSubsection(subsecMap, &r.offset);
subsec->relocs.push_back(r);
- if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {
- relInfo = relInfos[++i];
+ if (isSubtrahend) {
+ relocation_info minuendInfo = 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);
+ // attached to the same address.
+ assert(target->hasAttr(minuendInfo.r_type, RelocAttrBits::UNSIGNED) &&
+ relInfo.r_address == minuendInfo.r_address);
Reloc p;
- p.type = relInfo.r_type;
- p.referent = symbols[relInfo.r_symbolnum];
+ p.type = minuendInfo.r_type;
+ if (minuendInfo.r_extern) {
+ p.referent = symbols[minuendInfo.r_symbolnum];
+ p.addend = totalAddend;
+ } else {
+ uint64_t referentOffset =
+ totalAddend - sectionHeaders[minuendInfo.r_symbolnum - 1].addr;
+ SubsectionMap &referentSubsecMap =
+ subsections[minuendInfo.r_symbolnum - 1];
+ p.referent =
+ findContainingSubsection(referentSubsecMap, &referentOffset);
+ p.addend = referentOffset;
+ }
subsec->relocs.push_back(p);
}
}
uint64_t referentVA = 0;
if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {
const Symbol *fromSym = r.referent.get<Symbol *>();
- const Symbol *toSym = relocs[++i].referent.get<Symbol *>();
- referentVA = toSym->getVA() - fromSym->getVA();
+ const Reloc &minuend = relocs[++i];
+ uint64_t minuendVA;
+ if (const Symbol *toSym = minuend.referent.dyn_cast<Symbol *>())
+ minuendVA = toSym->getVA();
+ else
+ minuendVA = minuend.referent.get<InputSection *>()->getVA();
+ referentVA = minuendVA - fromSym->getVA() + minuend.addend;
} else if (auto *referentSym = r.referent.dyn_cast<Symbol *>()) {
if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&
!referentSym->isInGot())
} else if (auto *referentIsec = r.referent.dyn_cast<InputSection *>()) {
referentVA = referentIsec->getVA();
}
- target->relocateOne(loc, r, referentVA, getVA() + r.offset);
+ target->relocateOne(loc, r, referentVA + r.addend, getVA() + r.offset);
}
}
// 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<Defined>(it->referent.dyn_cast<Symbol *>()));
continue;
}
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
# 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
.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