[lld] e8a3058 - [lld-macho] Fix handling of X86_64_RELOC_SIGNED_{1, 2, 4}

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 11 10:28:43 PST 2021


Author: Jez Ng
Date: 2021-03-11T13:28:11-05:00
New Revision: e8a30583033596b80d51dc89ad166526b5446d88

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

LOG: [lld-macho] Fix handling of X86_64_RELOC_SIGNED_{1,2,4}

The previous implementation miscalculated the addend, resulting
in an underflow. This meant that every SIGNED_N section relocation would
be associated with the last subsection (since the addend would now be a
huge number). We were "lucky" that this mistake was typically cancelled
out -- 64-to-32-bit-truncation meant that the final value was correct,
as long as subsections were not rearranged.

Reviewed By: #lld-macho, thakis

Differential Revision: https://reviews.llvm.org/D98385

Added: 
    

Modified: 
    lld/MachO/Arch/X86_64.cpp
    lld/MachO/InputFiles.cpp
    lld/MachO/Target.h
    lld/test/MachO/x86-64-reloc-signed.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index 112e2f214050..7a7ad0a7f0fc 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -28,7 +28,7 @@ struct X86_64 : TargetInfo {
   uint64_t getEmbeddedAddend(MemoryBufferRef, const section_64 &,
                              const relocation_info) const override;
   void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
-                   uint64_t pc) const override;
+                   uint64_t relocVA) const override;
 
   void writeStub(uint8_t *buf, const macho::Symbol &) const override;
   void writeStubHelperHeader(uint8_t *buf) const override;
@@ -64,6 +64,19 @@ const RelocAttrs &X86_64::getRelocAttrs(uint8_t type) const {
   return relocAttrsArray[type];
 }
 
+static int pcrelOffset(uint8_t type) {
+  switch (type) {
+  case X86_64_RELOC_SIGNED_1:
+    return 1;
+  case X86_64_RELOC_SIGNED_2:
+    return 2;
+  case X86_64_RELOC_SIGNED_4:
+    return 4;
+  default:
+    return 0;
+  }
+}
+
 uint64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, const section_64 &sec,
                                    relocation_info rel) const {
   auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
@@ -71,19 +84,22 @@ uint64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, const section_64 &sec,
 
   switch (rel.r_length) {
   case 2:
-    return read32le(loc);
+    return read32le(loc) + pcrelOffset(rel.r_type);
   case 3:
-    return read64le(loc);
+    return read64le(loc) + pcrelOffset(rel.r_type);
   default:
     llvm_unreachable("invalid r_length");
   }
 }
 
 void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
-                         uint64_t pc) const {
+                         uint64_t relocVA) const {
   value += r.addend;
-  if (r.pcrel)
-    value -= (pc + 4);
+  if (r.pcrel) {
+    uint64_t pc = relocVA + 4 + pcrelOffset(r.type);
+    value -= pc;
+  }
+
   switch (r.length) {
   case 2:
     write32le(loc, value);

diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 5ec0bf611c84..f986818d14f7 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -305,6 +305,9 @@ void ObjFile::parseRelocations(const section_64 &sec,
         // The implicit addend for pcrel section relocations is the pcrel offset
         // in terms of the addresses in the input file. Here we adjust it so
         // that it describes the offset from the start of the referent section.
+        // FIXME This logic was written around x86_64 behavior -- ARM64 doesn't
+        // have pcrel section relocations. We may want to factor this out into
+        // the arch-specific .cpp file.
         assert(target->hasAttr(r.type, RelocAttrBits::BYTE4));
         referentOffset =
             sec.addr + relInfo.r_address + 4 + totalAddend - referentSec.addr;

diff  --git a/lld/MachO/Target.h b/lld/MachO/Target.h
index 2563bc1e987d..8d98a73a6cca 100644
--- a/lld/MachO/Target.h
+++ b/lld/MachO/Target.h
@@ -43,7 +43,7 @@ class TargetInfo {
   getEmbeddedAddend(llvm::MemoryBufferRef, const llvm::MachO::section_64 &,
                     const llvm::MachO::relocation_info) const = 0;
   virtual void relocateOne(uint8_t *loc, const Reloc &, uint64_t va,
-                           uint64_t pc) const = 0;
+                           uint64_t relocVA) const = 0;
 
   // Write code for lazy binding. See the comments on StubsSection for more
   // details.

diff  --git a/lld/test/MachO/x86-64-reloc-signed.s b/lld/test/MachO/x86-64-reloc-signed.s
index b74124d43c36..74c59529b98a 100644
--- a/lld/test/MachO/x86-64-reloc-signed.s
+++ b/lld/test/MachO/x86-64-reloc-signed.s
@@ -1,21 +1,29 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
-# RUN: %lld -o %t %t.o
-# RUN: llvm-objdump -D %t | FileCheck %s
+# RUN: echo _t > %t.order
+# RUN: %lld -o %t -order_file %t.order %t.o
+# RUN: llvm-objdump --section-headers --syms -D %t | FileCheck %s
 
+# CHECK-LABEL: Sections:
+# CHECK:       __foo         {{[0-9a-f]+}}  [[#%x,FOO:]]  DATA
+
+# CHECK-LABEL: SYMBOL TABLE:
+# CHECK:       [[#%x,S:]]  g     O __DATA,__data _s
+
+# CHECK-LABEL: Disassembly of section
 # CHECK:      <_main>:
-# CHECK-NEXT:   movl {{.*}}  # 100001000 <_s>
+# CHECK-NEXT:   movl {{.*}}  # [[#S]]
 # CHECK-NEXT:   callq {{.*}}
-# CHECK-NEXT:   movl {{.*}}  # 100001002 <_s+0x2>
+# CHECK-NEXT:   movl {{.*}}  # [[#S + 2]]
 # CHECK-NEXT:   callq {{.*}}
-# CHECK-NEXT:   movb {{.*}}  # 100001000 <_s>
+# CHECK-NEXT:   movb {{.*}}  # [[#S]]
 # CHECK-NEXT:   callq {{.*}}
 # CHECK:      <__not_text>:
-# CHECK-NEXT:   movl {{.*}}  # 100001005
+# CHECK-NEXT:   movl {{.*}}  # [[#FOO + 8]]
 # CHECK-NEXT:   callq {{.*}}
-# CHECK-NEXT:   movl {{.*}}  # 100001007
+# CHECK-NEXT:   movl {{.*}}  # [[#FOO + 8 + 2]]
 # CHECK-NEXT:   callq {{.*}}
-# CHECK-NEXT:   movb {{.*}}  # 100001005
+# CHECK-NEXT:   movb {{.*}}  # [[#FOO + 8]]
 # CHECK-NEXT:   callq {{.*}}
 
 .section __TEXT,__text
@@ -61,4 +69,18 @@ _s:
 ## symbol to create a symbol relocation plus an addend.
 .section __DATA,__foo
 L._s:
-  .space 5
+  .space 1
+
+## This symbol exists in order to split __foo into two subsections, thereby
+## testing that our code matches the relocations with the right target
+## subsection. In particular, although L._s+2 points to an address within _t's
+## subsection, it's defined relative to L._s, and should therefore be associated
+## with L._s' subsection.
+##
+## We furthermore use an order file to rearrange these subsections so that a
+## mistake here will be obvious.
+.globl _t
+_t:
+  .quad 123
+
+.subsections_via_symbols


        


More information about the llvm-commits mailing list