From 464531193353584cef7003c11ceffee61a7dc38a Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Tue, 29 Mar 2022 09:51:41 -0700 Subject: [PATCH] [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 --- lld/ELF/InputSection.cpp | 25 +++++++++++++++++++++---- lld/ELF/InputSection.h | 1 + lld/test/ELF/eh-frame-merge.s | 6 +++--- lld/test/ELF/ehframe-relocation.s | 10 ++++++---- lld/test/ELF/mips64-eh-abs-reloc.s | 4 ++-- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index d45ab94..9fe9cea 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(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(this); + if (!es->rawData.empty()) + if (InputSection *isec = es->getParent()) + return isec->outSecOff + es->getParentOffset(offset); return offset; + } case Merge: const MergeInputSection *ms = cast(this); if (InputSection *isec = ms->getParent()) @@ -1334,6 +1342,15 @@ void EhInputSection::split(ArrayRef 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 b99a344..912b969 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -325,6 +325,7 @@ public: SmallVector 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 44aedb7..b9136b0 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 040fbbb..930d7e6 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",@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 a981f12..f4fab93 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 -- 2.7.4