From 9ec25667d90912828b32618c911de2e7600f48d2 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 28 Mar 2022 15:55:46 -0700 Subject: [PATCH 1/2] [ELF][test] Refactor some .eh_frame tests * Improve eh-frame-merge.s * Delete invalid .eh_frame+5 test in ehframe-relocation.s --- lld/test/ELF/eh-frame-begin-end.s | 2 +- lld/test/ELF/eh-frame-merge.s | 87 +++++++++++++------------------ lld/test/ELF/ehframe-relocation.s | 3 -- 3 files changed, 36 insertions(+), 56 deletions(-) diff --git a/lld/test/ELF/eh-frame-begin-end.s b/lld/test/ELF/eh-frame-begin-end.s index 46816054f2dc8..41df111c3b074 100644 --- a/lld/test/ELF/eh-frame-begin-end.s +++ b/lld/test/ELF/eh-frame-begin-end.s @@ -10,7 +10,7 @@ // CHECK-NEXT: Flags [ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x200120 +// CHECK-NEXT: Address: // CHECK-NEXT: Offset: 0x120 // CHECK-NEXT: Size: 4 diff --git a/lld/test/ELF/eh-frame-merge.s b/lld/test/ELF/eh-frame-merge.s index b60a5816f20ce..44aedb7c0204e 100644 --- a/lld/test/ELF/eh-frame-merge.s +++ b/lld/test/ELF/eh-frame-merge.s @@ -1,12 +1,39 @@ -// REQUIRES: x86 -// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld --hash-style=sysv %t.o %t.o -o %t -shared -// RUN: llvm-readobj -S --section-data %t | FileCheck %s +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld %t.o %t.o -shared --emit-relocs -o %t.so +# RUN: llvm-readelf -S -r %t.so | FileCheck %s --check-prefixes=CHECK,RELOC +# RUN: llvm-dwarfdump --eh-frame %t.so | FileCheck %s --check-prefix=EH -/// Also show that the merging happens when going via a -r link. -// RUN: ld.lld -r %t.o %t.o -o %t.r.o -// RUN: ld.lld --hash-style=sysv %t.r.o -o %t2 -shared -// RUN: llvm-readobj -S --section-data %t2 | FileCheck %s +## Also show that the merging happens when going via a -r link. +# RUN: ld.lld -r %t.o %t.o -o %t.ro +# RUN: ld.lld %t.ro -o %t2.so -shared +# RUN: llvm-readelf -S -r %t2.so | FileCheck %s + +# CHECK: Name Type Address Off Size ES Flg Lk Inf Al +# CHECK: .eh_frame PROGBITS [[#%x,]] [[#%x,]] 000064 00 A 0 0 8 +# CHECK: foo PROGBITS {{0*}}[[#%x,FOO:]] [[#%x,]] 000002 00 AX 0 0 1 +# CHECK-NEXT: bar PROGBITS {{0*}}[[#%x,FOO+2]] [[#%x,]] 000002 00 AX 0 0 1 + +# 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{{$}} + +# EH: Format: DWARF32 +# EH: 00000018 00000014 0000001c FDE cie=00000000 pc={{0*}}[[#%x,FOO:]]... +# EH-SAME: {{0*}}[[#%x,FOO+1]] +# EH-COUNT-7: DW_CFA_nop: +# EH-EMPTY: +# EH: 00000030 00000014 00000034 FDE cie=00000000 pc={{0*}}[[#%x,FOO+2]]...{{0*}}[[#%x,FOO+4]] +# EH-COUNT-7: DW_CFA_nop: +# EH-EMPTY: +# EH: 00000048 00000014 0000004c FDE cie=00000000 pc={{0*}}[[#%x,FOO+1]]...{{0*}}[[#%x,FOO+2]] +# EH-COUNT-7: DW_CFA_nop: +# EH-EMPTY: +# EH-NEXT: 0x[[#%x,]]: CFA=RSP+8: RIP=[CFA-8] +# EH-EMPTY: +# EH-NEXT: 00000060 ZERO terminator .section foo,"ax",@progbits .cfi_startproc @@ -18,47 +45,3 @@ nop nop .cfi_endproc - -// FIXME: We could really use a .eh_frame parser. -// The intention is to show that: -// * There is only one copy of the CIE -// * There are two copies of the first FDE -// * There is only one copy of the second FDE - -// CHECK: Name: .eh_frame -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: ] -// CHECK-NEXT: Address: -// CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 100 -// CHECK-NEXT: Link: 0 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 8 -// CHECK-NEXT: EntrySize: 0 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 14000000 00000000 017A5200 01781001 | -// CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000 | -// CHECK-NEXT: 0020: 44100000 01000000 00000000 00000000 | -// CHECK-NEXT: 0030: 14000000 34000000 2E100000 02000000 | -// CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000 | -// CHECK-NEXT: 0050: 15100000 01000000 00000000 00000000 | -// CHECK-NEXT: 0060: 00000000 -// CHECK-NEXT: ) - -// CHECK: Name: foo -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: SHF_EXECINSTR -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x125C - -// CHECK: Name: bar -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: SHF_EXECINSTR -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x125E diff --git a/lld/test/ELF/ehframe-relocation.s b/lld/test/ELF/ehframe-relocation.s index 32353c563356c..040fbbb8de0c3 100644 --- a/lld/test/ELF/ehframe-relocation.s +++ b/lld/test/ELF/ehframe-relocation.s @@ -16,12 +16,10 @@ // CHECK-NOT: .eh_frame // 0x200120 = 2097440 -// 0x200120 + 5 = 2097445 // DISASM: Disassembly of section .text: // DISASM-EMPTY: // DISASM-NEXT: <_start>: // DISASM-NEXT: 201154: {{.*}} movq 2097440, %rax -// DISASM-NEXT: 20115c: {{.*}} movq 2097445, %rax .section .eh_frame,"a",@unwind @@ -29,4 +27,3 @@ .globl _start _start: movq .eh_frame, %rax - movq .eh_frame + 5, %rax From 61da3165f2aa66dfa76aada999ae514b65da943d Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Tue, 29 Mar 2022 09:51:41 -0700 Subject: [PATCH 2/2] [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 4b047f75ad69c..3d653d5e2ec04 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -165,11 +165,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()) @@ -1351,6 +1359,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 f060a6337cf7a..2c55e889658e2 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -328,6 +328,7 @@ class EhInputSection : public InputSectionBase { 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 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",@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