[lld] 1aa29df - [lld-macho] Support subtractor relocations that reference sections

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 20 13:59:08 PDT 2021


Author: Jez Ng
Date: 2021-04-20T16:58:57-04:00
New Revision: 1aa29dffceff63c7f2bdecc03ec9c0922a100082

URL: https://github.com/llvm/llvm-project/commit/1aa29dffceff63c7f2bdecc03ec9c0922a100082
DIFF: https://github.com/llvm/llvm-project/commit/1aa29dffceff63c7f2bdecc03ec9c0922a100082.diff

LOG: [lld-macho] Support subtractor relocations that reference sections

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

Added: 
    

Modified: 
    lld/MachO/Arch/ARM64.cpp
    lld/MachO/Arch/ARM64Common.cpp
    lld/MachO/Arch/ARM64_32.cpp
    lld/MachO/Arch/X86_64.cpp
    lld/MachO/InputFiles.cpp
    lld/MachO/InputSection.cpp
    lld/MachO/Writer.cpp
    lld/test/MachO/reloc-subtractor.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp
index 708b12b92859c..90f7e174f61e9 100644
--- a/lld/MachO/Arch/ARM64.cpp
+++ b/lld/MachO/Arch/ARM64.cpp
@@ -49,7 +49,7 @@ const RelocAttrs &ARM64::getRelocAttrs(uint8_t type) const {
 #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
index 88e7286d14503..67e7292fd6fdb 100644
--- a/lld/MachO/Arch/ARM64Common.cpp
+++ b/lld/MachO/Arch/ARM64Common.cpp
@@ -47,7 +47,6 @@ int64_t ARM64Common::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
 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
index 80bd933f0728a..f7b1439b8930a 100644
--- a/lld/MachO/Arch/ARM64_32.cpp
+++ b/lld/MachO/Arch/ARM64_32.cpp
@@ -44,7 +44,7 @@ const RelocAttrs &ARM64_32::getRelocAttrs(uint8_t type) const {
   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)},

diff  --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index 0feb7bb635101..7e2155801fc2f 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -51,7 +51,7 @@ const RelocAttrs &X86_64::getRelocAttrs(uint8_t type) const {
       {"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 @@ int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
 
 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
index e2eb3379dfe01..c6bae08e86fb2 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -280,6 +280,8 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
     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 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
     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 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
         // 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 @@ void ObjFile::parseRelocations(ArrayRef<Section> sectionHeaders,
     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);
     }
   }

diff  --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index 70a3a852878c4..8d9113b2d5bfd 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -62,8 +62,13 @@ void InputSection::writeTo(uint8_t *buf) {
     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())
@@ -81,7 +86,7 @@ void InputSection::writeTo(uint8_t *buf) {
     } 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);
   }
 }
 

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 52b69fa50853e..6ba7ed0eaba9d 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -527,7 +527,6 @@ void Writer::scanRelocations() {
         // 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 *>()) {

diff  --git a/lld/test/MachO/reloc-subtractor.s b/lld/test/MachO/reloc-subtractor.s
index d426adc60bf2a..550f27d352b57 100644
--- 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 @@ _sub3:
   .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


        


More information about the llvm-commits mailing list