[lld] r247925 - [elf2] Combine adjacent compatible OutputSections in PT_LOADs.

Michael J. Spencer via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 17 12:58:07 PDT 2015


Author: mspencer
Date: Thu Sep 17 14:58:07 2015
New Revision: 247925

URL: http://llvm.org/viewvc/llvm-project?rev=247925&view=rev
Log:
[elf2] Combine adjacent compatible OutputSections in PT_LOADs.

Added:
    lld/trunk/test/elf2/program-header-layout.s
Modified:
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/elf2/dynamic-reloc.s
    lld/trunk/test/elf2/relocation.s
    lld/trunk/test/elf2/shared.s

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Sep 17 14:58:07 2015
@@ -446,6 +446,57 @@ private:
   SymbolTable &SymTab;
 };
 
+static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) {
+  uint32_t Ret = PF_R;
+  if (Flags & SHF_WRITE)
+    Ret |= PF_W;
+
+  if (Flags & SHF_EXECINSTR)
+    Ret |= PF_X;
+
+  return Ret;
+}
+
+template <bool Is64Bits>
+class ProgramHeader {
+public:
+  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
+  typedef
+    typename std::conditional<Is64Bits, Elf64_Phdr, Elf32_Phdr>::type HeaderT;
+
+  ProgramHeader(uintX_t p_type, uintX_t p_flags) {
+    std::memset(&Header, 0, sizeof(HeaderT));
+    Header.p_type = p_type;
+    Header.p_flags = p_flags;
+    Header.p_align = PageSize;
+  }
+
+  void setValuesFromSection(OutputSectionBase<Is64Bits> &Sec) {
+    Header.p_flags = convertSectionFlagsToPHDRFlags(Sec.getFlags());
+    Header.p_offset = Sec.getFileOff();
+    Header.p_vaddr = Sec.getVA();
+    Header.p_paddr = Header.p_vaddr;
+    Header.p_filesz = Sec.getSize();
+    Header.p_memsz = Header.p_filesz;
+    Header.p_align = Sec.getAlign();
+  }
+
+  template <endianness E>
+  void writeHeaderTo(typename ELFFile<ELFType<E, Is64Bits>>::Elf_Phdr *PHDR) {
+    PHDR->p_type = Header.p_type;
+    PHDR->p_flags = Header.p_flags;
+    PHDR->p_offset = Header.p_offset;
+    PHDR->p_vaddr = Header.p_vaddr;
+    PHDR->p_paddr = Header.p_paddr;
+    PHDR->p_filesz = Header.p_filesz;
+    PHDR->p_memsz = Header.p_memsz;
+    PHDR->p_align = Header.p_align;
+  }
+
+  HeaderT Header;
+  bool Closed = false;
+};
+
 // The writer writes a SymbolTable result to a file.
 template <class ELFT> class Writer {
 public:
@@ -487,14 +538,20 @@ private:
   unsigned getVAStart() const { return Config->Shared ? 0 : VAStart; }
 
   std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+
   llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
   std::vector<OutputSectionBase<ELFT::Is64Bits> *> OutputSections;
   unsigned getNumSections() const { return OutputSections.size() + 1; }
 
+  llvm::BumpPtrAllocator PAlloc;
+  std::vector<ProgramHeader<ELFT::Is64Bits> *> PHDRs;
+  ProgramHeader<ELFT::Is64Bits> FileHeaderPHDR{PT_LOAD, PF_R};
+  ProgramHeader<ELFT::Is64Bits> InterpPHDR{PT_INTERP, 0};
+  ProgramHeader<ELFT::Is64Bits> DynamicPHDR{PT_DYNAMIC, 0};
+
   uintX_t FileSize;
   uintX_t ProgramHeaderOff;
   uintX_t SectionHeaderOff;
-  unsigned NumPhdrs;
 
   StringTableSection<ELFT::Is64Bits> StrTabSec = { /*dynamic=*/false };
   StringTableSection<ELFT::Is64Bits> DynStrSec = { /*dynamic=*/true };
@@ -950,12 +1007,13 @@ template <class ELFT> void Writer<ELFT>:
 
 template <class ELFT>
 static bool outputSectionHasPHDR(OutputSectionBase<ELFT::Is64Bits> *Sec) {
-  return (Sec->getSize() != 0) && (Sec->getFlags() & SHF_ALLOC);
+  return Sec->getFlags() & SHF_ALLOC;
 }
 
 // Visits all sections to assign incremental, non-overlapping RVAs and
 // file offsets.
 template <class ELFT> void Writer<ELFT>::assignAddresses() {
+  assert(!OutputSections.empty() && "No output sections to layout!");
   uintX_t VA = getVAStart();
   uintX_t FileOff = 0;
 
@@ -967,26 +1025,41 @@ template <class ELFT> void Writer<ELFT>:
   FileOff = RoundUpToAlignment(FileOff, PageSize);
   VA = RoundUpToAlignment(VA, PageSize);
 
-  NumPhdrs = 0;
-
-  // Add a PHDR for PT_INTERP.
   if (needsInterpSection())
-    ++NumPhdrs;
+    PHDRs.push_back(&InterpPHDR);
 
-  // Add a PHDR for the elf header and program headers. Some dynamic linkers
-  // (musl at least) require them to be covered by a PT_LOAD.
-  ++NumPhdrs;
+  ProgramHeader<ELFT::Is64Bits> *LastPHDR = &FileHeaderPHDR;
+  // Create a PHDR for the file header.
+  PHDRs.push_back(&FileHeaderPHDR);
+  FileHeaderPHDR.Header.p_vaddr = getVAStart();
+  FileHeaderPHDR.Header.p_paddr = getVAStart();
+  FileHeaderPHDR.Header.p_align = PageSize;
 
   for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections) {
     StrTabSec.add(Sec->getName());
     Sec->finalize();
 
-    // Since each output section gets its own PHDR, align each output section to
-    // a page.
-    if (outputSectionHasPHDR<ELFT>(Sec)) {
-      ++NumPhdrs;
-      VA = RoundUpToAlignment(VA, PageSize);
-      FileOff = RoundUpToAlignment(FileOff, PageSize);
+    if (Sec->getSize()) {
+      uintX_t Flags = convertSectionFlagsToPHDRFlags(Sec->getFlags());
+      if (LastPHDR->Header.p_flags != Flags ||
+          !outputSectionHasPHDR<ELFT>(Sec)) {
+        // Flags changed. End current PHDR and potentially create a new one.
+        if (!LastPHDR->Closed) {
+          LastPHDR->Header.p_filesz = FileOff - LastPHDR->Header.p_offset;
+          LastPHDR->Header.p_memsz = VA - LastPHDR->Header.p_vaddr;
+          LastPHDR->Closed = true;
+        }
+
+        if (outputSectionHasPHDR<ELFT>(Sec)) {
+          LastPHDR = new (PAlloc) ProgramHeader<ELFT::Is64Bits>(PT_LOAD, Flags);
+          PHDRs.push_back(LastPHDR);
+          VA = RoundUpToAlignment(VA, PageSize);
+          FileOff = RoundUpToAlignment(FileOff, PageSize);
+          LastPHDR->Header.p_offset = FileOff;
+          LastPHDR->Header.p_vaddr = VA;
+          LastPHDR->Header.p_paddr = VA;
+        }
+      }
     }
 
     uintX_t Align = Sec->getAlign();
@@ -1004,7 +1077,7 @@ template <class ELFT> void Writer<ELFT>:
 
   // Add a PHDR for the dynamic table.
   if (needsDynamicSections())
-    ++NumPhdrs;
+    PHDRs.push_back(&DynamicPHDR);
 
   FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
 
@@ -1014,29 +1087,6 @@ template <class ELFT> void Writer<ELFT>:
   FileSize = FileOff;
 }
 
-static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) {
-  uint32_t Ret = PF_R;
-  if (Flags & SHF_WRITE)
-    Ret |= PF_W;
-
-  if (Flags & SHF_EXECINSTR)
-    Ret |= PF_X;
-
-  return Ret;
-}
-
-template <class ELFT>
-static void setValuesFromSection(typename ELFFile<ELFT>::Elf_Phdr &P,
-                                 OutputSectionBase<ELFT::Is64Bits> &S) {
-  P.p_flags = convertSectionFlagsToPHDRFlags(S.getFlags());
-  P.p_offset = S.getFileOff();
-  P.p_vaddr = S.getVA();
-  P.p_paddr = P.p_vaddr;
-  P.p_filesz = S.getSize();
-  P.p_memsz = P.p_filesz;
-  P.p_align = S.getAlign();
-}
-
 template <class ELFT> void Writer<ELFT>::writeHeader() {
   uint8_t *Buf = Buffer->getBufferStart();
   auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
@@ -1065,46 +1115,24 @@ template <class ELFT> void Writer<ELFT>:
   EHdr->e_shoff = SectionHeaderOff;
   EHdr->e_ehsize = sizeof(Elf_Ehdr);
   EHdr->e_phentsize = sizeof(Elf_Phdr);
-  EHdr->e_phnum = NumPhdrs;
+  EHdr->e_phnum = PHDRs.size();
   EHdr->e_shentsize = sizeof(Elf_Shdr);
   EHdr->e_shnum = getNumSections();
   EHdr->e_shstrndx = StrTabSec.getSectionIndex();
 
-  auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
-  if (needsInterpSection()) {
-    PHdrs->p_type = PT_INTERP;
-    setValuesFromSection<ELFT>(*PHdrs, InterpSec);
-    ++PHdrs;
-  }
-
-  PHdrs->p_type = PT_LOAD;
-  PHdrs->p_flags = PF_R;
-  PHdrs->p_offset = 0;
-  PHdrs->p_vaddr = getVAStart();
-  PHdrs->p_paddr = PHdrs->p_vaddr;
-  PHdrs->p_filesz = ProgramHeaderOff + NumPhdrs * sizeof(Elf_Phdr);
-  PHdrs->p_memsz = PHdrs->p_filesz;
-  PHdrs->p_align = PageSize;
-  ++PHdrs;
+  // If nothing was merged into the file header PT_LOAD, set the size correctly.
+  if (FileHeaderPHDR.Header.p_filesz == PageSize)
+    FileHeaderPHDR.Header.p_filesz = FileHeaderPHDR.Header.p_memsz =
+        sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * PHDRs.size();
 
-  for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections) {
-    if (!outputSectionHasPHDR<ELFT>(Sec))
-      continue;
-    PHdrs->p_type = PT_LOAD;
-    PHdrs->p_flags = convertSectionFlagsToPHDRFlags(Sec->getFlags());
-    PHdrs->p_offset = Sec->getFileOff();
-    PHdrs->p_vaddr = Sec->getVA();
-    PHdrs->p_paddr = PHdrs->p_vaddr;
-    PHdrs->p_filesz = Sec->getType() == SHT_NOBITS ? 0 : Sec->getSize();
-    PHdrs->p_memsz = Sec->getSize();
-    PHdrs->p_align = PageSize;
-    ++PHdrs;
-  }
+  if (needsInterpSection())
+    InterpPHDR.setValuesFromSection(InterpSec);
+  if (needsDynamicSections())
+    DynamicPHDR.setValuesFromSection(DynamicSec);
 
-  if (needsDynamicSections()) {
-    PHdrs->p_type = PT_DYNAMIC;
-    setValuesFromSection<ELFT>(*PHdrs, DynamicSec);
-  }
+  auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+  for (ProgramHeader<ELFT::Is64Bits> *PHDR : PHDRs)
+    PHDR->template writeHeaderTo<ELFT::TargetEndianness>(PHdrs++);
 
   auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
   // First entry is null.

Modified: lld/trunk/test/elf2/dynamic-reloc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/dynamic-reloc.s?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/test/elf2/dynamic-reloc.s (original)
+++ lld/trunk/test/elf2/dynamic-reloc.s Thu Sep 17 14:58:07 2015
@@ -22,7 +22,7 @@
 // CHECK-NEXT:   SHF_ALLOC
 // CHECK-NEXT: ]
 // CHECK-NEXT: Address: [[RELAADDR:.*]]
-// CHECK-NEXT: Offset: 0x6000
+// CHECK-NEXT: Offset: 0x4058
 // CHECK-NEXT: Size: [[RELASIZE:.*]]
 // CHECK-NEXT: Link: 4
 // CHECK-NEXT: Info: 0

Added: lld/trunk/test/elf2/program-header-layout.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/program-header-layout.s?rev=247925&view=auto
==============================================================================
--- lld/trunk/test/elf2/program-header-layout.s (added)
+++ lld/trunk/test/elf2/program-header-layout.s Thu Sep 17 14:58:07 2015
@@ -0,0 +1,46 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: lld -flavor gnu2 %t -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+# Check that different output sections with the same flags are merged into a
+# single Read/Write PT_LOAD.
+
+.section .r,"a"
+.globl _start
+_start:
+.quad 0
+
+.section .a,"aw"
+.quad 1
+
+.section .b,"aw"
+.quad 2
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize:
+# CHECK-NEXT:     MemSize:
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize: 16
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]

Modified: lld/trunk/test/elf2/relocation.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation.s?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/test/elf2/relocation.s (original)
+++ lld/trunk/test/elf2/relocation.s Thu Sep 17 14:58:07 2015
@@ -33,7 +33,7 @@ R_X86_64_32:
 // constants in hex.
 // CHECK: Disassembly of section .text2:
 // CHECK-NEXT: R_X86_64_32:
-// CHECK-NEXT:  12000: {{.*}} movl $73728, %edx
+// CHECK-NEXT:  1100c: {{.*}} movl $69644, %edx
 
 .section .R_X86_64_32S,"ax", at progbits
 .global R_X86_64_32S
@@ -50,4 +50,4 @@ R_X86_64_64:
  .quad R_X86_64_64
 
 // CHECK:      Contents of section .R_X86_64_64:
-// CHECK-NEXT:   14000 00400100 00000000
+// CHECK-NEXT:   12000 00200100 00000000

Modified: lld/trunk/test/elf2/shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/shared.s?rev=247925&r1=247924&r2=247925&view=diff
==============================================================================
--- lld/trunk/test/elf2/shared.s (original)
+++ lld/trunk/test/elf2/shared.s Thu Sep 17 14:58:07 2015
@@ -12,7 +12,7 @@
 // SO-NEXT: Flags [
 // SO-NEXT: ]
 // SO-NEXT: Address:
-// SO-NEXT: Offset: 0x400C
+// SO-NEXT: Offset: 0x300C
 // SO-NEXT: Size:
 // SO-NEXT: Link:
 // SO-NEXT: Info:
@@ -44,7 +44,7 @@
 // CHECK-NEXT:     SHF_ALLOC
 // CHECK-NEXT:   ]
 // CHECK-NEXT:   Address: [[DYNSYMADDR:.*]]
-// CHECK-NEXT:   Offset: 0x3000
+// CHECK-NEXT:   Offset: 0x201C
 // CHECK-NEXT:   Size: 48
 // CHECK-NEXT:   Link: [[DYNSTR:.*]]
 // CHECK-NEXT:   Info: 1




More information about the llvm-commits mailing list