Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Add the /order option.
Browse files Browse the repository at this point in the history
With the /order option, you can give an order file. An order file
contains symbol names, one per line, and the linker places comdat
sections in that given order. The option is used often to optimize
an output binary for (in particular, startup) speed by improving
locality.

Differential Revision: https://reviews.llvm.org/D42598

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@323579 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
rui314 committed Jan 27, 2018
1 parent 49e62e6 commit ae1d72f
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 0 deletions.
4 changes: 4 additions & 0 deletions COFF/Config.h
Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down
32 changes: 32 additions & 0 deletions COFF/Driver.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions COFF/Options.td
Expand Up @@ -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">;
Expand Down
20 changes: 20 additions & 0 deletions COFF/Writer.cpp
Expand Up @@ -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.
Expand All @@ -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
Expand Down
76 changes: 76 additions & 0 deletions 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
...
69 changes: 69 additions & 0 deletions 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
...

102 changes: 102 additions & 0 deletions 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
...

0 comments on commit ae1d72f

Please sign in to comment.