[lld] r270526 - Create a new file EhFrame.cpp and move code to read .eh_frame there.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Mon May 23 19:55:49 PDT 2016


Author: ruiu
Date: Mon May 23 21:55:45 2016
New Revision: 270526

URL: http://llvm.org/viewvc/llvm-project?rev=270526&view=rev
Log:
Create a new file EhFrame.cpp and move code to read .eh_frame there.

Added:
    lld/trunk/ELF/EhFrame.cpp
    lld/trunk/ELF/EhFrame.h
Modified:
    lld/trunk/ELF/CMakeLists.txt
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/OutputSections.cpp

Modified: lld/trunk/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/CMakeLists.txt?rev=270526&r1=270525&r2=270526&view=diff
==============================================================================
--- lld/trunk/ELF/CMakeLists.txt (original)
+++ lld/trunk/ELF/CMakeLists.txt Mon May 23 21:55:45 2016
@@ -5,6 +5,7 @@ add_public_tablegen_target(ELFOptionsTab
 add_lld_library(lldELF
   Driver.cpp
   DriverUtils.cpp
+  EhFrame.cpp
   Error.cpp
   ICF.cpp
   InputFiles.cpp

Added: lld/trunk/ELF/EhFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/EhFrame.cpp?rev=270526&view=auto
==============================================================================
--- lld/trunk/ELF/EhFrame.cpp (added)
+++ lld/trunk/ELF/EhFrame.cpp Mon May 23 21:55:45 2016
@@ -0,0 +1,167 @@
+//===- EhFrame.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// .eh_frame section contains information on how to unwind the stack when
+// an exception is thrown. The section consists of sequence of CIE and FDE
+// records. The linker needs to merge CIEs and associate FDEs to CIEs.
+// That means the linker has to understand the format of the section.
+//
+// This file contains a few utility functions to read .eh_frame contents.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EhFrame.h"
+#include "Error.h"
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+namespace lld {
+namespace elf {
+
+// .eh_frame section is a sequence of records. Each record starts with
+// a 4 byte length field. This function reads the length.
+template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> D) {
+  const endianness E = ELFT::TargetEndianness;
+  if (D.size() < 4)
+    fatal("CIE/FDE too small");
+
+  // First 4 bytes of CIE/FDE is the size of the record.
+  // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
+  // but we do not support that format yet.
+  uint64_t V = read32<E>(D.data());
+  if (V == UINT32_MAX)
+    fatal("CIE/FDE too large");
+  uint64_t Size = V + 4;
+  if (Size > D.size())
+    fatal("CIE/FIE ends past the end of the section");
+  return Size;
+}
+
+// Read a byte and advance D by one byte.
+static uint8_t readByte(ArrayRef<uint8_t> &D) {
+  if (D.empty())
+    fatal("corrupted or unsupported CIE information");
+  uint8_t B = D.front();
+  D = D.slice(1);
+  return B;
+}
+
+// Skip an integer encoded in the LEB128 format.
+// Actual number is not of interest because only the runtime needs it.
+// But we need to be at least able to skip it so that we can read
+// the field that follows a LEB128 number.
+static void skipLeb128(ArrayRef<uint8_t> &D) {
+  while (!D.empty()) {
+    uint8_t Val = D.front();
+    D = D.slice(1);
+    if ((Val & 0x80) == 0)
+      return;
+  }
+  fatal("corrupted or unsupported CIE information");
+}
+
+template <class ELFT> static size_t getAugPSize(unsigned Enc) {
+  switch (Enc & 0x0f) {
+  case DW_EH_PE_absptr:
+  case DW_EH_PE_signed:
+    return ELFT::Is64Bits ? 8 : 4;
+  case DW_EH_PE_udata2:
+  case DW_EH_PE_sdata2:
+    return 2;
+  case DW_EH_PE_udata4:
+  case DW_EH_PE_sdata4:
+    return 4;
+  case DW_EH_PE_udata8:
+  case DW_EH_PE_sdata8:
+    return 8;
+  }
+  fatal("unknown FDE encoding");
+}
+
+template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) {
+  uint8_t Enc = readByte(D);
+  if ((Enc & 0xf0) == DW_EH_PE_aligned)
+    fatal("DW_EH_PE_aligned encoding is not supported");
+  size_t Size = getAugPSize<ELFT>(Enc);
+  if (Size >= D.size())
+    fatal("corrupted CIE");
+  D = D.slice(Size);
+}
+
+template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> D) {
+  if (D.size() < 8)
+    fatal("CIE too small");
+  D = D.slice(8);
+
+  uint8_t Version = readByte(D);
+  if (Version != 1 && Version != 3)
+    fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
+
+  const unsigned char *AugEnd = std::find(D.begin() + 1, D.end(), '\0');
+  if (AugEnd == D.end())
+    fatal("corrupted CIE");
+  StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin());
+  D = D.slice(Aug.size() + 1);
+
+  // Code alignment factor should always be 1 for .eh_frame.
+  if (readByte(D) != 1)
+    fatal("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);
+
+  // We only care about an 'R' value, but other records may precede an 'R'
+  // record. Unfortunately records are not in TLV (type-length-value) format,
+  // so we need to teach the linker how to skip records for each type.
+  for (char C : Aug) {
+    if (C == 'R')
+      return readByte(D);
+    if (C == 'z') {
+      skipLeb128(D);
+      continue;
+    }
+    if (C == 'P') {
+      skipAugP<ELFT>(D);
+      continue;
+    }
+    if (C == 'L') {
+      readByte(D);
+      continue;
+    }
+    fatal("unknown .eh_frame augmentation string: " + Aug);
+  }
+  return DW_EH_PE_absptr;
+}
+
+template size_t readEhRecordSize<ELF32LE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF32BE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF64LE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF64BE>(ArrayRef<uint8_t>);
+
+template uint8_t getFdeEncoding<ELF32LE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF32BE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF64LE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF64BE>(ArrayRef<uint8_t>);
+}
+}

Added: lld/trunk/ELF/EhFrame.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/EhFrame.h?rev=270526&view=auto
==============================================================================
--- lld/trunk/ELF/EhFrame.h (added)
+++ lld/trunk/ELF/EhFrame.h Mon May 23 21:55:45 2016
@@ -0,0 +1,22 @@
+//===- EhFrame.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_EHFRAME_H
+#define LLD_ELF_EHFRAME_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> Data);
+template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> Data);
+}
+}
+
+#endif

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=270526&r1=270525&r2=270526&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Mon May 23 21:55:45 2016
@@ -9,6 +9,7 @@
 
 #include "InputSection.h"
 #include "Config.h"
+#include "EhFrame.h"
 #include "Error.h"
 #include "InputFiles.h"
 #include "OutputSections.h"
@@ -407,30 +408,13 @@ bool EHInputSection<ELFT>::classof(const
   return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
 }
 
-template <class ELFT> static size_t readRecordSize(ArrayRef<uint8_t> D) {
-  const endianness E = ELFT::TargetEndianness;
-  if (D.size() < 4)
-    fatal("CIE/FDE too small");
-
-  // First 4 bytes of CIE/FDE is the size of the record.
-  // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
-  // but we do not support that format yet.
-  uint64_t V = read32<E>(D.data());
-  if (V == UINT32_MAX)
-    fatal("CIE/FDE too large");
-  uint64_t Size = V + 4;
-  if (Size > D.size())
-    fatal("CIE/FIE ends past the end of the section");
-  return Size;
-}
-
 // .eh_frame is a sequence of CIE or FDE records.
 // This function splits an input section into records and returns them.
 template <class ELFT>
 void EHInputSection<ELFT>::split() {
   ArrayRef<uint8_t> Data = this->getSectionData();
   for (size_t Off = 0, End = Data.size(); Off != End;) {
-    size_t Size = readRecordSize<ELFT>(Data.slice(Off));
+    size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
     // The empty record is the end marker.
     if (Size == 4)
       break;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=270526&r1=270525&r2=270526&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Mon May 23 21:55:45 2016
@@ -9,6 +9,7 @@
 
 #include "OutputSections.h"
 #include "Config.h"
+#include "EhFrame.h"
 #include "LinkerScript.h"
 #include "SymbolTable.h"
 #include "Target.h"
@@ -916,105 +917,6 @@ void EhOutputSection<ELFT>::forEachInput
     F(S);
 }
 
-// Read a byte and advance D by one byte.
-static uint8_t readByte(ArrayRef<uint8_t> &D) {
-  if (D.empty())
-    fatal("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;
-  }
-  fatal("corrupted or unsupported CIE information");
-}
-
-template <class ELFT> static size_t getAugPSize(unsigned Enc) {
-  switch (Enc & 0x0f) {
-  case DW_EH_PE_absptr:
-  case DW_EH_PE_signed:
-    return ELFT::Is64Bits ? 8 : 4;
-  case DW_EH_PE_udata2:
-  case DW_EH_PE_sdata2:
-    return 2;
-  case DW_EH_PE_udata4:
-  case DW_EH_PE_sdata4:
-    return 4;
-  case DW_EH_PE_udata8:
-  case DW_EH_PE_sdata8:
-    return 8;
-  }
-  fatal("unknown FDE encoding");
-}
-
-template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) {
-  uint8_t Enc = readByte(D);
-  if ((Enc & 0xf0) == DW_EH_PE_aligned)
-    fatal("DW_EH_PE_aligned encoding is not supported");
-  size_t Size = getAugPSize<ELFT>(Enc);
-  if (Size >= D.size())
-    fatal("corrupted CIE");
-  D = D.slice(Size);
-}
-
-template <class ELFT> static uint8_t getFdeEncoding(ArrayRef<uint8_t> D) {
-  if (D.size() < 8)
-    fatal("CIE too small");
-  D = D.slice(8);
-
-  uint8_t Version = readByte(D);
-  if (Version != 1 && Version != 3)
-    fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
-
-  const unsigned char *AugEnd = std::find(D.begin() + 1, D.end(), '\0');
-  if (AugEnd == D.end())
-    fatal("corrupted CIE");
-  StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin());
-  D = D.slice(Aug.size() + 1);
-
-  // Code alignment factor should always be 1 for .eh_frame.
-  if (readByte(D) != 1)
-    fatal("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);
-
-  // We only care about an 'R' value, but other records may precede an 'R'
-  // record. Records are not in TLV (type-length-value) format, so we need
-  // to teach the linker how to skip records for each type.
-  for (char C : Aug) {
-    if (C == 'R')
-      return readByte(D);
-    if (C == 'z') {
-      skipLeb128(D);
-      continue;
-    }
-    if (C == 'P') {
-      skipAugP<ELFT>(D);
-      continue;
-    }
-    if (C == 'L') {
-      readByte(D);
-      continue;
-    }
-    fatal("unknown .eh_frame augmentation string: " + Aug);
-  }
-  return DW_EH_PE_absptr;
-}
-
 // Returns the first relocation that points to a region
 // between Begin and Begin+Size.
 template <class IntTy, class RelTy>




More information about the llvm-commits mailing list