Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2015-07-05 02:37:32 +0300
committerRui Ueyama <ruiu@google.com>2015-07-05 02:37:32 +0300
commit6600eb18cd4934e56f83e726c4ff5f04f123adae (patch)
treee8aa9e3e154423937f677695c065856ac5ffa45f /lld
parentf73f8919ed9a2e91cbdb10e1ecdf688066c597b7 (diff)
COFF: Implement /merge option.
/merge:.foo=.bar makes the linker to merge section .foo with section .bar. llvm-svn: 241396
Diffstat (limited to 'lld')
-rw-r--r--lld/COFF/Config.h4
-rw-r--r--lld/COFF/Driver.cpp12
-rw-r--r--lld/COFF/Driver.h1
-rw-r--r--lld/COFF/DriverUtils.cpp17
-rw-r--r--lld/COFF/Writer.cpp26
-rw-r--r--lld/test/COFF/merge.test53
6 files changed, 103 insertions, 10 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 578152ed8243..c94134ad274a 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -54,6 +54,7 @@ struct Configuration {
bool DoGC = true;
bool Relocatable = true;
bool Force = false;
+ bool Debug = false;
// Symbols in this set are considered as live by the garbage collector.
std::set<Undefined *> GCRoot;
@@ -70,6 +71,9 @@ struct Configuration {
// Used for /opt:icf
bool ICF = false;
+ // Used for /merge:from=to (e.g. /merge:.rdata=.text)
+ std::map<StringRef, StringRef> Merge;
+
// Options for manifest files.
ManifestKind Manifest = SideBySide;
int ManifestID = 1;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index af80b4602549..fa29d14678bf 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -121,7 +121,8 @@ LinkerDriver::parseDirectives(StringRef S) {
addUndefined(Arg->getValue());
break;
case OPT_merge:
- // Ignore /merge for now.
+ if (auto EC = parseMerge(Arg->getValue()))
+ return EC;
break;
case OPT_nodefaultlib:
Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
@@ -290,6 +291,10 @@ bool LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_entry))
Config->Entry = addUndefined(Arg->getValue());
+ // Handle /debug
+ if (Args.hasArg(OPT_debug))
+ Config->Debug = true;
+
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
if (!Args.hasArg(OPT_dll)) {
@@ -442,6 +447,11 @@ bool LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
return false;
}
+ // Handle /merge
+ for (auto *Arg : Args.filtered(OPT_merge))
+ if (parseMerge(Arg->getValue()))
+ return false;
+
// Handle /manifest
if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) {
if (auto EC = parseManifest(Arg->getValue())) {
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 3bb5682bd1ac..12ff37c91eb5 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -132,6 +132,7 @@ std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
uint32_t *Major, uint32_t *Minor);
std::error_code parseAlternateName(StringRef);
+std::error_code parseMerge(StringRef);
// Parses a string in the form of "EMBED[,=<integer>]|NO".
std::error_code parseManifest(StringRef Arg);
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 2cd3684cbdbf..1542256fdefd 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -172,6 +172,23 @@ std::error_code parseAlternateName(StringRef S) {
return std::error_code();
}
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+std::error_code parseMerge(StringRef S) {
+ StringRef From, To;
+ std::tie(From, To) = S.split('=');
+ if (From.empty() || To.empty()) {
+ llvm::errs() << "/merge: invalid argument: " << S << "\n";
+ return make_error_code(LLDError::InvalidOption);
+ }
+ auto Pair = Config->Merge.insert(std::make_pair(From, To));
+ bool Inserted = Pair.second;
+ if (!Inserted)
+ llvm::errs() << "warning: " << S << ": already merged into "
+ << Pair.first->second << "\n";
+ return std::error_code();
+}
+
// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to Config.
std::error_code parseManifest(StringRef Arg) {
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 0d17bc1d2303..062f63111429 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -158,6 +158,16 @@ void Writer::dedupCOMDATs() {
doICF(Symtab->getChunks());
}
+static StringRef getOutputSection(StringRef Name) {
+ StringRef S = Name.split('$').first;
+ if (Config->Debug)
+ return S;
+ auto It = Config->Merge.find(S);
+ if (It == Config->Merge.end())
+ return S;
+ return It->second;
+}
+
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
// First, bin chunks by name.
@@ -178,18 +188,16 @@ void Writer::createSections() {
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
// contributes to .text, for example. See PE/COFF spec 3.2.
- StringRef Name = Map.begin()->first.split('$').first;
- auto Sec = new (CAlloc.Allocate()) OutputSection(Name, 0);
- OutputSections.push_back(Sec);
- for (auto &P : Map) {
- StringRef SectionName = P.first;
- StringRef Base = SectionName.split('$').first;
- if (Base != Sec->getName()) {
+ std::map<StringRef, OutputSection *> Sections;
+ for (auto Pair : Map) {
+ StringRef Name = getOutputSection(Pair.first);
+ OutputSection *&Sec = Sections[Name];
+ if (!Sec) {
size_t SectIdx = OutputSections.size();
- Sec = new (CAlloc.Allocate()) OutputSection(Base, SectIdx);
+ Sec = new (CAlloc.Allocate()) OutputSection(Name, SectIdx);
OutputSections.push_back(Sec);
}
- std::vector<Chunk *> &Chunks = P.second;
+ std::vector<Chunk *> &Chunks = Pair.second;
for (Chunk *C : Chunks) {
Sec->addChunk(C);
Sec->addPermissions(C->getPermissions());
diff --git a/lld/test/COFF/merge.test b/lld/test/COFF/merge.test
new file mode 100644
index 000000000000..58113ca05f2b
--- /dev/null
+++ b/lld/test/COFF/merge.test
@@ -0,0 +1,53 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld -flavor link2 /out:%t.exe /entry:main /subsystem:console /force \
+# RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .def
+# CHECK: Name: .abc
+
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .foo
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 000000000000
+ - Name: .bar
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 000000000000
+symbols:
+ - Name: .foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .bar
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...