Skip to content

[cherry-pick] [ELF] --emit-relocs: adjust offsets of .rel[a].eh_frame relocations #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,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())
Expand Down Expand Up @@ -1351,6 +1359,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;
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/InputSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,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
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/eh-frame-begin-end.s
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
87 changes: 35 additions & 52 deletions lld/test/ELF/eh-frame-merge.s
Original file line number Diff line number Diff line change
@@ -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+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:]]...
# 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
Expand All @@ -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
13 changes: 6 additions & 7 deletions lld/test/ELF/ehframe-relocation.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -15,18 +15,17 @@
// CHECK-NEXT: Size: 52
// 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
// 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 + 5, %rax
movq .eh_frame, %rax # addend=0
leaq __EH_FRAME_LIST__(%rip), %rax # addend=-4, used by libclang_rt.crtbegin.o
4 changes: 2 additions & 2 deletions lld/test/ELF/mips64-eh-abs-reloc.s
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down