summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/Config.h4
-rw-r--r--lld/COFF/Driver.cpp32
-rw-r--r--lld/COFF/Options.td1
-rw-r--r--lld/COFF/Writer.cpp20
-rw-r--r--lld/test/COFF/Inputs/order.yaml76
-rw-r--r--lld/test/COFF/order-i386.test69
-rw-r--r--lld/test/COFF/order.test102
7 files changed, 304 insertions, 0 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 08a6bab3bc0..f98ed3fee3e 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -10,6 +10,7 @@
#ifndef LLD_COFF_CONFIG_H
#define LLD_COFF_CONFIG_H
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/CachePruning.h"
@@ -153,6 +154,9 @@ struct Configuration {
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
+ // Used for /order.
+ llvm::StringMap<int> Order;
+
// Used for /lldmap.
std::string MapFile;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index e9a76f7a6a3..1503a2c5d2b 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -14,6 +14,7 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
+#include "lld/Common/Args.h"
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@@ -756,6 +757,33 @@ bool LinkerDriver::run() {
return DidWork;
}
+// Parse an /order file. If an option is given, the linker places
+// COMDAT sections in the same order as their names appear in the
+// given file.
+static void parseOrderFile(StringRef Arg) {
+ // For some reason, the MSVC linker requires a filename to be
+ // preceded by "@".
+ if (!Arg.startswith("@")) {
+ error("malformed /order option: '@' missing");
+ return;
+ }
+
+ // Open a file.
+ StringRef Path = Arg.substr(1);
+ std::unique_ptr<MemoryBuffer> MB = CHECK(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+
+ // Parse a file. An order file contains one symbol per line.
+ // All symbols that were not present in a given order file are
+ // considered to have the lowest priority 0 and are placed at
+ // end of an output section.
+ for (std::string S : args::getLines(MB->getMemBufferRef())) {
+ if (Config->Machine == I386 && !isDecorated(S))
+ S = "_" + S;
+ Config->Order[S] = INT_MIN + Config->Order.size();
+ }
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
@@ -1160,6 +1188,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
}
+ // Handle /order
+ if (auto *Arg = Args.getLastArg(OPT_order))
+ parseOrderFile(Arg->getValue());
+
// Handle /export
for (auto *Arg : Args.filtered(OPT_export)) {
Export E = parseExport(Arg->getValue());
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 36650d082e0..50436da87fa 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -42,6 +42,7 @@ def merge : P<"merge", "Combine sections">;
def mllvm : P<"mllvm", "Options to pass to LLVM">;
def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
def opt : P<"opt", "Control optimizations">;
+def order : P<"order", "Put functions in order">;
def out : P<"out", "Path to file to write output">;
def pdb : P<"pdb", "PDB file path">;
def section : P<"section", "Specify section attributes">;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 256de12b2b5..7ce2db00a08 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -348,6 +348,21 @@ static StringRef getOutputSection(StringRef Name) {
return It->second;
}
+// For /order.
+static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
+ auto GetPriority = [](const Chunk *C) {
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ return Config->Order.lookup(Sec->Sym->getName());
+ return 0;
+ };
+
+ std::stable_sort(Chunks.begin(), Chunks.end(),
+ [=](const Chunk *A, const Chunk *B) {
+ return GetPriority(A) < GetPriority(B);
+ });
+}
+
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
// First, bin chunks by name.
@@ -362,6 +377,11 @@ void Writer::createSections() {
Map[C->getSectionName()].push_back(C);
}
+ // Process an /order option.
+ if (!Config->Order.empty())
+ for (auto &Pair : Map)
+ sortBySectionOrder(Pair.second);
+
// Then create an OutputSection for each section.
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
diff --git a/lld/test/COFF/Inputs/order.yaml b/lld/test/COFF/Inputs/order.yaml
new file mode 100644
index 00000000000..02e91d12261
--- /dev/null
+++ b/lld/test/COFF/Inputs/order.yaml
@@ -0,0 +1,76 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: unrelated2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 2
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn4
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn1
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/lld/test/COFF/order-i386.test b/lld/test/COFF/order-i386.test
new file mode 100644
index 00000000000..4cde5fa813f
--- /dev/null
+++ b/lld/test/COFF/order-i386.test
@@ -0,0 +1,69 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: echo fn1 > %t.order
+# RUN: echo fn2 >> %t.order
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \
+# RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s
+# CHECK: fn1
+# CHECK: fn2
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \
+# RUN: -lldmap:- -out:%t.exe | FileCheck -check-prefix=DEFAULT %s
+# DEFAULT: fn2
+# DEFAULT: fn1
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: '.text'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: CC
+ - Name: '.text'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: CC
+symbols:
+ - Name: '.text'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: '.text'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: _fn2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _fn1
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
+
diff --git a/lld/test/COFF/order.test b/lld/test/COFF/order.test
new file mode 100644
index 00000000000..25df87d7dba
--- /dev/null
+++ b/lld/test/COFF/order.test
@@ -0,0 +1,102 @@
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %p/Inputs/order.yaml > %t2.obj
+
+# RUN: echo fn1 > %t.order
+# RUN: echo fn2 >> %t.order
+# RUN: echo fn3 >> %t.order
+# RUN: echo fn4 >> %t.order
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref -debug %t1.obj %t2.obj \
+# RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s
+# CHECK: fn1
+# CHECK: fn2
+# CHECK: fn3
+# CHECK: fn4
+# CHECK: unrelated1
+# CHECK: unrelated2
+
+# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref -debug %t1.obj %t2.obj \
+# RUN: -lldmap:- -out:%t.exe | FileCheck -check-prefix=DEFAULT %s
+# DEFAULT: fn2
+# DEFAULT: fn3
+# DEFAULT: unrelated1
+# DEFAULT: unrelated2
+# DEFAULT: fn4
+# DEFAULT: fn1
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: fn3
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .text
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: unrelated1
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
OpenPOWER on IntegriCloud