Subclass InputGraph to get darwin linker library semantics

The darwin linker operates differently than the gnu linker with respect to
libraries. The darwin linker first links in all object files from the command
line, then to resolve any remaining undefines, it repeatedly iterates over
libraries on the command line until either all undefines are resolved or no
undefines were resolved in the last pass.

When Shankar made the InputGraph model, the plan for darwin was for the darwin
driver to place all libraries in a group at the end of the InputGraph. Thus
making the darwin model a subset of the gnu model. But it turns out that does
not work because the driver cannot tell if a file is an object or library until
it has been loaded, which happens later.

This solution is to subclass InputGraph for darwin and just iterate the graph
the way darwin linker needs.

llvm-svn: 220330
This commit is contained in:
Nick Kledzik 2014-10-21 21:14:11 +00:00
parent 8c4fb7cae0
commit a721db24c0
9 changed files with 157 additions and 8 deletions

View File

@ -50,19 +50,20 @@ public:
/// \brief Initialize the inputgraph
InputGraph() : _nextElementIndex(0), _currentInputElement(nullptr) {}
virtual ~InputGraph();
/// getNextFile returns the next file that needs to be processed by
/// the resolver. When there are no more files to be processed, an
/// appropriate InputGraphError is returned. Ordinals are assigned
/// to files returned by getNextFile, which means ordinals would be
/// assigned in the way files are resolved.
ErrorOr<File &> getNextFile();
virtual ErrorOr<File &> getNextFile();
/// Notifies the current input element of Resolver made some progress on
/// resolving undefined symbols using the current file. Group (representing
/// --start-group and --end-group) uses that notification to make a decision
/// whether it should iterate over again or terminate or not.
void notifyProgress();
virtual void notifyProgress();
/// Adds an observer of getNextFile(). Each time a new file is about to be
/// returned from getNextFile(), registered observers are called with the file

View File

@ -22,6 +22,18 @@
namespace lld {
class DarwinInputGraph : public InputGraph {
public:
DarwinInputGraph() : _librariesPhase(false), _repeatLibraries(false) { }
ErrorOr<File &> getNextFile() override;
void notifyProgress() override;
private:
bool _librariesPhase;
bool _repeatLibraries;
};
/// \brief Represents a MachO File
class MachOFileNode : public FileNode {
public:

View File

@ -13,6 +13,8 @@
using namespace lld;
InputGraph::~InputGraph() { }
ErrorOr<File &> InputGraph::getNextFile() {
// Try to get the next file of _currentInputElement. If the current input
// element points to an archive file, and there's a file left in the archive,

View File

@ -17,6 +17,49 @@
namespace lld {
ErrorOr<File &> DarwinInputGraph::getNextFile() {
// The darwin linker processes input files in two phases. The first phase
// links in all object (.o) files in command line order. The second phase
// links in libraries in command line order. If there are still UndefinedAtoms
// the second phase is repeated until notifyProgress() is not called by
// resolver.
for (;;) {
if (_currentInputElement) {
for(;;) {
ErrorOr<File &> next = _currentInputElement->getNextFile();
if (next.getError())
break;
File *file = &next.get();
bool fileIsLibrary = isa<SharedLibraryFile>(file) ||
isa<ArchiveLibraryFile>(file);
if (fileIsLibrary == _librariesPhase) {
// Return library in library phase and object files in non-lib mode.
return *file;
}
}
}
if (_nextElementIndex >= _inputArgs.size()) {
// If no more elements, done unless we need to repeat library scan.
if (_librariesPhase && !_repeatLibraries)
return make_error_code(InputGraphError::no_more_files);
// Clear iterations and only look for libraries.
_librariesPhase = true;
_repeatLibraries = false;
_nextElementIndex = 0;
for (auto &ie : _inputArgs) {
ie->resetNextIndex();
}
}
_currentInputElement = _inputArgs[_nextElementIndex++].get();
}
}
void DarwinInputGraph::notifyProgress() {
_repeatLibraries = true;
}
/// \brief Parse the input file to lld::File.
std::error_code MachOFileNode::parse(const LinkingContext &ctx,
raw_ostream &diagnostics) {

View File

@ -83,7 +83,7 @@ static std::string canonicalizePath(StringRef path) {
}
}
static void addFile(StringRef path, std::unique_ptr<InputGraph> &inputGraph,
static void addFile(StringRef path, std::unique_ptr<DarwinInputGraph> &inputGraph,
MachOLinkingContext &ctx, bool loadWholeArchive,
bool upwardDylib) {
auto node = llvm::make_unique<MachOFileNode>(path, ctx);
@ -132,7 +132,7 @@ static std::error_code parseExportsList(StringRef exportFilePath,
// per line. The <dir> prefix is prepended to each partial path.
//
static std::error_code parseFileList(StringRef fileListPath,
std::unique_ptr<InputGraph> &inputGraph,
std::unique_ptr<DarwinInputGraph> &inputGraph,
MachOLinkingContext &ctx, bool forceLoad,
raw_ostream &diagnostics) {
// If there is a comma, split off <dir>.
@ -468,7 +468,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
}
std::unique_ptr<InputGraph> inputGraph(new InputGraph());
std::unique_ptr<DarwinInputGraph> inputGraph(new DarwinInputGraph());
// Now construct the set of library search directories, following ld64's
// baroque set of accumulated hacks. Mostly, the algorithm constructs

Binary file not shown.

View File

@ -1,4 +1,4 @@
# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -print_atoms 2>&1 -r | FileCheck %s
# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1 | FileCheck %s
--- !native
undefined-atoms:
@ -7,10 +7,10 @@ undefined-atoms:
- name: _from_fileo
# CHECK: defined-atoms:
# CHECK: - name: _from_mystatic
# CHECK: content: [ 02, 00, 00, 00 ]
# CHECK: - name: _from_fileo
# CHECK: content: [ 2A, 00, 00, 00 ]
# CHECK: - name: _from_mystatic
# CHECK: content: [ 02, 00, 00, 00 ]
# CHECK: shared-library-atoms:
# CHECK: - name: _from_myshared
# CHECK: load-name: libmyshared.dylib

View File

@ -0,0 +1,45 @@
# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %s -o %t \
# RUN: %p/Inputs/libSystem.yaml
# RUN: llvm-nm -m -n %t | FileCheck %s
#
# Test that if library is before object file on command line, it still is used.
#
--- !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 ]
alignment: 4
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
relocations:
- offset: 0x00000012
type: X86_64_RELOC_BRANCH
length: 2
pc-rel: true
extern: true
symbol: 1
global-symbols:
- name: _main
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
undefined-symbols:
- name: _foo
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
...
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo

View File

@ -0,0 +1,46 @@
# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \
# RUN: %s -o %t %p/Inputs/libSystem.yaml
# RUN: llvm-nm -m -n %t | FileCheck %s
#
# Test that static libraries are automatically rescanned (bar needs foo).
#
--- !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 ]
alignment: 4
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
relocations:
- offset: 0x00000012
type: X86_64_RELOC_BRANCH
length: 2
pc-rel: true
extern: true
symbol: 1
global-symbols:
- name: _main
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
undefined-symbols:
- name: _bar
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
...
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _bar
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo