Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/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 @@ // Used for /alternatename. std::map AlternateNames; + // Used for /order. + llvm::StringMap Order; + // Used for /lldmap. std::string MapFile; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/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 @@ 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 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 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 @@ } } + // 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()); Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -42,6 +42,7 @@ 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">; Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -348,6 +348,21 @@ return It->second; } +// For /order. +static void sortBySectionOrder(std::vector &Chunks) { + auto GetPriority = [](const Chunk *C) { + if (auto *Sec = dyn_cast(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 @@ 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 Index: lld/trunk/test/COFF/Inputs/order.yaml =================================================================== --- lld/trunk/test/COFF/Inputs/order.yaml +++ lld/trunk/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 +... Index: lld/trunk/test/COFF/order-i386.test =================================================================== --- lld/trunk/test/COFF/order-i386.test +++ lld/trunk/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 +... + Index: lld/trunk/test/COFF/order.test =================================================================== --- lld/trunk/test/COFF/order.test +++ lld/trunk/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 +...