COFF: Implement /merge option.

/merge:.foo=.bar makes the linker to merge section .foo with section .bar.

llvm-svn: 241396
This commit is contained in:
Rui Ueyama 2015-07-04 23:37:32 +00:00
parent f73f8919ed
commit 6600eb18cd
6 changed files with 103 additions and 10 deletions

View File

@ -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;

View File

@ -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())) {

View File

@ -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);

View File

@ -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) {

View File

@ -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());

53
lld/test/COFF/merge.test Normal file
View File

@ -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
...