[lld] r355153 - ELF: Write .eh_frame_hdr explicitly after writing .eh_frame.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 28 15:11:35 PST 2019


Author: pcc
Date: Thu Feb 28 15:11:35 2019
New Revision: 355153

URL: http://llvm.org/viewvc/llvm-project?rev=355153&view=rev
Log:
ELF: Write .eh_frame_hdr explicitly after writing .eh_frame.

This lets us remove the special case from Writer::writeSections(), and also
fixes a bug where .eh_frame_hdr isn't necessarily written in the correct
order if a linker script moves .eh_frame and .eh_frame_hdr into the same
output section.

Differential Revision: https://reviews.llvm.org/D58795

Added:
    lld/trunk/test/ELF/linkerscript/eh-frame-merge.s
Modified:
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/SyntheticSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=355153&r1=355152&r2=355153&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Feb 28 15:11:35 2019
@@ -30,6 +30,7 @@ using namespace llvm::ELF;
 using namespace lld;
 using namespace lld::elf;
 
+uint8_t *Out::BufferStart;
 uint8_t Out::First;
 PhdrEntry *Out::TlsPhdr;
 OutputSection *Out::ElfHeader;
@@ -222,8 +223,6 @@ template <class ELFT> void OutputSection
   if (Type == SHT_NOBITS)
     return;
 
-  Loc = Buf;
-
   // If -compress-debug-section is specified and if this is a debug seciton,
   // we've already compressed section contents. If that's the case,
   // just write it down.

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=355153&r1=355152&r2=355153&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Feb 28 15:11:35 2019
@@ -82,9 +82,6 @@ public:
 
   void addSection(InputSection *IS);
 
-  // Location in the output buffer.
-  uint8_t *Loc = nullptr;
-
   // The following members are normally only used in linker scripts.
   MemoryRegion *MemRegion = nullptr;
   MemoryRegion *LMARegion = nullptr;
@@ -128,6 +125,7 @@ std::vector<InputSection *> getInputSect
 // globally accessible. Writer initializes them, so don't use them
 // until Writer is initialized.
 struct Out {
+  static uint8_t *BufferStart;
   static uint8_t First;
   static PhdrEntry *TlsPhdr;
   static OutputSection *ElfHeader;

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=355153&r1=355152&r2=355153&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Thu Feb 28 15:11:35 2019
@@ -509,7 +509,7 @@ void EhFrameSection::finalizeContents()
 // to get an FDE from an address to which FDE is applied. This function
 // returns a list of such pairs.
 std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
-  uint8_t *Buf = getParent()->Loc + OutSecOff;
+  uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff;
   std::vector<FdeData> Ret;
 
   uint64_t VA = In.EhFrameHdr->getVA();
@@ -595,6 +595,9 @@ void EhFrameSection::writeTo(uint8_t *Bu
   // getOffset() takes care of discontiguous section pieces.
   for (EhInputSection *S : Sections)
     S->relocateAlloc(Buf, nullptr);
+
+  if (In.EhFrameHdr && In.EhFrameHdr->getParent())
+    In.EhFrameHdr->write();
 }
 
 GotSection::GotSection()
@@ -2667,11 +2670,20 @@ bool GdbIndexSection::empty() const { re
 EhFrameHeader::EhFrameHeader()
     : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
 
+void EhFrameHeader::writeTo(uint8_t *Buf) {
+  // Unlike most sections, the EhFrameHeader section is written while writing
+  // another section, namely EhFrameSection, which calls the write() function
+  // below from its writeTo() function. This is necessary because the contents
+  // of EhFrameHeader depend on the relocated contents of EhFrameSection and we
+  // don't know which order the sections will be written in.
+}
+
 // .eh_frame_hdr contains a binary search table of pointers to FDEs.
 // Each entry of the search table consists of two values,
 // the starting PC from where FDEs covers, and the FDE's address.
 // It is sorted by PC.
-void EhFrameHeader::writeTo(uint8_t *Buf) {
+void EhFrameHeader::write() {
+  uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff;
   typedef EhFrameSection::FdeData FdeData;
 
   std::vector<FdeData> Fdes = In.EhFrame->getFdeData();

Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=355153&r1=355152&r2=355153&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Thu Feb 28 15:11:35 2019
@@ -743,6 +743,7 @@ private:
 class EhFrameHeader final : public SyntheticSection {
 public:
   EhFrameHeader();
+  void write();
   void writeTo(uint8_t *Buf) override;
   size_t getSize() const override;
   bool empty() const override;

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=355153&r1=355152&r2=355153&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Thu Feb 28 15:11:35 2019
@@ -98,7 +98,7 @@ template <class ELFT> static ErrorPlace
     if (!IS->getParent())
       continue;
 
-    uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
+    uint8_t *ISLoc = Out::BufferStart + IS->getParent()->Offset + IS->OutSecOff;
     if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
       return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "};
   }

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=355153&r1=355152&r2=355153&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Feb 28 15:11:35 2019
@@ -2407,16 +2407,14 @@ static uint8_t getAbiVersion() {
 }
 
 template <class ELFT> void Writer<ELFT>::writeHeader() {
-  uint8_t *Buf = Buffer->getBufferStart();
-
   // For executable segments, the trap instructions are written before writing
   // the header. Setting Elf header bytes to zero ensures that any unused bytes
   // in header are zero-cleared, instead of having trap instructions.
-  memset(Buf, 0, sizeof(Elf_Ehdr));
-  memcpy(Buf, "\177ELF", 4);
+  memset(Out::BufferStart, 0, sizeof(Elf_Ehdr));
+  memcpy(Out::BufferStart, "\177ELF", 4);
 
   // Write the ELF header.
-  auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
+  auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Out::BufferStart);
   EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
   EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
   EHdr->e_ident[EI_VERSION] = EV_CURRENT;
@@ -2438,7 +2436,7 @@ template <class ELFT> void Writer<ELFT>:
   }
 
   // Write the program header table.
-  auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+  auto *HBuf = reinterpret_cast<Elf_Phdr *>(Out::BufferStart + EHdr->e_phoff);
   for (PhdrEntry *P : Phdrs) {
     HBuf->p_type = P->p_type;
     HBuf->p_flags = P->p_flags;
@@ -2460,7 +2458,7 @@ template <class ELFT> void Writer<ELFT>:
   // the value. The sentinel values and fields are:
   // e_shnum = 0, SHdrs[0].sh_size = number of sections.
   // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
-  auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+  auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Out::BufferStart + EHdr->e_shoff);
   size_t Num = OutputSections.size() + 1;
   if (Num >= SHN_LORESERVE)
     SHdrs->sh_size = Num;
@@ -2494,18 +2492,19 @@ template <class ELFT> void Writer<ELFT>:
   Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
       FileOutputBuffer::create(Config->OutputFile, FileSize, Flags);
 
-  if (!BufferOrErr)
+  if (!BufferOrErr) {
     error("failed to open " + Config->OutputFile + ": " +
           llvm::toString(BufferOrErr.takeError()));
-  else
-    Buffer = std::move(*BufferOrErr);
+    return;
+  }
+  Buffer = std::move(*BufferOrErr);
+  Out::BufferStart = Buffer->getBufferStart();
 }
 
 template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
-  uint8_t *Buf = Buffer->getBufferStart();
   for (OutputSection *Sec : OutputSections)
     if (Sec->Flags & SHF_ALLOC)
-      Sec->writeTo<ELFT>(Buf + Sec->Offset);
+      Sec->writeTo<ELFT>(Out::BufferStart + Sec->Offset);
 }
 
 static void fillTrap(uint8_t *I, uint8_t *End) {
@@ -2524,11 +2523,12 @@ template <class ELFT> void Writer<ELFT>:
     return;
 
   // Fill the last page.
-  uint8_t *Buf = Buffer->getBufferStart();
   for (PhdrEntry *P : Phdrs)
     if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
-      fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize),
-               Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize));
+      fillTrap(Out::BufferStart +
+                   alignDown(P->p_offset + P->p_filesz, Target->PageSize),
+               Out::BufferStart +
+                   alignTo(P->p_offset + P->p_filesz, Target->PageSize));
 
   // Round up the file size of the last segment to the page boundary iff it is
   // an executable segment to ensure that other tools don't accidentally
@@ -2544,27 +2544,16 @@ template <class ELFT> void Writer<ELFT>:
 
 // Write section contents to a mmap'ed file.
 template <class ELFT> void Writer<ELFT>::writeSections() {
-  uint8_t *Buf = Buffer->getBufferStart();
-
-  OutputSection *EhFrameHdr = nullptr;
-  if (In.EhFrameHdr && !In.EhFrameHdr->empty())
-    EhFrameHdr = In.EhFrameHdr->getParent();
-
   // In -r or -emit-relocs mode, write the relocation sections first as in
   // ELf_Rel targets we might find out that we need to modify the relocated
   // section while doing it.
   for (OutputSection *Sec : OutputSections)
     if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
-      Sec->writeTo<ELFT>(Buf + Sec->Offset);
+      Sec->writeTo<ELFT>(Out::BufferStart + Sec->Offset);
 
   for (OutputSection *Sec : OutputSections)
-    if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
-      Sec->writeTo<ELFT>(Buf + Sec->Offset);
-
-  // The .eh_frame_hdr depends on .eh_frame section contents, therefore
-  // it should be written after .eh_frame is written.
-  if (EhFrameHdr)
-    EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+    if (Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
+      Sec->writeTo<ELFT>(Out::BufferStart + Sec->Offset);
 }
 
 template <class ELFT> void Writer<ELFT>::writeBuildId() {
@@ -2572,9 +2561,7 @@ template <class ELFT> void Writer<ELFT>:
     return;
 
   // Compute a hash of all sections of the output file.
-  uint8_t *Start = Buffer->getBufferStart();
-  uint8_t *End = Start + FileSize;
-  In.BuildId->writeBuildId({Start, End});
+  In.BuildId->writeBuildId({Out::BufferStart, FileSize});
 }
 
 template void elf::writeResult<ELF32LE>();

Added: lld/trunk/test/ELF/linkerscript/eh-frame-merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/eh-frame-merge.s?rev=355153&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/eh-frame-merge.s (added)
+++ lld/trunk/test/ELF/linkerscript/eh-frame-merge.s Thu Feb 28 15:11:35 2019
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame) } }" > %t.script
+# RUN: ld.lld -o %t --no-threads --eh-frame-hdr --script %t.script %t.o
+# RUN: llvm-readobj -s -u %t | FileCheck %s
+
+# CHECK: Name: .dah
+# CHECK-NOT: Section
+# CHECK: Address: 0x4D
+
+# CHECK: initial_location: 0x4d
+
+.global _start
+_start:
+ nop
+
+.section .dah,"ax", at progbits
+.cfi_startproc
+ nop
+.cfi_endproc




More information about the llvm-commits mailing list