summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/OutputSections.cpp38
-rw-r--r--lld/test/ELF/eh-frame-hdr-abs-fde.s33
2 files changed, 56 insertions, 15 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index bec005e9862..3274ec012aa 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -668,25 +668,31 @@ template <class ELFT>
typename EhFrameHeader<ELFT>::uintX_t
EhFrameHeader<ELFT>::getFdePc(uintX_t EhVA, const FdeData &F) {
const endianness E = ELFT::TargetEndianness;
- assert((F.Enc & 0xF0) != DW_EH_PE_datarel);
-
- uintX_t FdeOff = EhVA + F.Off + 8;
- switch (F.Enc & 0xF) {
+ uint8_t Size = F.Enc & 0x7;
+ if (Size == DW_EH_PE_absptr)
+ Size = sizeof(uintX_t) == 8 ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+ uint64_t PC;
+ switch (Size) {
case DW_EH_PE_udata2:
- case DW_EH_PE_sdata2:
- return FdeOff + read16<E>(F.PCRel);
+ PC = read16<E>(F.PCRel);
+ break;
case DW_EH_PE_udata4:
- case DW_EH_PE_sdata4:
- return FdeOff + read32<E>(F.PCRel);
+ PC = read32<E>(F.PCRel);
+ break;
case DW_EH_PE_udata8:
- case DW_EH_PE_sdata8:
- return FdeOff + read64<E>(F.PCRel);
+ PC = read64<E>(F.PCRel);
+ break;
+ default:
+ fatal("unknown FDE size encoding");
+ }
+ switch (F.Enc & 0x70) {
case DW_EH_PE_absptr:
- if (sizeof(uintX_t) == 8)
- return FdeOff + read64<E>(F.PCRel);
- return FdeOff + read32<E>(F.PCRel);
+ return PC;
+ case DW_EH_PE_pcrel:
+ return PC + EhVA + F.Off + 8;
+ default:
+ fatal("unknown FDE size relative encoding");
}
- fatal("unknown FDE size encoding");
}
template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
@@ -1084,8 +1090,10 @@ uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
skipAugP<ELFT>(D);
continue;
}
- if (C == 'L')
+ if (C == 'L') {
+ readByte(D);
continue;
+ }
fatal("unknown .eh_frame augmentation string: " + Aug);
}
return DW_EH_PE_absptr;
diff --git a/lld/test/ELF/eh-frame-hdr-abs-fde.s b/lld/test/ELF/eh-frame-hdr-abs-fde.s
new file mode 100644
index 00000000000..edc892ac8d0
--- /dev/null
+++ b/lld/test/ELF/eh-frame-hdr-abs-fde.s
@@ -0,0 +1,33 @@
+# Check reading PC values of FDEs and writing lookup table in the .eh_frame_hdr
+# if CIE augmentation string has 'L' token and PC values are encoded using
+# absolute (not relative) format.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr %t.o -o %t
+# RUN: llvm-objdump -s -dwarf=frames %t | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK: Contents of section .eh_frame_hdr:
+# CHECK-NEXT: 10158 011b033b ffffffcc 00000001 0000fea8
+# ^-- 0x20000 - 0x10158
+# .text - .eh_frame_hdr
+# CHECK-NEXT: 10168 ffffffe8
+# CHECK-NEXT: Contents of section .text:
+# CHECK-NEXT: 20000 00000000
+
+# CHECK: Augmentation: "zLR"
+# CHECK: Augmentation data: 00 0B
+# ^-- DW_EH_PE_udata4 | DW_EH_PE_signed
+
+ .text
+ .globl __start
+__start:
+ .cfi_startproc
+ .cfi_lsda 0, _ex
+ nop
+ .cfi_endproc
+
+ .data
+_ex:
+ .word 0
OpenPOWER on IntegriCloud