diff options
Diffstat (limited to 'lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp')
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp | 78 |
1 files changed, 57 insertions, 21 deletions
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 330d8311caf..7b3b36de358 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -83,7 +83,7 @@ appendRelocations(Relocations &relocs, StringRef buffer, bool swap, if ((reloff + nreloc*8) > buffer.size()) return llvm::make_error_code(llvm::errc::executable_format_error); const any_relocation_info* relocsArray = - reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff); + reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff); for(uint32_t i=0; i < nreloc; ++i) { relocs.push_back(unpackRelocation(relocsArray[i], swap, bigEndian)); @@ -91,17 +91,53 @@ appendRelocations(Relocations &relocs, StringRef buffer, bool swap, return error_code::success(); } - +template <typename T> static T readBigEndian(T t) { + if (llvm::sys::IsLittleEndianHost) + return SwapByteOrder(t); + return t; +} /// Reads a mach-o file and produces an in-memory normalized view. -ErrorOr<std::unique_ptr<NormalizedFile>> -readBinary(std::unique_ptr<MemoryBuffer> &mb) { +ErrorOr<std::unique_ptr<NormalizedFile>> +readBinary(std::unique_ptr<MemoryBuffer> &mb, + const MachOLinkingContext::Arch arch) { // Make empty NormalizedFile. std::unique_ptr<NormalizedFile> f(new NormalizedFile()); + 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*> - (mb->getBufferStart()); + 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 llvm::make_error_code(llvm::errc::executable_format_error); + } + objSize = readBigEndian(fa->size); + uint32_t offset = readBigEndian(fa->offset); + if ((offset + objSize) > mb->getBufferSize()) + return llvm::make_error_code(llvm::errc::executable_format_error); + start += offset; + mh = reinterpret_cast<const mach_header *>(start); + } + bool is64, swap; switch (mh->magic) { case llvm::MachO::MH_MAGIC: @@ -135,10 +171,10 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb) { // Validate head and load commands fit in buffer. const uint32_t lcCount = smh->ncmds; - const char* lcStart = mb->getBufferStart() + (is64 ? sizeof(mach_header_64) - : sizeof(mach_header)); + const char *lcStart = + start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header)); StringRef lcRange(lcStart, smh->sizeofcmds); - if (lcRange.end() > mb->getBufferEnd()) + if (lcRange.end() > (start + objSize)) return llvm::make_error_code(llvm::errc::executable_format_error); // Normalize architecture @@ -175,8 +211,8 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb) { section.attributes = read32(swap, sect->flags) & SECTION_ATTRIBUTES; section.alignment = read32(swap, sect->align); section.address = read64(swap, sect->addr); - const uint8_t *content = (uint8_t *)mb->getBufferStart() - + read32(swap, sect->offset); + const uint8_t *content = + (uint8_t *)start + read32(swap, sect->offset); size_t contentSize = read64(swap, sect->size); // Note: this assign() is copying the content bytes. Ideally, // we can use a custom allocator for vector to avoid the copy. @@ -210,8 +246,8 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb) { section.attributes = read32(swap, sect->flags) & SECTION_ATTRIBUTES; section.alignment = read32(swap, sect->align); section.address = read32(swap, sect->addr); - const uint8_t *content = (uint8_t *)mb->getBufferStart() - + read32(swap, sect->offset); + const uint8_t *content = + (uint8_t *)start + read32(swap, sect->offset); size_t contentSize = read32(swap, sect->size); // Note: this assign() is copying the content bytes. Ideally, // we can use a custom allocator for vector to avoid the copy. @@ -225,19 +261,19 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb) { } if (cmd == LC_SYMTAB) { const symtab_command *st = reinterpret_cast<const symtab_command*>(lc); - const char* strings = mb->getBufferStart() + read32(swap, st->stroff); + const char *strings = start + read32(swap, st->stroff); const uint32_t strSize = read32(swap, st->strsize); // Validate string pool and symbol table all in buffer. if ( read32(swap, st->stroff)+read32(swap, st->strsize) - > mb->getBufferSize() ) + > objSize ) return llvm::make_error_code(llvm::errc::executable_format_error); if (is64) { const uint32_t symOffset = read32(swap, st->symoff); const uint32_t symCount = read32(swap, st->nsyms); - if ( symOffset+(symCount*sizeof(nlist_64)) > mb->getBufferSize()) + if ( symOffset+(symCount*sizeof(nlist_64)) > objSize) return llvm::make_error_code(llvm::errc::executable_format_error); - const nlist_64* symbols = reinterpret_cast<const nlist_64*> - (mb->getBufferStart() + symOffset); + const nlist_64 *symbols = + reinterpret_cast<const nlist_64 *>(start + symOffset); // Convert each nlist_64 to a lld::mach_o::normalized::Symbol. for(uint32_t i=0; i < symCount; ++i) { const nlist_64 *sin = &symbols[i]; @@ -264,10 +300,10 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb) { } else { const uint32_t symOffset = read32(swap, st->symoff); const uint32_t symCount = read32(swap, st->nsyms); - if ( symOffset+(symCount*sizeof(nlist)) > mb->getBufferSize()) + if ( symOffset+(symCount*sizeof(nlist)) > objSize) return llvm::make_error_code(llvm::errc::executable_format_error); - const nlist* symbols = reinterpret_cast<const nlist*> - (mb->getBufferStart() + symOffset); + const nlist *symbols = + reinterpret_cast<const nlist *>(start + symOffset); // Convert each nlist to a lld::mach_o::normalized::Symbol. for(uint32_t i=0; i < symCount; ++i) { const nlist *sin = &symbols[i]; |