[lld] r221545 - [mach-o] Add support for -order_file option
Nick Kledzik
kledzik at apple.com
Fri Nov 7 13:01:21 PST 2014
Author: kledzik
Date: Fri Nov 7 15:01:21 2014
New Revision: 221545
URL: http://llvm.org/viewvc/llvm-project?rev=221545&view=rev
Log:
[mach-o] Add support for -order_file option
The darwin linker lets you rearrange functions and data for better locality
(less paging). You do this with the -order_file option which supplies a text
file containing one symbol per line.
Implementing this required a small change to LayoutPass to add a custom sorter
hook.
Added:
lld/trunk/test/mach-o/Inputs/order_file-basic.order
lld/trunk/test/mach-o/order_file-basic.yaml
Modified:
lld/trunk/include/lld/Passes/LayoutPass.h
lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
lld/trunk/lib/Driver/DarwinLdDriver.cpp
lld/trunk/lib/Driver/DarwinLdOptions.td
lld/trunk/lib/Passes/LayoutPass.cpp
lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
Modified: lld/trunk/include/lld/Passes/LayoutPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Passes/LayoutPass.h?rev=221545&r1=221544&r2=221545&view=diff
==============================================================================
--- lld/trunk/include/lld/Passes/LayoutPass.h (original)
+++ lld/trunk/include/lld/Passes/LayoutPass.h Fri Nov 7 15:01:21 2014
@@ -37,7 +37,10 @@ public:
uint64_t _override;
};
- LayoutPass(const Registry ®istry);
+ typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right,
+ bool &leftBeforeRight)> SortOverride;
+
+ LayoutPass(const Registry ®istry, SortOverride sorter=nullptr);
/// Sorts atoms in mergedFile by content type then by command line order.
void perform(std::unique_ptr<MutableFile> &mergedFile) override;
@@ -57,6 +60,7 @@ private:
void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range);
const Registry &_registry;
+ SortOverride _customSorter;
typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=221545&r1=221544&r2=221545&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Fri Nov 7 15:01:21 2014
@@ -103,6 +103,8 @@ public:
_debugInfoMode = mode;
}
+ void appendOrderedSymbol(StringRef symbol, StringRef filename);
+
bool keepPrivateExterns() const { return _keepPrivateExterns; }
void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; }
bool demangleSymbols() const { return _demangle; }
@@ -282,8 +284,8 @@ private:
mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
void checkExportWhiteList(const DefinedAtom *atom) const;
void checkExportBlackList(const DefinedAtom *atom) const;
-
-
+ bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
+ bool &leftBeforeRight);
struct ArchInfo {
StringRef archName;
MachOLinkingContext::Arch arch;
@@ -298,6 +300,14 @@ private:
uint8_t align2;
};
+ struct OrderFileNode {
+ StringRef fileFilter;
+ unsigned order;
+ };
+
+ static bool findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+ const DefinedAtom *atom, unsigned &ordinal);
+
static ArchInfo _s_archInfos[];
std::set<StringRef> _existingPaths; // For testing only.
@@ -334,6 +344,8 @@ private:
llvm::StringSet<> _exportedSymbols;
DebugInfoMode _debugInfoMode;
std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
+ llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
+ unsigned _orderFileEntries;
};
} // end namespace lld
Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=221545&r1=221544&r2=221545&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Fri Nov 7 15:01:21 2014
@@ -120,6 +120,59 @@ static std::error_code parseExportsList(
return std::error_code();
}
+
+
+/// Order files are one symbol per line. Blank lines are ignored.
+/// Trailing comments start with #. Symbol names can be prefixed with an
+/// architecture name and/or .o leaf name. Examples:
+/// _foo
+/// bar.o:_bar
+/// libfrob.a(bar.o):_bar
+/// x86_64:_foo64
+static std::error_code parseOrderFile(StringRef orderFilePath,
+ MachOLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Map in order file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(orderFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(orderFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ buffer = lineAndRest.second;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ if (symAndComment.first.empty())
+ continue;
+ StringRef sym = symAndComment.first.trim();
+ if (sym.empty())
+ continue;
+ // Check for prefix.
+ StringRef prefix;
+ std::pair<StringRef, StringRef> prefixAndSym = sym.split(':');
+ if (!prefixAndSym.second.empty()) {
+ sym = prefixAndSym.second;
+ prefix = prefixAndSym.first;
+ if (!prefix.endswith(".o") && !prefix.endswith(".o)")) {
+ // If arch name prefix does not match arch being linked, ignore symbol.
+ if (!ctx.archName().equals(prefix))
+ continue;
+ prefix = "";
+ }
+ } else
+ sym = prefixAndSym.first;
+ if (!sym.empty()) {
+ ctx.appendOrderedSymbol(sym, prefix);
+ //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+ }
+ }
+ return std::error_code();
+}
+
//
// There are two variants of the -filelist option:
//
@@ -644,6 +697,18 @@ bool DarwinLdDriver::parse(int argc, con
if (parsedArgs->hasArg(OPT_S))
ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap);
+ // Handle -order_file <file>
+ for (auto orderFile : parsedArgs->filtered(OPT_order_file)) {
+ if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-order_file "
+ << orderFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
// Handle input files
for (auto &arg : *parsedArgs) {
bool upward;
Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=221545&r1=221544&r2=221545&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Fri Nov 7 15:01:21 2014
@@ -51,6 +51,10 @@ def unexported_symbol : Separate<["-"],
def keep_private_externs : Flag<["-"], "keep_private_externs">,
HelpText<"Private extern (hidden) symbols should not be transformed "
"into local symbols">, Group<grp_opts>;
+def order_file : Separate<["-"], "order_file">,
+ MetaVarName<"<file-path>">,
+ HelpText<"re-order and move specified symbols to start of their section">,
+ Group<grp_opts>;
// main executable options
def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
Modified: lld/trunk/lib/Passes/LayoutPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Passes/LayoutPass.cpp?rev=221545&r1=221544&r2=221545&view=diff
==============================================================================
--- lld/trunk/lib/Passes/LayoutPass.cpp (original)
+++ lld/trunk/lib/Passes/LayoutPass.cpp Fri Nov 7 15:01:21 2014
@@ -19,7 +19,8 @@ using namespace lld;
#define DEBUG_TYPE "LayoutPass"
static bool compareAtoms(const LayoutPass::SortKey &,
- const LayoutPass::SortKey &);
+ const LayoutPass::SortKey &,
+ LayoutPass::SortOverride customSorter=nullptr);
#ifndef NDEBUG
// Return "reason (leftval, rightval)"
@@ -161,10 +162,12 @@ void LayoutPass::checkFollowonChain(Muta
/// b) Sorts atoms by their ordinal overrides (layout-after/ingroup)
/// c) Sorts atoms by their permissions
/// d) Sorts atoms by their content
-/// e) Sorts atoms on how they appear using File Ordinality
-/// f) Sorts atoms on how they appear within the File
+/// e) If custom sorter provided, let it sort
+/// f) Sorts atoms on how they appear using File Ordinality
+/// g) Sorts atoms on how they appear within the File
static bool compareAtomsSub(const LayoutPass::SortKey &lc,
const LayoutPass::SortKey &rc,
+ LayoutPass::SortOverride customSorter,
std::string &reason) {
const DefinedAtom *left = lc._atom;
const DefinedAtom *right = rc._atom;
@@ -216,6 +219,13 @@ static bool compareAtomsSub(const Layout
return leftType < rightType;
}
+ // Use custom sorter if supplied.
+ if (customSorter) {
+ bool leftBeforeRight;
+ if (customSorter(leftRoot, rightRoot, leftBeforeRight))
+ return leftBeforeRight;
+ }
+
// Sort by .o order.
const File *leftFile = &leftRoot->file();
const File *rightFile = &rightRoot->file();
@@ -242,9 +252,10 @@ static bool compareAtomsSub(const Layout
}
static bool compareAtoms(const LayoutPass::SortKey &lc,
- const LayoutPass::SortKey &rc) {
+ const LayoutPass::SortKey &rc,
+ LayoutPass::SortOverride customSorter) {
std::string reason;
- bool result = compareAtomsSub(lc, rc, reason);
+ bool result = compareAtomsSub(lc, rc, customSorter, reason);
DEBUG({
StringRef comp = result ? "<" : ">=";
llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '"
@@ -253,7 +264,8 @@ static bool compareAtoms(const LayoutPas
return result;
}
-LayoutPass::LayoutPass(const Registry ®istry) : _registry(registry) {}
+LayoutPass::LayoutPass(const Registry ®istry, SortOverride sorter)
+ : _registry(registry), _customSorter(sorter) {}
// Returns the atom immediately followed by the given atom in the followon
// chain.
@@ -522,7 +534,10 @@ void LayoutPass::perform(std::unique_ptr
});
std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
- std::sort(vec.begin(), vec.end(), compareAtoms);
+ std::sort(vec.begin(), vec.end(),
+ [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+ return compareAtoms(l, r, _customSorter);
+ });
DEBUG(checkTransitivity(vec));
undecorate(atomRange, vec);
Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=221545&r1=221544&r2=221545&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Fri Nov 7 15:01:21 2014
@@ -146,7 +146,7 @@ MachOLinkingContext::MachOLinkingContext
_printAtoms(false), _testingFileUsage(false), _keepPrivateExterns(false),
_demangle(false), _archHandler(nullptr),
_exportMode(ExportMode::globals),
- _debugInfoMode(DebugInfoMode::addDebugMap) {}
+ _debugInfoMode(DebugInfoMode::addDebugMap), _orderFileEntries(0) {}
MachOLinkingContext::~MachOLinkingContext() {}
@@ -577,7 +577,12 @@ bool MachOLinkingContext::validateImpl(r
}
void MachOLinkingContext::addPasses(PassManager &pm) {
- pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));
+ pm.add(std::unique_ptr<Pass>(new LayoutPass(
+ registry(), [&](const DefinedAtom * left, const DefinedAtom * right,
+ bool & leftBeforeRight)
+ ->bool {
+ return customAtomOrderer(left, right, leftBeforeRight);
+ })));
if (needsStubsPass())
mach_o::addStubsPass(pm, *this);
if (needsCompactUnwindPass())
@@ -825,5 +830,84 @@ void MachOLinkingContext::addOutputFileD
*_dependencyInfo << '\0';
}
+void MachOLinkingContext::appendOrderedSymbol(StringRef symbol,
+ StringRef filename) {
+ // To support sorting static functions which may have the same name in
+ // multiple .o files, _orderFiles maps the symbol name to a vector
+ // of OrderFileNode each of which can specify a file prefix.
+ OrderFileNode info;
+ if (!filename.empty())
+ info.fileFilter = copy(filename);
+ info.order = _orderFileEntries++;
+ _orderFiles[symbol].push_back(info);
+}
+
+bool
+MachOLinkingContext::findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+ const DefinedAtom *atom,
+ unsigned &ordinal) {
+ const File *objFile = &atom->file();
+ assert(objFile);
+ StringRef objName = objFile->path();
+ std::pair<StringRef, StringRef> dirAndLeaf = objName.rsplit('/');
+ if (!dirAndLeaf.second.empty())
+ objName = dirAndLeaf.second;
+ for (const OrderFileNode &info : nodes) {
+ if (info.fileFilter.empty()) {
+ // Have unprefixed symbol name in order file that matches this atom.
+ ordinal = info.order;
+ llvm::errs() << "ordered " << atom->name() << "\n";
+ return true;
+ }
+ if (info.fileFilter.equals(objName)) {
+ // Have prefixed symbol name in order file that matches atom's path.
+ ordinal = info.order;
+ llvm::errs() << "ordered " << atom->name() << " with prefix '"
+ << info.fileFilter << "'\n";
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
+ const DefinedAtom *right,
+ bool &leftBeforeRight) {
+ // No custom sorting if no order file entries.
+ if (!_orderFileEntries)
+ return false;
+
+ // Order files can only order named atoms.
+ StringRef leftName = left->name();
+ StringRef rightName = right->name();
+ if (leftName.empty() || rightName.empty())
+ return false;
+
+ // If neither is in order file list, no custom sorter.
+ auto leftPos = _orderFiles.find(leftName);
+ auto rightPos = _orderFiles.find(rightName);
+ bool leftIsOrdered = (leftPos != _orderFiles.end());
+ bool rightIsOrdered = (rightPos != _orderFiles.end());
+ if (!leftIsOrdered && !rightIsOrdered)
+ return false;
+
+ // There could be multiple symbols with same name but different file prefixes.
+ unsigned leftOrder;
+ unsigned rightOrder;
+ bool foundLeft =
+ leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder);
+ bool foundRight = rightIsOrdered &&
+ findOrderOrdinal(rightPos->getValue(), right, rightOrder);
+ if (!foundLeft && !foundRight)
+ return false;
+
+ // If only one is in order file list, ordered one goes first.
+ if (foundLeft != foundRight)
+ leftBeforeRight = foundLeft;
+ else
+ leftBeforeRight = (leftOrder < rightOrder);
+
+ return true;
+}
} // end namespace lld
Added: lld/trunk/test/mach-o/Inputs/order_file-basic.order
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/Inputs/order_file-basic.order?rev=221545&view=auto
==============================================================================
--- lld/trunk/test/mach-o/Inputs/order_file-basic.order (added)
+++ lld/trunk/test/mach-o/Inputs/order_file-basic.order Fri Nov 7 15:01:21 2014
@@ -0,0 +1,11 @@
+
+# input file for order_file-basic.yaml
+
+_func2
+libfoo.a(foo.o):_foo # tests file specific ordering within archive
+i386:_func3 # wrong arch, so ignored
+armv7:_func3 # wrong arch, so ignored
+_func1
+_notfound # unknown symbol silently ignored
+_data3 # data symbols should be orderable
+
Added: lld/trunk/test/mach-o/order_file-basic.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/order_file-basic.yaml?rev=221545&view=auto
==============================================================================
--- lld/trunk/test/mach-o/order_file-basic.yaml (added)
+++ lld/trunk/test/mach-o/order_file-basic.yaml Fri Nov 7 15:01:21 2014
@@ -0,0 +1,75 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml \
+# RUN: -order_file %p/Inputs/order_file-basic.order \
+# RUN: -force_load %p/Inputs/libfoo.a -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test -order_file
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3, 0xC3, 0xC3, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000014
+ content: [ 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _data1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000014
+ - name: _data2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000018
+ - name: _data3
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x000000000000001C
+ - name: _func1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _func2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _func3
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000002
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000003
+...
+
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _func2
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _func1
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _func3
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: {{[0-9a-f]+}} (__DATA,__data) external _data3
+# CHECK: {{[0-9a-f]+}} (__DATA,__data) external _data1
+# CHECK: {{[0-9a-f]+}} (__DATA,__data) external _data2
+
More information about the llvm-commits
mailing list