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
120 lines
4.0 KiB
C++
120 lines
4.0 KiB
C++
//===- lib/ReaderWriter/MachO/DarwinInputGraph.cpp ------------------------===//
|
|
//
|
|
// The LLVM Linker
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lld/Driver/DarwinInputGraph.h"
|
|
#include "lld/Core/ArchiveLibraryFile.h"
|
|
#include "lld/Core/DefinedAtom.h"
|
|
#include "lld/Core/File.h"
|
|
#include "lld/Core/LLVM.h"
|
|
#include "lld/Core/Reference.h"
|
|
#include "lld/Core/SharedLibraryFile.h"
|
|
|
|
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) {
|
|
ErrorOr<StringRef> filePath = getPath(ctx);
|
|
if (std::error_code ec = filePath.getError())
|
|
return ec;
|
|
|
|
if (std::error_code ec = getBuffer(*filePath))
|
|
return ec;
|
|
|
|
_context.addInputFileDependency(*filePath);
|
|
if (ctx.logInputFiles())
|
|
diagnostics << *filePath << "\n";
|
|
|
|
narrowFatBuffer(*filePath);
|
|
|
|
std::vector<std::unique_ptr<File>> parsedFiles;
|
|
if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles))
|
|
return ec;
|
|
for (std::unique_ptr<File> &pf : parsedFiles) {
|
|
// If file is a dylib, inform LinkingContext about it.
|
|
if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
|
|
_context.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
|
|
_upwardDylib);
|
|
}
|
|
// If file is an archive and -all_load, then add all members.
|
|
if (ArchiveLibraryFile *archive = dyn_cast<ArchiveLibraryFile>(pf.get())) {
|
|
if (_isWholeArchive) {
|
|
// Note: the members are added to _files, but the archive is not.
|
|
return archive->parseAllMembers(_files);
|
|
}
|
|
}
|
|
_files.push_back(std::move(pf));
|
|
}
|
|
return std::error_code();
|
|
}
|
|
|
|
|
|
/// If buffer contains a fat file, find required arch in fat buffer and
|
|
/// switch buffer to point to just that required slice.
|
|
void MachOFileNode::narrowFatBuffer(StringRef filePath) {
|
|
// Check if buffer is a "fat" file that contains needed arch.
|
|
uint32_t offset;
|
|
uint32_t size;
|
|
if (!_context.sliceFromFatFile(*_buffer, offset, size)) {
|
|
return;
|
|
}
|
|
// Create new buffer containing just the needed slice.
|
|
auto subuf = MemoryBuffer::getFileSlice(filePath, size, offset);
|
|
if (subuf.getError())
|
|
return;
|
|
// The assignment to _buffer will release previous buffer.
|
|
_buffer = std::move(subuf.get());
|
|
}
|
|
|
|
|
|
} // end namesapce lld
|