[lld] r257753 - [ELF] - implemented --eh-frame-hdr command line option.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 14 02:30:33 PST 2016


Author: grimar
Date: Thu Jan 14 04:30:32 2016
New Revision: 257753

URL: http://llvm.org/viewvc/llvm-project?rev=257753&view=rev
Log:
[ELF] - implemented --eh-frame-hdr command line option.

--eh-frame-hdr
Request creation of ".eh_frame_hdr" section and ELF "PT_GNU_EH_FRAME" segment header.

Both gold and the GNU linker support an option --eh-frame-hdr which tell them to construct a header for all the .eh_frame sections. This header is placed in a section named .eh_frame_hdr and also in a PT_GNU_EH_FRAME segment. At runtime the unwinder can find all the PT_GNU_EH_FRAME segments by calling dl_iterate_phdr.
This section contains a lookup table for quick binary search of FDEs.
Detailed info can be found here:
http://www.airs.com/blog/archives/462

Differential revision: http://reviews.llvm.org/D15712

Added:
    lld/trunk/test/ELF/Inputs/invalid-cie-version2.elf   (with props)
    lld/trunk/test/ELF/eh-frame-hdr-no-out.s
    lld/trunk/test/ELF/eh-frame-hdr-no-out2.s
    lld/trunk/test/ELF/eh-frame-hdr.s
Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=257753&r1=257752&r2=257753&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Thu Jan 14 04:30:32 2016
@@ -57,6 +57,7 @@ struct Configuration {
   bool DiscardAll;
   bool DiscardLocals;
   bool DiscardNone;
+  bool EhFrameHdr;
   bool EnableNewDtags;
   bool ExportDynamic;
   bool GcSections;

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=257753&r1=257752&r2=257753&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Thu Jan 14 04:30:32 2016
@@ -189,6 +189,7 @@ void LinkerDriver::readConfigs(opt::Inpu
   Config->DiscardAll = Args.hasArg(OPT_discard_all);
   Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
   Config->DiscardNone = Args.hasArg(OPT_discard_none);
+  Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
   Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
   Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
   Config->GcSections = Args.hasArg(OPT_gc_sections);

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=257753&r1=257752&r2=257753&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Thu Jan 14 04:30:32 2016
@@ -36,6 +36,9 @@ def discard_none : Flag<["-"], "discard-
 def dynamic_linker : Separate<["--", "-"], "dynamic-linker">,
   HelpText<"Which dynamic linker to use">;
 
+def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
+  HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+
 def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
   HelpText<"Enable new dynamic tags">;
 
@@ -154,7 +157,6 @@ def start_group_paren: Flag<["-"], "(">;
 
 // Options listed below are silently ignored for now for compatibility.
 def build_id : Flag<["--"], "build-id">;
-def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">;
 def fatal_warnings : Flag<["--"], "fatal-warnings">;
 def no_add_needed : Flag<["--"], "no-add-needed">;
 def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=257753&r1=257752&r2=257753&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Jan 14 04:30:32 2016
@@ -11,7 +11,9 @@
 #include "Config.h"
 #include "SymbolTable.h"
 #include "Target.h"
+#include "llvm/Support/Dwarf.h"
 #include "llvm/Support/MathExtras.h"
+#include <map>
 
 using namespace llvm;
 using namespace llvm::object;
@@ -756,6 +758,99 @@ template <class ELFT> void DynamicSectio
 }
 
 template <class ELFT>
+EhFrameHeader<ELFT>::EhFrameHeader()
+    : OutputSectionBase<ELFT>(".eh_frame_hdr", llvm::ELF::SHT_PROGBITS,
+                              SHF_ALLOC) {
+  // It's a 4 bytes of header + pointer to the contents of the .eh_frame section
+  // + the number of FDE pointers in the table.
+  this->Header.sh_size = 12;
+}
+
+// We have to get PC values of FDEs. They depend on relocations
+// which are target specific, so we run this code after performing
+// all relocations. We read the values from ouput buffer according to the
+// encoding given for FDEs. Return value is an offset to the initial PC value
+// for the FDE.
+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) != dwarf::DW_EH_PE_datarel);
+
+  uintX_t FdeOff = EhVA + F.Off + 8;
+  switch (F.Enc & 0xF) {
+  case dwarf::DW_EH_PE_udata2:
+  case dwarf::DW_EH_PE_sdata2:
+    return FdeOff + read16<E>(F.PCRel);
+  case dwarf::DW_EH_PE_udata4:
+  case dwarf::DW_EH_PE_sdata4:
+    return FdeOff + read32<E>(F.PCRel);
+  case dwarf::DW_EH_PE_udata8:
+  case dwarf::DW_EH_PE_sdata8:
+    return FdeOff + read64<E>(F.PCRel);
+  case dwarf::DW_EH_PE_absptr:
+    if (sizeof(uintX_t) == 8)
+      return FdeOff + read64<E>(F.PCRel);
+    return FdeOff + read32<E>(F.PCRel);
+  }
+  error("unknown FDE size encoding");
+}
+
+template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
+  const endianness E = ELFT::TargetEndianness;
+
+  const uint8_t Header[] = {1, dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4,
+                            dwarf::DW_EH_PE_udata4,
+                            dwarf::DW_EH_PE_datarel | dwarf::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());
+  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);
+    // The last four bytes are an offset to the FDE data itself.
+    write32<E>(Buf + 4, EhVA + I.second - VA);
+    Buf += 8;
+  }
+}
+
+template <class ELFT>
+void EhFrameHeader<ELFT>::assignEhFrame(EHOutputSection<ELFT> *Sec) {
+  if (this->Sec && this->Sec != Sec) {
+    warning("multiple .eh_frame sections not supported for .eh_frame_hdr");
+    Live = false;
+    return;
+  }
+  Live = Config->EhFrameHdr;
+  this->Sec = Sec;
+}
+
+template <class ELFT>
+void EhFrameHeader<ELFT>::addFde(uint8_t Enc, size_t Off, uint8_t *PCRel) {
+  if (Live && (Enc & 0xF0) == dwarf::DW_EH_PE_datarel)
+    error("DW_EH_PE_datarel encoding unsupported for FDEs by .eh_frame_hdr");
+  FdeList.push_back(FdeData{Enc, Off, PCRel});
+}
+
+template <class ELFT> void EhFrameHeader<ELFT>::reserveFde() {
+  // Each FDE entry is 8 bytes long:
+  // The first four bytes are an offset to the initial PC value for the FDE. The
+  // last four byte are an offset to the FDE data itself.
+  this->Header.sh_size += 8;
+}
+
+template <class ELFT>
 OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type,
                                    uintX_t Flags)
     : OutputSectionBase<ELFT>(Name, Type, Flags) {}
@@ -908,7 +1003,9 @@ template <class ELFT> void OutputSection
 template <class ELFT>
 EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t Type,
                                        uintX_t Flags)
-    : OutputSectionBase<ELFT>(Name, Type, Flags) {}
+    : OutputSectionBase<ELFT>(Name, Type, Flags) {
+  Out<ELFT>::EhFrameHdr->assignEhFrame(this);
+}
 
 template <class ELFT>
 EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index)
@@ -927,6 +1024,107 @@ template <class ELFT>
 Cie<ELFT>::Cie(EHInputSection<ELFT> *S, unsigned Index)
     : EHRegion<ELFT>(S, Index) {}
 
+// Read a byte and advance D by one byte.
+static uint8_t readByte(ArrayRef<uint8_t> &D) {
+  if (D.empty())
+    error("corrupted or unsupported CIE information");
+  uint8_t B = D.front();
+  D = D.slice(1);
+  return B;
+}
+
+static void skipLeb128(ArrayRef<uint8_t> &D) {
+  while (!D.empty()) {
+    uint8_t Val = D.front();
+    D = D.slice(1);
+    if ((Val & 0x80) == 0)
+      return;
+  }
+  error("corrupted or unsupported CIE information");
+}
+
+template <class ELFT> static unsigned getSizeForEncoding(unsigned Enc) {
+  typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+  switch (Enc & 0x0f) {
+  default:
+    error("unknown FDE encoding");
+  case dwarf::DW_EH_PE_absptr:
+  case dwarf::DW_EH_PE_signed:
+    return sizeof(uintX_t);
+  case dwarf::DW_EH_PE_udata2:
+  case dwarf::DW_EH_PE_sdata2:
+    return 2;
+  case dwarf::DW_EH_PE_udata4:
+  case dwarf::DW_EH_PE_sdata4:
+    return 4;
+  case dwarf::DW_EH_PE_udata8:
+  case dwarf::DW_EH_PE_sdata8:
+    return 8;
+  }
+}
+
+template <class ELFT>
+uint8_t EHOutputSection<ELFT>::getFdeEncoding(ArrayRef<uint8_t> D) {
+  auto Check = [](bool C) {
+    if (!C)
+      error("corrupted or unsupported CIE information");
+  };
+
+  Check(D.size() >= 8);
+  D = D.slice(8);
+
+  uint8_t Version = readByte(D);
+  if (Version != 1 && Version != 3)
+    error("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
+
+  auto AugEnd = std::find(D.begin() + 1, D.end(), '\0');
+  Check(AugEnd != D.end());
+  ArrayRef<uint8_t> AugString(D.begin(), AugEnd - D.begin());
+  D = D.slice(AugString.size() + 1);
+
+  // Code alignment factor should always be 1 for .eh_frame.
+  if (readByte(D) != 1)
+    error("CIE code alignment must be 1");
+  // Skip data alignment factor
+  skipLeb128(D);
+
+  // Skip the return address register. In CIE version 1 this is a single
+  // byte. In CIE version 3 this is an unsigned LEB128.
+  if (Version == 1)
+    readByte(D);
+  else
+    skipLeb128(D);
+
+  while (!AugString.empty()) {
+    switch (readByte(AugString)) {
+    case 'z':
+      skipLeb128(D);
+      break;
+    case 'R':
+      return readByte(D);
+    case 'P': {
+      uint8_t Enc = readByte(D);
+      if ((Enc & 0xf0) == dwarf::DW_EH_PE_aligned)
+        error("DW_EH_PE_aligned encoding for address of a personality routine "
+              "handler not supported");
+      unsigned EncSize = getSizeForEncoding<ELFT>(Enc);
+      Check(D.size() >= EncSize);
+      D = D.slice(EncSize);
+      break;
+    }
+    case 'S':
+    case 'L':
+      // L: Language Specific Data Area (LSDA) encoding
+      // S: This CIE represents a stack frame for the invocation of a signal
+      //    handler
+      break;
+    default:
+      error("unknown .eh_frame augmentation string value");
+    }
+  }
+  return dwarf::DW_EH_PE_absptr;
+}
+
 template <class ELFT>
 template <bool IsRela>
 void EHOutputSection<ELFT>::addSectionAux(
@@ -964,6 +1162,8 @@ void EHOutputSection<ELFT>::addSectionAu
     if (ID == 0) {
       // CIE
       Cie<ELFT> C(S, Index);
+      if (Config->EhFrameHdr)
+        C.FdeEncoding = getFdeEncoding(D);
 
       StringRef Personality;
       if (HasReloc) {
@@ -989,6 +1189,7 @@ void EHOutputSection<ELFT>::addSectionAu
         if (I == OffsetToIndex.end())
           error("Invalid CIE reference");
         Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index));
+        Out<ELFT>::EhFrameHdr->reserveFde();
         this->Header.sh_size += align(Length, sizeof(uintX_t));
       }
     }
@@ -1062,6 +1263,7 @@ template <class ELFT> void EHOutputSecti
       uintX_t Len = writeAlignedCieOrFde<ELFT>(F.data(), Buf + Offset);
       write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer
       F.S->Offsets[F.Index].second = Offset;
+      Out<ELFT>::EhFrameHdr->addFde(C.FdeEncoding, Offset, Buf + Offset + 8);
       Offset += Len;
     }
   }
@@ -1455,6 +1657,11 @@ template class OutputSectionBase<ELF32BE
 template class OutputSectionBase<ELF64LE>;
 template class OutputSectionBase<ELF64BE>;
 
+template class EhFrameHeader<ELF32LE>;
+template class EhFrameHeader<ELF32BE>;
+template class EhFrameHeader<ELF64LE>;
+template class EhFrameHeader<ELF64BE>;
+
 template class GotPltSection<ELF32LE>;
 template class GotPltSection<ELF32BE>;
 template class GotPltSection<ELF64LE>;

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=257753&r1=257752&r2=257753&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Jan 14 04:30:32 2016
@@ -287,6 +287,7 @@ template <class ELFT> struct EHRegion {
 template <class ELFT> struct Cie : public EHRegion<ELFT> {
   Cie(EHInputSection<ELFT> *S, unsigned Index);
   std::vector<EHRegion<ELFT>> Fdes;
+  uint8_t FdeEncoding;
 };
 
 template <class ELFT>
@@ -308,6 +309,7 @@ public:
   void addSection(InputSectionBase<ELFT> *S) override;
 
 private:
+  uint8_t getFdeEncoding(ArrayRef<uint8_t> D);
   uintX_t readEntryLength(ArrayRef<uint8_t> D);
 
   std::vector<EHInputSection<ELFT> *> Sections;
@@ -429,6 +431,42 @@ private:
   uint32_t GprMask = 0;
 };
 
+// --eh-frame-hdr option tells linker to construct a header for all the
+// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
+// and also to a PT_GNU_EH_FRAME segment.
+// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
+// calling dl_iterate_phdr.
+// This section contains a lookup table for quick binary search of FDEs.
+// Detailed info about internals can be found in Ian Lance Taylor's blog:
+// http://www.airs.com/blog/archives/460 (".eh_frame")
+// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
+template <class ELFT>
+class EhFrameHeader final : public OutputSectionBase<ELFT> {
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+
+public:
+  EhFrameHeader();
+  void writeTo(uint8_t *Buf) override;
+
+  void addFde(uint8_t Enc, size_t Off, uint8_t *PCRel);
+  void assignEhFrame(EHOutputSection<ELFT> *Sec);
+  void reserveFde();
+
+  bool Live = false;
+
+private:
+  struct FdeData {
+    uint8_t Enc;
+    size_t Off;
+    uint8_t *PCRel;
+  };
+
+  uintX_t getFdePc(uintX_t EhVA, const FdeData &F);
+
+  EHOutputSection<ELFT> *Sec = nullptr;
+  std::vector<FdeData> FdeList;
+};
+
 inline uint64_t align(uint64_t Value, uint64_t Align) {
   return llvm::RoundUpToAlignment(Value, Align);
 }
@@ -440,6 +478,7 @@ template <class ELFT> struct Out {
   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
   static DynamicSection<ELFT> *Dynamic;
+  static EhFrameHeader<ELFT> *EhFrameHdr;
   static GnuHashTableSection<ELFT> *GnuHashTab;
   static GotPltSection<ELFT> *GotPlt;
   static GotSection<ELFT> *Got;
@@ -461,6 +500,7 @@ template <class ELFT> struct Out {
 };
 
 template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
+template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
 template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
 template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt;
 template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=257753&r1=257752&r2=257753&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Jan 14 04:30:32 2016
@@ -140,6 +140,8 @@ template <class ELFT> void elf2::writeRe
     Out<ELFT>::RelaPlt = &RelaPlt;
   DynamicSection<ELFT> Dynamic(*Symtab);
   Out<ELFT>::Dynamic = &Dynamic;
+  EhFrameHeader<ELFT> EhFrameHdr;
+  Out<ELFT>::EhFrameHdr = &EhFrameHdr;
 
   Writer<ELFT>(*Symtab).run();
 }
@@ -910,6 +912,9 @@ template <class ELFT> void Writer<ELFT>:
     Add(Out<ELFT>::GotPlt);
   if (!Out<ELFT>::Plt->empty())
     Add(Out<ELFT>::Plt);
+
+  if (Out<ELFT>::EhFrameHdr->Live)
+    Add(Out<ELFT>::EhFrameHdr);
 }
 
 // The linker is expected to define SECNAME_start and SECNAME_end
@@ -1109,6 +1114,12 @@ template <class ELFT> void Writer<ELFT>:
     *PH = GnuRelroPhdr;
   }
 
+  if (Out<ELFT>::EhFrameHdr->Live) {
+    Elf_Phdr *PH = &Phdrs[++PhdrIdx];
+    PH->p_type = PT_GNU_EH_FRAME;
+    copyPhdr(PH, Out<ELFT>::EhFrameHdr);
+  }
+
   // PT_GNU_STACK is a special section to tell the loader to make the
   // pages for the stack non-executable.
   if (!Config->ZExecStack) {
@@ -1158,6 +1169,8 @@ template <class ELFT> int Writer<ELFT>::
     ++I;
   if (HasRelro)
     ++I;
+  if (Out<ELFT>::EhFrameHdr->Live)
+    ++I;
   return I;
 }
 

Added: lld/trunk/test/ELF/Inputs/invalid-cie-version2.elf
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/invalid-cie-version2.elf?rev=257753&view=auto
==============================================================================
Binary file - no diff available.

Propchange: lld/trunk/test/ELF/Inputs/invalid-cie-version2.elf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: lld/trunk/test/ELF/eh-frame-hdr-no-out.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-hdr-no-out.s?rev=257753&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-hdr-no-out.s (added)
+++ lld/trunk/test/ELF/eh-frame-hdr-no-out.s Thu Jan 14 04:30:32 2016
@@ -0,0 +1,6 @@
+// REQUIRES: x86
+// RUN: not ld.lld --eh-frame-hdr %p/Inputs/invalid-cie-version2.elf -o %t >& %t.log
+// RUN: FileCheck %s < %t.log
+
+// invalid-cie-version2.elf contains unsupported version of CIE = 2.
+// CHECK: FDE version 1 or 3 expected, but got 2

Added: lld/trunk/test/ELF/eh-frame-hdr-no-out2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-hdr-no-out2.s?rev=257753&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-hdr-no-out2.s (added)
+++ lld/trunk/test/ELF/eh-frame-hdr-no-out2.s Thu Jan 14 04:30:32 2016
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t
+// RUN: llvm-readobj -s -program-headers %t | FileCheck %s --check-prefix=NOHDR
+
+.section foo,"ax", at progbits
+ nop
+
+.text
+.globl _start;
+_start:
+
+// There is no .eh_frame section,
+// therefore .eh_frame_hdr also not created.
+// NOHDR:       Sections [
+// NOHDR-NOT:    Name: .eh_frame
+// NOHDR-NOT:    Name: .eh_frame_hdr
+// NOHDR:      ProgramHeaders [
+// NOHDR-NOT:   PT_GNU_EH_FRAME

Added: lld/trunk/test/ELF/eh-frame-hdr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-hdr.s?rev=257753&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-hdr.s (added)
+++ lld/trunk/test/ELF/eh-frame-hdr.s Thu Jan 14 04:30:32 2016
@@ -0,0 +1,127 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=NOHDR
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t
+// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=HDR
+// RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=HDRDISASM
+
+.section foo,"ax", at progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar,"ax", at progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah,"ax", at progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.text
+.globl _start;
+_start:
+
+// NOHDR:       Sections [
+// NOHDR-NOT:    Name: .eh_frame_hdr
+// NOHDR:      ProgramHeaders [
+// NOHDR-NOT:   PT_GNU_EH_FRAME
+
+//HDRDISASM:      Disassembly of section foo:
+//HDRDISASM-NEXT: foo:
+//HDRDISASM-NEXT:    11000: 90 nop
+//HDRDISASM-NEXT: Disassembly of section bar:
+//HDRDISASM-NEXT: bar:
+//HDRDISASM-NEXT:    11001: 90 nop
+//HDRDISASM-NEXT: Disassembly of section dah:
+//HDRDISASM-NEXT: dah:
+//HDRDISASM-NEXT:    11002: 90 nop
+
+// HDR:       Sections [
+// HDR:        Section {
+// HDR:        Index: 1
+// HDR-NEXT:    Name: .eh_frame
+// HDR-NEXT:    Type: SHT_X86_64_UNWIND
+// HDR-NEXT:    Flags [
+// HDR-NEXT:      SHF_ALLOC
+// HDR-NEXT:    ]
+// HDR-NEXT:    Address: 0x10158
+// HDR-NEXT:    Offset: 0x158
+// HDR-NEXT:    Size: 96
+// HDR-NEXT:    Link: 0
+// HDR-NEXT:    Info: 0
+// HDR-NEXT:    AddressAlignment: 8
+// HDR-NEXT:    EntrySize: 0
+// HDR-NEXT:    SectionData (
+// HDR-NEXT:      0000: 14000000 00000000 017A5200 01781001  |
+// HDR-NEXT:      0010: 1B0C0708 90010000 14000000 1C000000  |
+// HDR-NEXT:      0020: 880E0000 01000000 00000000 00000000  |
+// HDR-NEXT:      0030: 14000000 34000000 710E0000 01000000  |
+// HDR-NEXT:      0040: 00000000 00000000 14000000 4C000000  |
+// HDR-NEXT:      0050: 5A0E0000 01000000 00000000 00000000  |
+//            CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000
+//            FDE(1): 14000000 1C000000 880E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x880E0000) = 0x10158 + 0x0020 = 0x10178
+//                    The starting address to which this FDE applies = 0xE88 + 0x10178 = 0x11000
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+//            FDE(2): 14000000 34000000 710E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x710E0000) = 0x10158 + 0x0038 = 0x10190
+//                    The starting address to which this FDE applies = 0xE71 + 0x10190 = 0x11001
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+//            FDE(3): 14000000 4C000000 5A0E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x5A0E0000) = 0x10158 + 0x0050 = 0x101A8
+//                    The starting address to which this FDE applies = 0xE5A + 0x101A8 = 0x11002
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+// HDR-NEXT:    )
+// HDR-NEXT:  }
+// HDR-NEXT:  Section {
+// HDR-NEXT:    Index: 2
+// HDR-NEXT:    Name: .eh_frame_hdr
+// HDR-NEXT:    Type: SHT_PROGBITS
+// HDR-NEXT:    Flags [
+// HDR-NEXT:      SHF_ALLOC
+// HDR-NEXT:    ]
+// HDR-NEXT:    Address: 0x101B8
+// HDR-NEXT:    Offset: 0x1B8
+// HDR-NEXT:    Size: 36
+// HDR-NEXT:    Link: 0
+// HDR-NEXT:    Info: 0
+// HDR-NEXT:    AddressAlignment: 0
+// HDR-NEXT:    EntrySize: 0
+// HDR-NEXT:    SectionData (
+// HDR-NEXT:      0000: 011B033B 9CFFFFFF 03000000 480E0000  |
+// HDR-NEXT:      0010: B8FFFFFF 490E0000 D0FFFFFF 4A0E0000  |
+// HDR-NEXT:      0020: E8FFFFFF                             |
+//                Header (always 4 bytes): 0x011B033B
+//                   9CFFFFFF = .eh_frame(0x10158) - .eh_frame_hdr(0x101B8) - 4
+//                   03000000 = 3 = the number of FDE pointers in the table.
+//                Entry(1): 480E0000 B8FFFFFF
+//                   480E0000 = 0x11000 - .eh_frame_hdr(0x101B8) = 0xE48
+//                   B8FFFFFF = address of FDE(1) - .eh_frame_hdr(0x101B8) =
+//                      = .eh_frame(0x10158) + 24 - 0x101B8 = 0xFFFFFFB8
+//                Entry(2): 490E0000 D0FFFFFF
+//                   490E0000 = 0x11001 - .eh_frame_hdr(0x101B8) = 0xE49
+//                   D0FFFFFF = address of FDE(2) - .eh_frame_hdr(0x101B8) =
+//                      = .eh_frame(0x10158) + 24 + 24 - 0x101B8 = 0xFFFFFFD0
+//                Entry(3): 4A0E0000 E8FFFFFF
+//                   4A0E0000 = 0x11002 - .eh_frame_hdr(0x101B8) = 0xE4A
+//                   E8FFFFFF = address of FDE(2) - .eh_frame_hdr(0x101B8) =
+//                      = .eh_frame(0x10158) + 24 + 24 - 0x101B8 = 0xFFFFFFE8
+// HDR-NEXT:    )
+// HDR-NEXT:  }
+// HDR:     ProgramHeaders [
+// HDR:      ProgramHeader {
+// HDR:       Type: PT_GNU_EH_FRAME
+// HDR-NEXT:   Offset: 0x1B8
+// HDR-NEXT:   VirtualAddress: 0x101B8
+// HDR-NEXT:   PhysicalAddress: 0x101B8
+// HDR-NEXT:   FileSize: 36
+// HDR-NEXT:   MemSize: 36
+// HDR-NEXT:   Flags [
+// HDR-NEXT:     PF_R
+// HDR-NEXT:   ]
+// HDR-NEXT:   Alignment: 1
+// HDR-NEXT: }




More information about the llvm-commits mailing list