Files
llvm/lld/lib/Driver/DarwinInputGraph.cpp
Nick Kledzik 14b5d208cb [mach-o] Support fat archives
mach-o supports "fat" files which are a header/table-of-contents followed by a
concatenation of mach-o files (or archives of mach-o files) built for
different architectures.  Previously, the support for fat files was in the
MachOReader, but that only supported fat .o files and dylibs (not archives).

The fix is to put the fat handing into MachOFileNode.  That way any input file
kind (including archives) can be fat.  MachOFileNode selects the sub-range
of the fat file that matches the arch being linked and creates a MemoryBuffer
for just that subrange.

llvm-svn: 219268
2014-10-08 01:48:10 +00:00

87 lines
2.8 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 {
/// \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 (_isWholeArchive) {
std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles);
if (ec)
return ec;
assert(parsedFiles.size() == 1);
std::unique_ptr<File> f(parsedFiles[0].release());
if (auto archive =
reinterpret_cast<const ArchiveLibraryFile *>(f.get())) {
// FIXME: something needs to own archive File
//_files.push_back(std::move(archive));
return archive->parseAllMembers(_files);
} else {
// if --whole-archive is around non-archive, just use it as normal.
_files.push_back(std::move(f));
return std::error_code();
}
}
if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles))
return ec;
for (std::unique_ptr<File> &pf : parsedFiles) {
// If a dylib was parsed, inform LinkingContext about it.
if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
_context.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl));
}
_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