[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