[lld] 4645311 - [ELF] --emit-relocs: adjust offsets of .rel[a].eh_frame relocations

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 29 09:51:47 PDT 2022


Author: Fangrui Song
Date: 2022-03-29T09:51:41-07:00
New Revision: 464531193353584cef7003c11ceffee61a7dc38a

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

LOG: [ELF] --emit-relocs: adjust offsets of .rel[a].eh_frame relocations

Two code paths may reach the EHFrame case in SectionBase::getOffset:

* .eh_frame reference
* relocation copy for --emit-relocs

The first may be used by clang_rt.crtbegin.o and GCC crtbeginT.o to get the
start address of the output .eh_frame. The relocation has an offset of 0 or
(x86-64 PC-relative leaq for clang_rt.crtbegin.o) -4. The current code just
returns `offset`, which handles this case well.

The second is related to InputSection::copyRelocations on .eh_frame (used by
--emit-relocs). .eh_frame pieces may be dropped due to GC/ICF, so we should
convert the input offset to the output offset. Use the same way as
MergeInputSection with a special case handling outSecOff==-1 for an invalid
piece (see eh-frame-marker.s).

This exposes an issue in mips64-eh-abs-reloc.s that we don't reliably
handle anyway. Just add --no-check-dynamic-relocations to paper over it.

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

Added: 
    

Modified: 
    lld/ELF/InputSection.cpp
    lld/ELF/InputSection.h
    lld/test/ELF/eh-frame-merge.s
    lld/test/ELF/ehframe-relocation.s
    lld/test/ELF/mips64-eh-abs-reloc.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index d45ab9480f421..9fe9cea0426a1 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -160,11 +160,19 @@ uint64_t SectionBase::getOffset(uint64_t offset) const {
   case Regular:
   case Synthetic:
     return cast<InputSection>(this)->outSecOff + offset;
-  case EHFrame:
-    // The file crtbeginT.o has relocations pointing to the start of an empty
-    // .eh_frame that is known to be the first in the link. It does that to
-    // identify the start of the output .eh_frame.
+  case EHFrame: {
+    // Two code paths may reach here. First, clang_rt.crtbegin.o and GCC
+    // crtbeginT.o may reference the start of an empty .eh_frame to identify the
+    // start of the output .eh_frame. Just return offset.
+    //
+    // Second, InputSection::copyRelocations on .eh_frame. Some pieces may be
+    // discarded due to GC/ICF. We should compute the output section offset.
+    const EhInputSection *es = cast<EhInputSection>(this);
+    if (!es->rawData.empty())
+      if (InputSection *isec = es->getParent())
+        return isec->outSecOff + es->getParentOffset(offset);
     return offset;
+  }
   case Merge:
     const MergeInputSection *ms = cast<MergeInputSection>(this);
     if (InputSection *isec = ms->getParent())
@@ -1334,6 +1342,15 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
                 getObjMsg(d.data() - rawData.data()));
 }
 
+// Return the offset in an output section for a given input offset.
+uint64_t EhInputSection::getParentOffset(uint64_t offset) const {
+  const EhSectionPiece &piece = partition_point(
+      pieces, [=](EhSectionPiece p) { return p.inputOff <= offset; })[-1];
+  if (piece.outputOff == -1) // invalid piece
+    return offset - piece.inputOff;
+  return piece.outputOff + (offset - piece.inputOff);
+}
+
 static size_t findNull(StringRef s, size_t entSize) {
   for (unsigned i = 0, n = s.size(); i != n; i += entSize) {
     const char *b = s.begin() + i;

diff  --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index b99a344618ada..912b969fe3c41 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -325,6 +325,7 @@ class EhInputSection : public InputSectionBase {
   SmallVector<EhSectionPiece, 0> pieces;
 
   SyntheticSection *getParent() const;
+  uint64_t getParentOffset(uint64_t offset) const;
 };
 
 // This is a section that is added directly to an output section

diff  --git a/lld/test/ELF/eh-frame-merge.s b/lld/test/ELF/eh-frame-merge.s
index 44aedb7c0204e..b9136b01708e8 100644
--- a/lld/test/ELF/eh-frame-merge.s
+++ b/lld/test/ELF/eh-frame-merge.s
@@ -16,9 +16,9 @@
 
 # RELOC:        Offset             Info     Type          Symbol's Value  Symbol's Name + Addend
 # RELOC-NEXT: {{0*}}[[#%x,OFF:]]   [[#%x,]] R_X86_64_PC32 [[#%x,]]        foo + 0
-# RELOC-NEXT: {{0*}}[[#%x,OFF+20]] [[#%x,]] R_X86_64_PC32 [[#%x,]]        bar + 0
-# RELOC-NEXT: {{0*}}[[#OFF]]       [[#%x,]] R_X86_64_PC32 [[#%x,]]        foo + 1
-# RELOC-NEXT: {{0*}}[[#OFF+20]]    [[#%x,]] R_X86_64_NONE 0{{$}}
+# RELOC-NEXT: {{0*}}[[#%x,OFF+24]] [[#%x,]] R_X86_64_PC32 [[#%x,]]        bar + 0
+# RELOC-NEXT: {{0*}}[[#OFF+48]]    [[#%x,]] R_X86_64_PC32 [[#%x,]]        foo + 1
+# RELOC-NEXT: {{0*}}[[#%x,OFF-24]] [[#%x,]] R_X86_64_NONE 0{{$}}
 
 # EH:          Format:                DWARF32
 # EH:        00000018 00000014 0000001c FDE cie=00000000 pc={{0*}}[[#%x,FOO:]]...

diff  --git a/lld/test/ELF/ehframe-relocation.s b/lld/test/ELF/ehframe-relocation.s
index 040fbbb8de0c3..930d7e67ac472 100644
--- a/lld/test/ELF/ehframe-relocation.s
+++ b/lld/test/ELF/ehframe-relocation.s
@@ -3,7 +3,7 @@
 // RUN: echo '.cfi_startproc; .cfi_endproc' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o
 // RUN: ld.lld %t.o %t2.o -o %t
 // RUN: llvm-readobj -S %t | FileCheck %s
-// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// RUN: llvm-objdump -d --print-imm-hex %t | FileCheck --check-prefix=DISASM %s
 
 // CHECK:      Name: .eh_frame
 // CHECK-NEXT: Type: SHT_PROGBITS
@@ -15,15 +15,17 @@
 // CHECK-NEXT: Size: 52
 // CHECK-NOT: .eh_frame
 
-// 0x200120 = 2097440
 // DISASM:      Disassembly of section .text:
 // DISASM-EMPTY:
 // DISASM-NEXT: <_start>:
-// DISASM-NEXT:   201154: {{.*}} movq 2097440, %rax
+// DISASM-NEXT:   movq 0x200120, %rax
+// DISASM-NEXT:   leaq {{.*}}(%rip), %rax  # {{.*}} <__EH_FRAME_LIST__>
 
 .section .eh_frame,"a", at unwind
+__EH_FRAME_LIST__:
 
 .section .text
 .globl _start
 _start:
- movq .eh_frame, %rax
+ movq .eh_frame, %rax  # addend=0
+ leaq __EH_FRAME_LIST__(%rip), %rax  # addend=-4, used by libclang_rt.crtbegin.o

diff  --git a/lld/test/ELF/mips64-eh-abs-reloc.s b/lld/test/ELF/mips64-eh-abs-reloc.s
index a981f121197af..f4fab9360428f 100644
--- a/lld/test/ELF/mips64-eh-abs-reloc.s
+++ b/lld/test/ELF/mips64-eh-abs-reloc.s
@@ -2,13 +2,13 @@
 # Having an R_MIPS_64 relocation in eh_frame would previously crash LLD
 # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
 # RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ
-# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o
+# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o --no-check-dynamic-relocations
 # RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix PIC-RELOCS
 
 # Linking this as a PIE executable would also previously crash
 # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/archive2.s -o %t-foo.o
 # -pie needs -z notext because of the R_MIPS_64 relocation
-# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o
+# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o --no-check-dynamic-relocations
 # RUN: llvm-readobj -r %t-pie-dynamic.exe | FileCheck %s -check-prefix PIC-RELOCS
 
 


        


More information about the llvm-commits mailing list