From 6600eb18cd4934e56f83e726c4ff5f04f123adae Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sat, 4 Jul 2015 23:37:32 +0000 Subject: [PATCH] COFF: Implement /merge option. /merge:.foo=.bar makes the linker to merge section .foo with section .bar. llvm-svn: 241396 --- lld/COFF/Config.h | 4 +++ lld/COFF/Driver.cpp | 12 ++++++++- lld/COFF/Driver.h | 1 + lld/COFF/DriverUtils.cpp | 17 +++++++++++++ lld/COFF/Writer.cpp | 26 +++++++++++++------- lld/test/COFF/merge.test | 53 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 lld/test/COFF/merge.test 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 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 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 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 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[,=]|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 "=". +// 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[,=]|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 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 &Chunks = P.second; + std::vector &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 +...