[lld] 198b0c5 - [lld-macho] Support pc-relative section relocations

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Sat May 9 20:58:24 PDT 2020


Author: Jez Ng
Date: 2020-05-09T20:56:23-07:00
New Revision: 198b0c57dffbca309dd5acaebe58300203f4c12d

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

LOG: [lld-macho] Support pc-relative section relocations

Summary: So far we've only supported symbol relocations.

Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee

Subscribers: llvm-commits

Tags: #llvm

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

Added: 
    

Modified: 
    lld/MachO/InputFiles.cpp
    lld/MachO/InputSection.cpp
    lld/MachO/InputSection.h
    lld/test/MachO/relocations.s
    lld/test/MachO/x86-64-reloc-signed.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index f8fdd76ff50f..e836f4d79962 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -134,6 +134,7 @@ InputFile::parseSections(ArrayRef<section_64> sections) {
   for (const section_64 &sec : sections) {
     InputSection *isec = make<InputSection>();
     isec->file = this;
+    isec->header = &sec;
     isec->name = StringRef(sec.sectname, strnlen(sec.sectname, 16));
     isec->segname = StringRef(sec.segname, strnlen(sec.segname, 16));
     isec->data = {buf + sec.offset, static_cast<size_t>(sec.size)};
@@ -165,11 +166,14 @@ void InputFile::parseRelocations(const section_64 &sec,
       r.type = rel.r_type;
       r.offset = rel.r_address;
       r.addend = target->getImplicitAddend(buf + sec.offset + r.offset, r.type);
-      if (rel.r_extern)
+      if (rel.r_extern) {
         r.target = symbols[rel.r_symbolnum];
-      else {
-        error("TODO: Non-extern relocations are not supported");
-        continue;
+      } else {
+        if (rel.r_symbolnum == 0 || rel.r_symbolnum > sections.size())
+          fatal("invalid section index in relocation for offset " +
+                std::to_string(r.offset) + " in section " + sec.sectname +
+                " of " + getName());
+        r.target = sections[rel.r_symbolnum - 1];
       }
     }
     relocs.push_back(r);

diff  --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index cfc6050cb90c..ace30c8c41dc 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -32,6 +32,7 @@ void InputSection::writeTo(uint8_t *buf) {
 
   for (Reloc &r : relocs) {
     uint64_t va = 0;
+    uint64_t addend = r.addend;
     if (auto *s = r.target.dyn_cast<Symbol *>()) {
       if (auto *dylibSymbol = dyn_cast<DylibSymbol>(s)) {
         va = target->getDylibSymbolVA(*dylibSymbol, r.type);
@@ -40,11 +41,15 @@ void InputSection::writeTo(uint8_t *buf) {
       }
     } else if (auto *isec = r.target.dyn_cast<InputSection *>()) {
       va = isec->getVA();
-    } else {
-      llvm_unreachable("Unknown relocation target");
+      // 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 target section.
+      // TODO: Figure out what to do for non-pcrel section relocations.
+      // TODO: The offset of 4 is probably not right for ARM64.
+      addend -= isec->header->addr - (header->addr + r.offset + 4);
     }
 
-    uint64_t val = va + r.addend;
+    uint64_t val = va + addend;
     if (1) // TODO: handle non-pcrel relocations
       val -= getVA() + r.offset;
     target->relocateOne(buf + r.offset, r.type, val);

diff  --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h
index a945b79ad3a0..908f09e6d29d 100644
--- a/lld/MachO/InputSection.h
+++ b/lld/MachO/InputSection.h
@@ -42,6 +42,8 @@ class InputSection {
   InputFile *file = nullptr;
   StringRef name;
   StringRef segname;
+  // This provides access to the address of the section in the input file.
+  const llvm::MachO::section_64 *header;
 
   OutputSection *parent = nullptr;
   uint64_t outSecOff = 0;

diff  --git a/lld/test/MachO/relocations.s b/lld/test/MachO/relocations.s
index 7f41a6c93283..b1c828d4d469 100644
--- a/lld/test/MachO/relocations.s
+++ b/lld/test/MachO/relocations.s
@@ -12,9 +12,12 @@
 # CHECK-LABEL: <_main>:
 ## Test X86_64_RELOC_BRANCH
 # CHECK:       callq 0x[[#%x, F_ADDR]] <_f>
-## Test X86_64_RELOC_SIGNED
+## Test extern (symbol) X86_64_RELOC_SIGNED
 # CHECK:       leaq [[#%u, STR_OFF:]](%rip), %rsi
 # CHECK-NEXT:  [[#%x, CSTRING_ADDR - STR_OFF]]
+## Test non-extern (section) X86_64_RELOC_SIGNED
+# CHECK:       leaq [[#%u, LSTR_OFF:]](%rip), %rsi
+# CHECK-NEXT:  [[#%x, CSTRING_ADDR + 22 - LSTR_OFF]]
 
 .section __TEXT,__text
 .globl _main, _f
@@ -26,11 +29,21 @@ _main:
 _f:
   movl $0x2000004, %eax # write() syscall
   mov $1, %rdi # stdout
-  leaq str(%rip), %rsi
-  mov $13, %rdx # length of str
+  leaq _str(%rip), %rsi
+  mov $21, %rdx # length of str
+  syscall
+
+  movl $0x2000004, %eax # write() syscall
+  mov $1, %rdi # stdout
+  leaq L_.str(%rip), %rsi
+  mov $15, %rdx # length of str
   syscall
   ret
 
 .section __TEXT,__cstring
-str:
-  .asciz "Hello world!\n"
+## References to this generate a symbol relocation
+_str:
+  .asciz "Local defined symbol\n"
+## References to this generate a section relocation
+L_.str:
+  .asciz "Private symbol\n"

diff  --git a/lld/test/MachO/x86-64-reloc-signed.s b/lld/test/MachO/x86-64-reloc-signed.s
index 9ff91567d764..079ea7d1e96f 100644
--- a/lld/test/MachO/x86-64-reloc-signed.s
+++ b/lld/test/MachO/x86-64-reloc-signed.s
@@ -1,7 +1,7 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
 # RUN: lld -flavor darwinnew -o %t %t.o
-# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: llvm-objdump -D %t | FileCheck %s
 
 # CHECK:      <_main>:
 # CHECK-NEXT:   movl {{.*}}  # 2000 <_s>
@@ -10,10 +10,18 @@
 # CHECK-NEXT:   callq {{.*}}
 # CHECK-NEXT:   movb {{.*}}  # 2000 <_s>
 # CHECK-NEXT:   callq {{.*}}
+# CHECK:      <__not_text>:
+# CHECK-NEXT:   movl {{.*}}  # 2005
+# CHECK-NEXT:   callq {{.*}}
+# CHECK-NEXT:   movl {{.*}}  # 2007
+# CHECK-NEXT:   callq {{.*}}
+# CHECK-NEXT:   movb {{.*}}  # 2005
+# CHECK-NEXT:   callq {{.*}}
 
 .section __TEXT,__text
 .globl _main
 _main:
+  ## Symbol relocations
   movl $0x434241, _s(%rip)  # X86_64_RELOC_SIGNED_4
   callq _f
   movl $0x44, _s+2(%rip)    # X86_64_RELOC_SIGNED_2
@@ -31,7 +39,26 @@ _f:
   syscall
   ret
 
+.section __TEXT,__not_text
+  ## Section relocations. We intentionally put them in a separate section since
+  ## the __text section typically starts at an address of zero in object files,
+  ## and so does not fully exercise the relocation logic.
+  movl $0x434241, L._s(%rip)  # X86_64_RELOC_SIGNED_4
+  callq _f
+  movl $0x44, L._s+2(%rip)    # X86_64_RELOC_SIGNED_2
+  callq _f
+  movb $0x45, L._s(%rip)      # X86_64_RELOC_SIGNED_1
+  callq _f
+  ret
+
 .section __DATA,__data
 .globl _s
 _s:
   .space 5
+
+## Create a new section to force the assembler to use a section relocation for
+## the private symbol L._s. Otherwise, it will instead use a nearby non-private
+## symbol to create a symbol relocation plus an addend.
+.section __DATA,__foo
+L._s:
+  .space 5


        


More information about the llvm-commits mailing list