[lld] r252868 - [ELF2] SECTIONS command basic support

Denis Protivensky via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 12 01:52:09 PST 2015


Author: denis-protivensky
Date: Thu Nov 12 03:52:08 2015
New Revision: 252868

URL: http://llvm.org/viewvc/llvm-project?rev=252868&view=rev
Log:
[ELF2] SECTIONS command basic support

* determine output section by input section name
* discard input sections
* order output sections accordingly

Differential Revision: http://reviews.llvm.org/D14140

Added:
    lld/trunk/test/elf2/linkerscript-sections.s
Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=252868&r1=252867&r2=252868&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Thu Nov 12 03:52:08 2015
@@ -10,6 +10,7 @@
 #ifndef LLD_ELF_CONFIG_H
 #define LLD_ELF_CONFIG_H
 
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/ELF.h"
 
@@ -41,6 +42,7 @@ struct Configuration {
   llvm::StringRef SoName;
   llvm::StringRef Sysroot;
   std::string RPath;
+  llvm::MapVector<llvm::StringRef, std::vector<llvm::StringRef>> OutputSections;
   std::vector<llvm::StringRef> SearchPaths;
   std::vector<llvm::StringRef> Undefined;
   bool AllowMultipleDefinition;

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=252868&r1=252867&r2=252868&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Thu Nov 12 03:52:08 2015
@@ -36,6 +36,7 @@ private:
   static std::vector<StringRef> tokenize(StringRef S);
   static StringRef skipSpace(StringRef S);
   StringRef next();
+  bool skip(StringRef Tok);
   bool atEOF() { return Tokens.size() == Pos; }
   void expect(StringRef Expect);
 
@@ -50,6 +51,9 @@ private:
   void readOutputArch();
   void readOutputFormat();
   void readSearchDir();
+  void readSections();
+
+  void readOutputSectionDescription();
 
   StringSaver Saver;
   std::vector<StringRef> Tokens;
@@ -78,6 +82,8 @@ void LinkerScript::run() {
       readOutputFormat();
     } else if (Tok == "SEARCH_DIR") {
       readSearchDir();
+    } else if (Tok == "SECTIONS") {
+      readSections();
     } else {
       error("unknown directive: " + Tok);
     }
@@ -133,11 +139,20 @@ StringRef LinkerScript::skipSpace(String
 }
 
 StringRef LinkerScript::next() {
-  if (Pos == Tokens.size())
+  if (atEOF())
     error("unexpected EOF");
   return Tokens[Pos++];
 }
 
+bool LinkerScript::skip(StringRef Tok) {
+  if (atEOF())
+    error("unexpected EOF");
+  if (Tok != Tokens[Pos])
+    return false;
+  ++Pos;
+  return true;
+}
+
 void LinkerScript::expect(StringRef Expect) {
   StringRef Tok = next();
   if (Tok != Expect)
@@ -255,6 +270,26 @@ void LinkerScript::readSearchDir() {
   expect(")");
 }
 
+void LinkerScript::readSections() {
+  expect("{");
+  while (!skip("}"))
+    readOutputSectionDescription();
+}
+
+void LinkerScript::readOutputSectionDescription() {
+  StringRef Name = next();
+  std::vector<StringRef> &InputSections = Config->OutputSections[Name];
+
+  expect(":");
+  expect("{");
+  while (!skip("}")) {
+    next(); // Skip input file name.
+    expect("(");
+    while (!skip(")"))
+      InputSections.push_back(next());
+  }
+}
+
 // Entry point. The other functions or classes are private to this file.
 void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
   LinkerScript(A, MB.getBuffer()).run();

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=252868&r1=252867&r2=252868&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Nov 12 03:52:08 2015
@@ -13,6 +13,7 @@
 #include "SymbolTable.h"
 #include "Target.h"
 
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/FileOutputBuffer.h"
 #include "llvm/Support/StringSaver.h"
@@ -47,9 +48,12 @@ private:
   void scanRelocs(InputSection<ELFT> &C);
   void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
   void assignAddresses();
+  void buildSectionMap();
   void openFile(StringRef OutputPath);
   void writeHeader();
   void writeSections();
+  bool isDiscarded(InputSectionBase<ELFT> *IS) const;
+  StringRef getOutputSectionName(StringRef S) const;
   bool needsInterpSection() const {
     return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
   }
@@ -82,6 +86,8 @@ private:
 
   uintX_t FileSize;
   uintX_t SectionHeaderOff;
+
+  llvm::StringMap<llvm::StringRef> InputToOutputSection;
 };
 } // anonymous namespace
 
@@ -131,6 +137,7 @@ template <class ELFT> void lld::elf2::wr
 
 // The main function of the writer.
 template <class ELFT> void Writer<ELFT>::run() {
+  buildSectionMap();
   if (!Config->DiscardAll)
     copyLocalSymbols();
   createSections();
@@ -461,7 +468,12 @@ void Writer<ELFT>::addSharedCopySymbols(
   Out<ELFT>::Bss->setSize(Off);
 }
 
-static StringRef getOutputName(StringRef S) {
+template <class ELFT>
+StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {
+  auto It = InputToOutputSection.find(S);
+  if (It != std::end(InputToOutputSection))
+    return It->second;
+
   if (S.startswith(".text."))
     return ".text";
   if (S.startswith(".rodata."))
@@ -473,6 +485,27 @@ static StringRef getOutputName(StringRef
   return S;
 }
 
+template <class ELFT>
+bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *IS) const {
+  if (!IS || !IS->isLive() || IS == &InputSection<ELFT>::Discarded)
+    return true;
+  return InputToOutputSection.lookup(IS->getSectionName()) == "/DISCARD/";
+}
+
+template <class ELFT>
+static bool compareSections(OutputSectionBase<ELFT> *A,
+                            OutputSectionBase<ELFT> *B) {
+  auto ItA = Config->OutputSections.find(A->getName());
+  auto ItEnd = std::end(Config->OutputSections);
+  if (ItA == ItEnd)
+    return compareOutputSections(A, B);
+  auto ItB = Config->OutputSections.find(B->getName());
+  if (ItB == ItEnd)
+    return compareOutputSections(A, B);
+
+  return std::distance(ItA, ItB) > 0;
+}
+
 // Create output section objects and add them to OutputSections.
 template <class ELFT> void Writer<ELFT>::createSections() {
   // .interp needs to be on the first page in the output file.
@@ -485,7 +518,7 @@ template <class ELFT> void Writer<ELFT>:
 
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
     for (InputSectionBase<ELFT> *C : F->getSections()) {
-      if (!C || !C->isLive() || C == &InputSection<ELFT>::Discarded)
+      if (isDiscarded(C))
         continue;
       const Elf_Shdr *H = C->getSectionHdr();
       uintX_t OutFlags = H->sh_flags & ~SHF_GROUP;
@@ -498,7 +531,7 @@ template <class ELFT> void Writer<ELFT>:
       if (OutType == SHT_PROGBITS && C->getSectionName() == ".eh_frame" &&
           Config->EMachine == EM_X86_64)
         OutType = SHT_X86_64_UNWIND;
-      SectionKey<ELFT::Is64Bits> Key{getOutputName(C->getSectionName()),
+      SectionKey<ELFT::Is64Bits> Key{getOutputSectionName(C->getSectionName()),
                                      OutType, OutFlags, EntSize};
       OutputSectionBase<ELFT> *&Sec = Map[Key];
       if (!Sec) {
@@ -577,14 +610,14 @@ template <class ELFT> void Writer<ELFT>:
   // Scan relocations. This must be done after every symbol is declared so that
   // we can correctly decide if a dynamic relocation is needed.
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
-    for (InputSectionBase<ELFT> *B : F->getSections()) {
-      if (auto *S = dyn_cast_or_null<InputSection<ELFT>>(B)) {
-        if (S != &InputSection<ELFT>::Discarded && S->isLive())
-          scanRelocs(*S);
-      } else if (auto *S = dyn_cast_or_null<EHInputSection<ELFT>>(B)) {
+    for (InputSectionBase<ELFT> *C : F->getSections()) {
+      if (isDiscarded(C))
+        continue;
+      if (auto *S = dyn_cast<InputSection<ELFT>>(C))
+        scanRelocs(*S);
+      else if (auto *S = dyn_cast<EHInputSection<ELFT>>(C))
         if (S->RelocSection)
           scanRelocs(*S, *S->RelocSection);
-      }
     }
   }
 
@@ -656,7 +689,7 @@ template <class ELFT> void Writer<ELFT>:
     OutputSections.push_back(Out<ELFT>::Plt);
 
   std::stable_sort(OutputSections.begin(), OutputSections.end(),
-                   compareOutputSections<ELFT>);
+                   compareSections<ELFT>);
 
   for (unsigned I = 0, N = OutputSections.size(); I < N; ++I)
     OutputSections[I]->SectionIndex = I + 1;
@@ -952,6 +985,13 @@ void Writer<ELFT>::copyPhdr(Elf_Phdr *PH
   PH->p_align = From->getAlign();
 }
 
+template <class ELFT> void Writer<ELFT>::buildSectionMap() {
+  for (const std::pair<StringRef, std::vector<StringRef>> &OutSec :
+       Config->OutputSections)
+    for (StringRef Name : OutSec.second)
+      InputToOutputSection[Name] = OutSec.first;
+}
+
 template void lld::elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
 template void lld::elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
 template void lld::elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);

Added: lld/trunk/test/elf2/linkerscript-sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/linkerscript-sections.s?rev=252868&view=auto
==============================================================================
--- lld/trunk/test/elf2/linkerscript-sections.s (added)
+++ lld/trunk/test/elf2/linkerscript-sections.s Thu Nov 12 03:52:08 2015
@@ -0,0 +1,119 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Empty SECTIONS command.
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld2 -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+# SECTIONS command with the same order as default.
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } }" \ > %t.script
+# RUN: ld.lld2 -o %t2 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+#             Idx Name          Size
+# SEC-DEFAULT: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DEFAULT: 2 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-DEFAULT: 5 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-DEFAULT: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-DEFAULT: 7 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-DEFAULT: 8 .strtab       00000008 {{[0-9a-f]*}}
+
+# Sections are put in order specified in linker script.
+# RUN: echo "SECTIONS { \
+# RUN:          .bss : { *(.bss) } \
+# RUN:          other : { *(other) } \
+# RUN:          .shstrtab : { *(.shstrtab) } \
+# RUN:          .symtab : { *(.symtab) } \
+# RUN:          .strtab : { *(.strtab) } \
+# RUN:          .data : { *(.data) } \
+# RUN:          .text : { *(.text) } }" \ > %t.script
+# RUN: ld.lld2 -o %t3 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t3 | \
+# RUN:   FileCheck -check-prefix=SEC-ORDER %s
+
+#           Idx Name          Size
+# SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 3 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-ORDER: 4 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-ORDER: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-ORDER: 6 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 7 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 8 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+
+# .text and .data have swapped names but proper sizes and types.
+# RUN: echo "SECTIONS { \
+# RUN:          .data : { *(.text) } \
+# RUN:          .text : { *(.data) } }" \ > %t.script
+# RUN: ld.lld2 -o %t4 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t4 | \
+# RUN:   FileCheck -check-prefix=SEC-SWAP-NAMES %s
+
+#                Idx Name          Size
+# SEC-SWAP-NAMES: 1 .data         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-SWAP-NAMES: 2 .text         00000020 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-SWAP-NAMES: 5 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 7 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 8 .strtab       00000008 {{[0-9a-f]*}}
+
+# .shstrtab from the input object file is discarded.
+# RUN: echo "SECTIONS { \
+# RUN:          /DISCARD/ : { *(.shstrtab) } }" \ > %t.script
+# RUN: ld.lld2 -o %t5 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t5 | \
+# RUN:   FileCheck -check-prefix=SEC-DISCARD %s
+
+#             Idx Name          Size
+# SEC-DISCARD: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DISCARD: 2 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-DISCARD: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-DISCARD: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-DISCARD: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-DISCARD: 6 .shstrtab     00000032 {{[0-9a-f]*}}
+# SEC-DISCARD: 7 .strtab       00000008 {{[0-9a-f]*}}
+
+# Multiple SECTIONS command specifying additional input section descriptions
+# for the same output section description - input sections are merged into
+# one output section.
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } } \
+# RUN:       SECTIONS { \
+# RUN:          .data : { *(other) } }" \ > %t.script
+# RUN: ld.lld2 -o %t6 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t6 | \
+# RUN:   FileCheck -check-prefix=SEC-MULTI %s
+
+#           Idx Name          Size
+# SEC-MULTI: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-MULTI: 2 .data         00000023 {{[0-9a-f]*}} DATA
+# SEC-MULTI: 3 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-MULTI: 4 .shstrtab     00000002 {{[0-9a-f]*}}
+# SEC-MULTI: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-MULTI: 6 .shstrtab     0000002c {{[0-9a-f]*}}
+# SEC-MULTI: 7 .strtab       00000008 {{[0-9a-f]*}}
+
+.globl _start;
+_start:
+    mov $60, %rax
+    mov $42, %rdi
+
+.section .data,"aw"
+.quad 10, 10, 20, 20
+.section other,"aw"
+.short 10
+.byte 20
+.section .shstrtab,""
+.short 20
+.section .bss,"", at nobits
+.short 0




More information about the llvm-commits mailing list