summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
diff options
context:
space:
mode:
authorNick Kledzik <kledzik@apple.com>2014-10-08 01:48:10 +0000
committerNick Kledzik <kledzik@apple.com>2014-10-08 01:48:10 +0000
commit14b5d208cba5ff5c5d779c104efa62be48ae4134 (patch)
tree4d9b38f1ae7965fc62468d252b9302d99955a07b /lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
parentf20143825cf97e581334a57c1c69d5914601a1ea (diff)
downloadbcm5719-llvm-14b5d208cba5ff5c5d779c104efa62be48ae4134.tar.gz
bcm5719-llvm-14b5d208cba5ff5c5d779c104efa62be48ae4134.zip
[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
Diffstat (limited to 'lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp')
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp80
1 files changed, 44 insertions, 36 deletions
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 9997ca0245c..0993ea569c2 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -170,6 +170,35 @@ bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
return true;
}
+
+bool sliceFromFatFile(const MemoryBuffer &mb, MachOLinkingContext::Arch arch,
+ uint32_t &offset, uint32_t &size) {
+ const char *start = mb.getBufferStart();
+ const llvm::MachO::fat_header *fh =
+ reinterpret_cast<const llvm::MachO::fat_header *>(start);
+ if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC)
+ return false;
+ uint32_t nfat_arch = readBigEndian(fh->nfat_arch);
+ const fat_arch *fstart =
+ reinterpret_cast<const fat_arch *>(start + sizeof(fat_header));
+ const fat_arch *fend =
+ reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) +
+ sizeof(fat_arch) * nfat_arch);
+ const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch);
+ const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch);
+ for (const fat_arch *fa = fstart; fa < fend; ++fa) {
+ if ((readBigEndian(fa->cputype) == reqCpuType) &&
+ (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) {
+ offset = readBigEndian(fa->offset);
+ size = readBigEndian(fa->size);
+ if ((offset + size) > mb.getBufferSize())
+ return false;
+ return true;
+ }
+ }
+ return false;
+}
+
/// Reads a mach-o file and produces an in-memory normalized view.
ErrorOr<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> &mb,
@@ -179,41 +208,17 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
const char *start = mb->getBufferStart();
size_t objSize = mb->getBufferSize();
-
- // Determine endianness and pointer size for mach-o file.
const mach_header *mh = reinterpret_cast<const mach_header *>(start);
- bool isFat = mh->magic == llvm::MachO::FAT_CIGAM ||
- mh->magic == llvm::MachO::FAT_MAGIC;
- if (isFat) {
- uint32_t cputype = MachOLinkingContext::cpuTypeFromArch(arch);
- uint32_t cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(arch);
- const fat_header *fh = reinterpret_cast<const fat_header *>(start);
- uint32_t nfat_arch = readBigEndian(fh->nfat_arch);
- const fat_arch *fa =
- reinterpret_cast<const fat_arch *>(start + sizeof(fat_header));
- bool foundArch = false;
- while (nfat_arch-- > 0) {
- if (readBigEndian(fa->cputype) == cputype &&
- readBigEndian(fa->cpusubtype) == cpusubtype) {
- foundArch = true;
- break;
- }
- fa++;
- }
- if (!foundArch) {
- return make_dynamic_error_code(Twine("file does not contain required"
- " architecture ("
- + MachOLinkingContext::nameFromArch(arch)
- + ")" ));
- }
- objSize = readBigEndian(fa->size);
- uint32_t offset = readBigEndian(fa->offset);
- if ((offset + objSize) > mb->getBufferSize())
- return make_error_code(llvm::errc::executable_format_error);
- start += offset;
+
+ uint32_t sliceOffset;
+ uint32_t sliceSize;
+ if (sliceFromFatFile(*mb, arch, sliceOffset, sliceSize)) {
+ start = &start[sliceOffset];
+ objSize = sliceSize;
mh = reinterpret_cast<const mach_header *>(start);
}
+ // Determine endianness and pointer size for mach-o file.
bool is64, swap;
if (!isMachOHeader(mh, is64, swap))
return make_error_code(llvm::errc::executable_format_error);
@@ -501,18 +506,20 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
return std::move(f);
}
-
class MachOReader : public Reader {
public:
MachOReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
bool canParse(file_magic magic, StringRef ext,
const MemoryBuffer &mb) const override {
- if (magic != llvm::sys::fs::file_magic::macho_object &&
- magic != llvm::sys::fs::file_magic::macho_universal_binary &&
- magic != llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib)
+ switch (magic) {
+ case llvm::sys::fs::file_magic::macho_object:
+ case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib:
+ case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub:
+ return (mb.getBufferSize() > 32);
+ default:
return false;
- return (mb.getBufferSize() > 32);
+ }
}
std::error_code
@@ -548,5 +555,6 @@ void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
}
+
} // namespace lld
OpenPOWER on IntegriCloud