[ELF2] Emit section table.
authorMichael J. Spencer <bigcheesegs@gmail.com>
Wed, 29 Jul 2015 00:30:10 +0000 (00:30 +0000)
committerMichael J. Spencer <bigcheesegs@gmail.com>
Wed, 29 Jul 2015 00:30:10 +0000 (00:30 +0000)
llvm-svn: 243506

lld/ELF/Chunks.h
lld/ELF/Writer.cpp
lld/ELF/Writer.h
lld/test/elf2/basic.test

index 3080502..836a980 100644 (file)
@@ -26,6 +26,8 @@ class OutputSection;
 // doesn't even have actual data (if common or bss).
 class Chunk {
 public:
+  enum Kind { SectionKind, OtherKind };
+  Kind kind() const { return ChunkKind; }
   virtual ~Chunk() = default;
 
   // Returns the size of this chunk (even if this is a common or BSS.)
@@ -54,6 +56,9 @@ public:
   OutputSection *getOutputSection() { return Out; }
 
 protected:
+  Chunk(Kind K = OtherKind) : ChunkKind(K) {}
+  const Kind ChunkKind;
+
   // The VA of this chunk in the output. The writer sets a value.
   uint64_t VA = 0;
 
@@ -78,6 +83,11 @@ public:
   size_t getSize() const override { return Header->sh_size; }
   void writeTo(uint8_t *Buf) override;
   StringRef getSectionName() const override { return SectionName; }
+  const Elf_Shdr *getSectionHdr() const { return Header; }
+
+  static bool classof(const Chunk *C) {
+    return C->kind() == SectionKind;
+  }
 
 private:
   // A file this chunk was created from.
index d11378f..615a5ef 100644 (file)
@@ -57,6 +57,22 @@ void OutputSection::addChunk(Chunk *C) {
   C->setFileOff(Off);
   Off += C->getSize();
   Header.sh_size = Off;
+  if (auto SC = dyn_cast<SectionChunk<ELF64LE>>(C))
+    Header.sh_type = SC->getSectionHdr()->sh_type;
+}
+
+template <class ELFT>
+void OutputSection::writeHeaderTo(Elf_Shdr_Impl<ELFT> *SHdr) {
+  SHdr->sh_name = Header.sh_name;
+  SHdr->sh_type = Header.sh_type;
+  SHdr->sh_flags = Header.sh_flags;
+  SHdr->sh_addr = Header.sh_addr;
+  SHdr->sh_offset = Header.sh_offset;
+  SHdr->sh_size = Header.sh_size;
+  SHdr->sh_link = Header.sh_link;
+  SHdr->sh_info = Header.sh_info;
+  SHdr->sh_addralign = Header.sh_addralign;
+  SHdr->sh_entsize = Header.sh_entsize;
 }
 
 // Create output section objects and add them to OutputSections.
@@ -75,10 +91,7 @@ template <class ELFT> void Writer<ELFT>::createSections() {
 // Visits all sections to assign incremental, non-overlapping RVAs and
 // file offsets.
 template <class ELFT> void Writer<ELFT>::assignAddresses() {
-  SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>) +
-                                         sizeof(Elf_Shdr_Impl<ELFT>) *
-                                             OutputSections.size(),
-                                     PageSize);
+  SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
   uint64_t VA = 0x1000; // The first page is kept unmapped.
   uint64_t FileOff = SizeOfHeaders;
   for (OutputSection *Sec : OutputSections) {
@@ -87,7 +100,9 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
     VA += RoundUpToAlignment(Sec->getSize(), PageSize);
     FileOff += RoundUpToAlignment(Sec->getSize(), 8);
   }
-  SizeOfImage = SizeOfHeaders + RoundUpToAlignment(VA - 0x1000, PageSize);
+  // Add space for section headers.
+  SectionHeaderOff = FileOff;
+  FileOff += (OutputSections.size() + 1) * sizeof(Elf_Shdr_Impl<ELFT>);
   FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
 }
 
@@ -108,12 +123,12 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
   EHdr->e_version = EV_CURRENT;
   EHdr->e_entry = 0x401000;
   EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
-  EHdr->e_shoff = 0;
+  EHdr->e_shoff = SectionHeaderOff;
   EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
   EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
   EHdr->e_phnum = 1;
   EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
-  EHdr->e_shnum = 0;
+  EHdr->e_shnum = OutputSections.size() + 1;
   EHdr->e_shstrndx = 0;
 
   auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
@@ -125,6 +140,12 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
   PHdrs->p_filesz = FileSize;
   PHdrs->p_memsz = FileSize;
   PHdrs->p_align = 0x4000;
+
+  auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
+  // First entry is null.
+  ++SHdrs;
+  for (OutputSection *Sec : OutputSections)
+    Sec->writeHeaderTo<ELFT>(SHdrs++);
 }
 
 template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
index f71c80f..55538eb 100644 (file)
@@ -27,6 +27,8 @@ public:
   void setFileOffset(uint64_t);
   void addChunk(Chunk *C);
   std::vector<Chunk *> &getChunks() { return Chunks; }
+  template <class ELFT>
+  void writeHeaderTo(llvm::object::Elf_Shdr_Impl<ELFT> *SHdr);
 
   // Returns the size of the section in the output file.
   uint64_t getSize() { return Header.sh_size; }
@@ -40,6 +42,8 @@ private:
 // The writer writes a SymbolTable result to a file.
 template <class ELFT> class Writer {
 public:
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+
   explicit Writer(SymbolTable<ELFT> *T);
   ~Writer();
   void write(StringRef Path);
@@ -57,8 +61,8 @@ private:
   std::vector<OutputSection *> OutputSections;
 
   uint64_t FileSize;
-  uint64_t SizeOfImage;
   uint64_t SizeOfHeaders;
+  uintX_t SectionHeaderOff;
 
   std::vector<std::unique_ptr<Chunk>> Chunks;
 };
index 39fb40f..8eec081 100644 (file)
@@ -1,6 +1,6 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 # RUN: lld -flavor gnu2 %t -o %t2
-# RUN: llvm-readobj -file-headers -program-headers %t2 | FileCheck %s
+# RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s
 # REQUIRES: x86
 
 # exits with return code 42 on linux
@@ -25,24 +25,82 @@ _start:
 # CHECK-NEXT:   Version: 1
 # CHECK-NEXT:   Entry: 0x401000
 # CHECK-NEXT:   ProgramHeaderOffset: 0x40
-# CHECK-NEXT:   SectionHeaderOffset: 0x0
+# CHECK-NEXT:   SectionHeaderOffset: 0x1010
 # CHECK-NEXT:   Flags [ (0x0)
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   HeaderSize: 64
 # CHECK-NEXT:   ProgramHeaderEntrySize: 56
 # CHECK-NEXT:   ProgramHeaderCount: 1
 # CHECK-NEXT:   SectionHeaderEntrySize: 64
-# CHECK-NEXT:   SectionHeaderCount: 0
+# CHECK-NEXT:   SectionHeaderCount: 4
 # CHECK-NEXT:    StringTableSectionIndex: 0
 # CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x1000
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     Size: 16
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x2000
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x2000
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
 # CHECK-NEXT: ProgramHeaders [
 # CHECK-NEXT:   ProgramHeader {
 # CHECK-NEXT:     Type: PT_LOAD (0x1)
 # CHECK-NEXT:     Offset: 0x0
 # CHECK-NEXT:     VirtualAddress: 0x400000
 # CHECK-NEXT:     PhysicalAddress: 0x400000
-# CHECK-NEXT:     FileSize: 4112
-# CHECK-NEXT:     MemSize: 4112
+# CHECK-NEXT:     FileSize: 4368
+# CHECK-NEXT:     MemSize: 4368
 # CHECK-NEXT:     Flags [ (0x5)
 # CHECK-NEXT:       PF_R (0x4)
 # CHECK-NEXT:       PF_X (0x1)