[lld] r265957 - ELF: Set FDE count in .eh_frame_hdr correctly.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 11 09:40:09 PDT 2016


Author: pcc
Date: Mon Apr 11 11:40:08 2016
New Revision: 265957

URL: http://llvm.org/viewvc/llvm-project?rev=265957&view=rev
Log:
ELF: Set FDE count in .eh_frame_hdr correctly.

It is possible to have FDEs with duplicate PCs if ICF was able to merge
functions with FDEs, or if the input files for some reason contained duplicate
FDEs.  We previously weren't handling this correctly when producing the
contents of the .eh_frame_hdr section; we were dropping entries and leaving
null entries at the end of the section, which confused consumers of unwind
data, such as the backtrace() function.

Fix the bug by setting the FDE count to the number of FDEs actually emitted
into .eh_frame_hdr, rather than the number of FDEs in .eh_frame.

Differential Revision: http://reviews.llvm.org/D18911

Added:
    lld/trunk/test/ELF/eh-frame-hdr-icf.s
Modified:
    lld/trunk/ELF/OutputSections.cpp

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=265957&r1=265956&r2=265957&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Mon Apr 11 11:40:08 2016
@@ -727,23 +727,25 @@ EhFrameHeader<ELFT>::getFdePc(uintX_t Eh
 template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
   const endianness E = ELFT::TargetEndianness;
 
+  uintX_t EhVA = Sec->getVA();
+  uintX_t VA = this->getVA();
+
+  // InitialPC -> Offset in .eh_frame, sorted by InitialPC, and deduplicate PCs.
+  // FIXME: Deduplication leaves unneeded null bytes at the end of the section.
+  std::map<uintX_t, size_t> PcToOffset;
+  for (const FdeData &F : FdeList)
+    PcToOffset[getFdePc(EhVA, F)] = F.Off;
+
   const uint8_t Header[] = {1, DW_EH_PE_pcrel | DW_EH_PE_sdata4,
                             DW_EH_PE_udata4,
                             DW_EH_PE_datarel | DW_EH_PE_sdata4};
   memcpy(Buf, Header, sizeof(Header));
 
-  uintX_t EhVA = Sec->getVA();
-  uintX_t VA = this->getVA();
   uintX_t EhOff = EhVA - VA - 4;
   write32<E>(Buf + 4, EhOff);
-  write32<E>(Buf + 8, this->FdeList.size());
+  write32<E>(Buf + 8, PcToOffset.size());
   Buf += 12;
 
-  // InitialPC -> Offset in .eh_frame, sorted by InitialPC.
-  std::map<uintX_t, size_t> PcToOffset;
-  for (const FdeData &F : FdeList)
-    PcToOffset[getFdePc(EhVA, F)] = F.Off;
-
   for (auto &I : PcToOffset) {
     // The first four bytes are an offset to the initial PC value for the FDE.
     write32<E>(Buf, I.first - VA);

Added: lld/trunk/test/ELF/eh-frame-hdr-icf.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-hdr-icf.s?rev=265957&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-hdr-icf.s (added)
+++ lld/trunk/test/ELF/eh-frame-hdr-icf.s Mon Apr 11 11:40:08 2016
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --eh-frame-hdr
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .eh_frame_hdr:
+# CHECK-NEXT: 101a0 011b033b b4ffffff 01000000 600e0000
+#                                     ^ FDE count
+# CHECK-NEXT: 101b0 e8ffffff 00000000 00000000
+#                   ^ FDE for f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  .cfi_startproc
+  ret
+  .cfi_endproc
+
+.section .text.f2, "ax"
+f2:
+  .cfi_startproc
+  ret
+  .cfi_endproc




More information about the llvm-commits mailing list