1280461Sdim//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===// 2280461Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6280461Sdim// 7280461Sdim//===----------------------------------------------------------------------===// 8280461Sdim 9280461Sdim/// 10280461Sdim/// \file For mach-o object files, this implementation converts from 11280461Sdim/// mach-o on-disk binary format to in-memory normalized mach-o. 12280461Sdim/// 13280461Sdim/// +---------------+ 14280461Sdim/// | binary mach-o | 15280461Sdim/// +---------------+ 16280461Sdim/// | 17280461Sdim/// | 18280461Sdim/// v 19280461Sdim/// +------------+ 20280461Sdim/// | normalized | 21280461Sdim/// +------------+ 22280461Sdim 23321369Sdim#include "ArchHandler.h" 24280461Sdim#include "MachONormalizedFile.h" 25280461Sdim#include "MachONormalizedFileBinaryUtils.h" 26327952Sdim#include "lld/Common/LLVM.h" 27280461Sdim#include "lld/Core/Error.h" 28280461Sdim#include "lld/Core/SharedLibraryFile.h" 29321369Sdim#include "llvm/ADT/STLExtras.h" 30280461Sdim#include "llvm/ADT/SmallString.h" 31280461Sdim#include "llvm/ADT/StringRef.h" 32280461Sdim#include "llvm/ADT/StringSwitch.h" 33280461Sdim#include "llvm/ADT/Twine.h" 34321369Sdim#include "llvm/BinaryFormat/MachO.h" 35321369Sdim#include "llvm/BinaryFormat/Magic.h" 36280461Sdim#include "llvm/Object/MachO.h" 37280461Sdim#include "llvm/Support/Casting.h" 38280461Sdim#include "llvm/Support/Errc.h" 39280461Sdim#include "llvm/Support/ErrorHandling.h" 40280461Sdim#include "llvm/Support/FileOutputBuffer.h" 41280461Sdim#include "llvm/Support/Host.h" 42280461Sdim#include "llvm/Support/MemoryBuffer.h" 43280461Sdim#include "llvm/Support/raw_ostream.h" 44280461Sdim#include <functional> 45280461Sdim#include <system_error> 46280461Sdim 47280461Sdimusing namespace llvm::MachO; 48280461Sdimusing llvm::object::ExportEntry; 49321369Sdimusing llvm::file_magic; 50280461Sdimusing llvm::object::MachOObjectFile; 51280461Sdim 52280461Sdimnamespace lld { 53280461Sdimnamespace mach_o { 54280461Sdimnamespace normalized { 55280461Sdim 56280461Sdim// Utility to call a lambda expression on each load command. 57303239Sdimstatic llvm::Error forEachLoadCommand( 58280461Sdim StringRef lcRange, unsigned lcCount, bool isBig, bool is64, 59280461Sdim std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) { 60280461Sdim const char* p = lcRange.begin(); 61280461Sdim for (unsigned i=0; i < lcCount; ++i) { 62280461Sdim const load_command *lc = reinterpret_cast<const load_command*>(p); 63280461Sdim load_command lcCopy; 64280461Sdim const load_command *slc = lc; 65280461Sdim if (isBig != llvm::sys::IsBigEndianHost) { 66280461Sdim memcpy(&lcCopy, lc, sizeof(load_command)); 67280461Sdim swapStruct(lcCopy); 68280461Sdim slc = &lcCopy; 69280461Sdim } 70280461Sdim if ( (p + slc->cmdsize) > lcRange.end() ) 71303239Sdim return llvm::make_error<GenericError>("Load command exceeds range"); 72280461Sdim 73280461Sdim if (func(slc->cmd, slc->cmdsize, p)) 74314564Sdim return llvm::Error::success(); 75280461Sdim 76280461Sdim p += slc->cmdsize; 77280461Sdim } 78280461Sdim 79314564Sdim return llvm::Error::success(); 80280461Sdim} 81280461Sdim 82280461Sdimstatic std::error_code appendRelocations(Relocations &relocs, StringRef buffer, 83280461Sdim bool bigEndian, 84280461Sdim uint32_t reloff, uint32_t nreloc) { 85280461Sdim if ((reloff + nreloc*8) > buffer.size()) 86280461Sdim return make_error_code(llvm::errc::executable_format_error); 87280461Sdim const any_relocation_info* relocsArray = 88280461Sdim reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff); 89280461Sdim 90280461Sdim for(uint32_t i=0; i < nreloc; ++i) { 91280461Sdim relocs.push_back(unpackRelocation(relocsArray[i], bigEndian)); 92280461Sdim } 93280461Sdim return std::error_code(); 94280461Sdim} 95280461Sdim 96280461Sdimstatic std::error_code 97280461SdimappendIndirectSymbols(IndirectSymbols &isyms, StringRef buffer, bool isBig, 98280461Sdim uint32_t istOffset, uint32_t istCount, 99280461Sdim uint32_t startIndex, uint32_t count) { 100280461Sdim if ((istOffset + istCount*4) > buffer.size()) 101280461Sdim return make_error_code(llvm::errc::executable_format_error); 102280461Sdim if (startIndex+count > istCount) 103280461Sdim return make_error_code(llvm::errc::executable_format_error); 104280461Sdim const uint8_t *indirectSymbolArray = (const uint8_t *)buffer.data(); 105280461Sdim 106280461Sdim for(uint32_t i=0; i < count; ++i) { 107280461Sdim isyms.push_back(read32( 108280461Sdim indirectSymbolArray + (startIndex + i) * sizeof(uint32_t), isBig)); 109280461Sdim } 110280461Sdim return std::error_code(); 111280461Sdim} 112280461Sdim 113280461Sdim 114280461Sdimtemplate <typename T> static T readBigEndian(T t) { 115280461Sdim if (llvm::sys::IsLittleEndianHost) 116280461Sdim llvm::sys::swapByteOrder(t); 117280461Sdim return t; 118280461Sdim} 119280461Sdim 120280461Sdim 121280461Sdimstatic bool isMachOHeader(const mach_header *mh, bool &is64, bool &isBig) { 122280461Sdim switch (read32(&mh->magic, false)) { 123280461Sdim case llvm::MachO::MH_MAGIC: 124280461Sdim is64 = false; 125280461Sdim isBig = false; 126280461Sdim return true; 127280461Sdim case llvm::MachO::MH_MAGIC_64: 128280461Sdim is64 = true; 129280461Sdim isBig = false; 130280461Sdim return true; 131280461Sdim case llvm::MachO::MH_CIGAM: 132280461Sdim is64 = false; 133280461Sdim isBig = true; 134280461Sdim return true; 135280461Sdim case llvm::MachO::MH_CIGAM_64: 136280461Sdim is64 = true; 137280461Sdim isBig = true; 138280461Sdim return true; 139280461Sdim default: 140280461Sdim return false; 141280461Sdim } 142280461Sdim} 143280461Sdim 144280461Sdim 145280461Sdimbool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) { 146280461Sdim // Try opening and mapping file at path. 147280461Sdim ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path); 148280461Sdim if (b.getError()) 149280461Sdim return false; 150280461Sdim 151280461Sdim // If file length < 32 it is too small to be mach-o object file. 152280461Sdim StringRef fileBuffer = b->get()->getBuffer(); 153280461Sdim if (fileBuffer.size() < 32) 154280461Sdim return false; 155280461Sdim 156280461Sdim // If file buffer does not start with MH_MAGIC (and variants), not obj file. 157280461Sdim const mach_header *mh = reinterpret_cast<const mach_header *>( 158280461Sdim fileBuffer.begin()); 159280461Sdim bool is64, isBig; 160280461Sdim if (!isMachOHeader(mh, is64, isBig)) 161280461Sdim return false; 162280461Sdim 163280461Sdim // If not MH_OBJECT, not object file. 164280461Sdim if (read32(&mh->filetype, isBig) != MH_OBJECT) 165280461Sdim return false; 166280461Sdim 167280461Sdim // Lookup up arch from cpu/subtype pair. 168280461Sdim arch = MachOLinkingContext::archFromCpuType( 169280461Sdim read32(&mh->cputype, isBig), 170280461Sdim read32(&mh->cpusubtype, isBig)); 171280461Sdim return true; 172280461Sdim} 173280461Sdim 174292934Sdimbool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch, 175292934Sdim uint32_t &offset, uint32_t &size) { 176280461Sdim const char *start = mb.getBufferStart(); 177280461Sdim const llvm::MachO::fat_header *fh = 178280461Sdim reinterpret_cast<const llvm::MachO::fat_header *>(start); 179280461Sdim if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC) 180280461Sdim return false; 181280461Sdim uint32_t nfat_arch = readBigEndian(fh->nfat_arch); 182280461Sdim const fat_arch *fstart = 183280461Sdim reinterpret_cast<const fat_arch *>(start + sizeof(fat_header)); 184280461Sdim const fat_arch *fend = 185280461Sdim reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) + 186280461Sdim sizeof(fat_arch) * nfat_arch); 187280461Sdim const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch); 188280461Sdim const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch); 189280461Sdim for (const fat_arch *fa = fstart; fa < fend; ++fa) { 190280461Sdim if ((readBigEndian(fa->cputype) == reqCpuType) && 191280461Sdim (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) { 192280461Sdim offset = readBigEndian(fa->offset); 193280461Sdim size = readBigEndian(fa->size); 194280461Sdim if ((offset + size) > mb.getBufferSize()) 195280461Sdim return false; 196280461Sdim return true; 197280461Sdim } 198280461Sdim } 199280461Sdim return false; 200280461Sdim} 201280461Sdim 202280461Sdim/// Reads a mach-o file and produces an in-memory normalized view. 203303239Sdimllvm::Expected<std::unique_ptr<NormalizedFile>> 204280461SdimreadBinary(std::unique_ptr<MemoryBuffer> &mb, 205280461Sdim const MachOLinkingContext::Arch arch) { 206280461Sdim // Make empty NormalizedFile. 207280461Sdim std::unique_ptr<NormalizedFile> f(new NormalizedFile()); 208280461Sdim 209280461Sdim const char *start = mb->getBufferStart(); 210280461Sdim size_t objSize = mb->getBufferSize(); 211280461Sdim const mach_header *mh = reinterpret_cast<const mach_header *>(start); 212280461Sdim 213280461Sdim uint32_t sliceOffset; 214280461Sdim uint32_t sliceSize; 215292934Sdim if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) { 216280461Sdim start = &start[sliceOffset]; 217280461Sdim objSize = sliceSize; 218280461Sdim mh = reinterpret_cast<const mach_header *>(start); 219280461Sdim } 220280461Sdim 221280461Sdim // Determine endianness and pointer size for mach-o file. 222280461Sdim bool is64, isBig; 223280461Sdim if (!isMachOHeader(mh, is64, isBig)) 224303239Sdim return llvm::make_error<GenericError>("File is not a mach-o"); 225280461Sdim 226280461Sdim // Endian swap header, if needed. 227280461Sdim mach_header headerCopy; 228280461Sdim const mach_header *smh = mh; 229280461Sdim if (isBig != llvm::sys::IsBigEndianHost) { 230280461Sdim memcpy(&headerCopy, mh, sizeof(mach_header)); 231280461Sdim swapStruct(headerCopy); 232280461Sdim smh = &headerCopy; 233280461Sdim } 234280461Sdim 235280461Sdim // Validate head and load commands fit in buffer. 236280461Sdim const uint32_t lcCount = smh->ncmds; 237280461Sdim const char *lcStart = 238280461Sdim start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header)); 239280461Sdim StringRef lcRange(lcStart, smh->sizeofcmds); 240280461Sdim if (lcRange.end() > (start + objSize)) 241303239Sdim return llvm::make_error<GenericError>("Load commands exceed file size"); 242280461Sdim 243280461Sdim // Get architecture from mach_header. 244280461Sdim f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype); 245280461Sdim if (f->arch != arch) { 246303239Sdim return llvm::make_error<GenericError>( 247303239Sdim Twine("file is wrong architecture. Expected " 248280461Sdim "(" + MachOLinkingContext::nameFromArch(arch) 249280461Sdim + ") found (" 250280461Sdim + MachOLinkingContext::nameFromArch(f->arch) 251280461Sdim + ")" )); 252280461Sdim } 253280461Sdim // Copy file type and flags 254280461Sdim f->fileType = HeaderFileType(smh->filetype); 255280461Sdim f->flags = smh->flags; 256280461Sdim 257280461Sdim 258280461Sdim // Pre-scan load commands looking for indirect symbol table. 259280461Sdim uint32_t indirectSymbolTableOffset = 0; 260280461Sdim uint32_t indirectSymbolTableCount = 0; 261303239Sdim auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64, 262303239Sdim [&](uint32_t cmd, uint32_t size, 263303239Sdim const char *lc) -> bool { 264280461Sdim if (cmd == LC_DYSYMTAB) { 265280461Sdim const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc); 266280461Sdim indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig); 267280461Sdim indirectSymbolTableCount = read32(&d->nindirectsyms, isBig); 268280461Sdim return true; 269280461Sdim } 270280461Sdim return false; 271280461Sdim }); 272280461Sdim if (ec) 273303239Sdim return std::move(ec); 274280461Sdim 275280461Sdim // Walk load commands looking for segments/sections and the symbol table. 276280461Sdim const data_in_code_entry *dataInCode = nullptr; 277280461Sdim const dyld_info_command *dyldInfo = nullptr; 278280461Sdim uint32_t dataInCodeSize = 0; 279280461Sdim ec = forEachLoadCommand(lcRange, lcCount, isBig, is64, 280280461Sdim [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool { 281280461Sdim switch(cmd) { 282280461Sdim case LC_SEGMENT_64: 283280461Sdim if (is64) { 284280461Sdim const segment_command_64 *seg = 285280461Sdim reinterpret_cast<const segment_command_64*>(lc); 286280461Sdim const unsigned sectionCount = read32(&seg->nsects, isBig); 287280461Sdim const section_64 *sects = reinterpret_cast<const section_64*> 288280461Sdim (lc + sizeof(segment_command_64)); 289280461Sdim const unsigned lcSize = sizeof(segment_command_64) 290280461Sdim + sectionCount*sizeof(section_64); 291280461Sdim // Verify sections don't extend beyond end of segment load command. 292280461Sdim if (lcSize > size) 293280461Sdim return true; 294280461Sdim for (unsigned i=0; i < sectionCount; ++i) { 295280461Sdim const section_64 *sect = §s[i]; 296280461Sdim Section section; 297280461Sdim section.segmentName = getString16(sect->segname); 298280461Sdim section.sectionName = getString16(sect->sectname); 299280461Sdim section.type = (SectionType)(read32(§->flags, isBig) & 300280461Sdim SECTION_TYPE); 301280461Sdim section.attributes = read32(§->flags, isBig) & SECTION_ATTRIBUTES; 302292934Sdim section.alignment = 1 << read32(§->align, isBig); 303280461Sdim section.address = read64(§->addr, isBig); 304280461Sdim const uint8_t *content = 305280461Sdim (const uint8_t *)start + read32(§->offset, isBig); 306280461Sdim size_t contentSize = read64(§->size, isBig); 307280461Sdim // Note: this assign() is copying the content bytes. Ideally, 308280461Sdim // we can use a custom allocator for vector to avoid the copy. 309280461Sdim section.content = llvm::makeArrayRef(content, contentSize); 310280461Sdim appendRelocations(section.relocations, mb->getBuffer(), isBig, 311280461Sdim read32(§->reloff, isBig), 312280461Sdim read32(§->nreloc, isBig)); 313280461Sdim if (section.type == S_NON_LAZY_SYMBOL_POINTERS) { 314280461Sdim appendIndirectSymbols(section.indirectSymbols, mb->getBuffer(), 315280461Sdim isBig, 316280461Sdim indirectSymbolTableOffset, 317280461Sdim indirectSymbolTableCount, 318280461Sdim read32(§->reserved1, isBig), 319280461Sdim contentSize/4); 320280461Sdim } 321280461Sdim f->sections.push_back(section); 322280461Sdim } 323280461Sdim } 324280461Sdim break; 325280461Sdim case LC_SEGMENT: 326280461Sdim if (!is64) { 327280461Sdim const segment_command *seg = 328280461Sdim reinterpret_cast<const segment_command*>(lc); 329280461Sdim const unsigned sectionCount = read32(&seg->nsects, isBig); 330280461Sdim const section *sects = reinterpret_cast<const section*> 331280461Sdim (lc + sizeof(segment_command)); 332280461Sdim const unsigned lcSize = sizeof(segment_command) 333280461Sdim + sectionCount*sizeof(section); 334280461Sdim // Verify sections don't extend beyond end of segment load command. 335280461Sdim if (lcSize > size) 336280461Sdim return true; 337280461Sdim for (unsigned i=0; i < sectionCount; ++i) { 338280461Sdim const section *sect = §s[i]; 339280461Sdim Section section; 340280461Sdim section.segmentName = getString16(sect->segname); 341280461Sdim section.sectionName = getString16(sect->sectname); 342280461Sdim section.type = (SectionType)(read32(§->flags, isBig) & 343280461Sdim SECTION_TYPE); 344280461Sdim section.attributes = 345280461Sdim read32((const uint8_t *)§->flags, isBig) & SECTION_ATTRIBUTES; 346292934Sdim section.alignment = 1 << read32(§->align, isBig); 347280461Sdim section.address = read32(§->addr, isBig); 348280461Sdim const uint8_t *content = 349280461Sdim (const uint8_t *)start + read32(§->offset, isBig); 350280461Sdim size_t contentSize = read32(§->size, isBig); 351280461Sdim // Note: this assign() is copying the content bytes. Ideally, 352280461Sdim // we can use a custom allocator for vector to avoid the copy. 353280461Sdim section.content = llvm::makeArrayRef(content, contentSize); 354280461Sdim appendRelocations(section.relocations, mb->getBuffer(), isBig, 355280461Sdim read32(§->reloff, isBig), 356280461Sdim read32(§->nreloc, isBig)); 357280461Sdim if (section.type == S_NON_LAZY_SYMBOL_POINTERS) { 358280461Sdim appendIndirectSymbols( 359280461Sdim section.indirectSymbols, mb->getBuffer(), isBig, 360280461Sdim indirectSymbolTableOffset, indirectSymbolTableCount, 361280461Sdim read32(§->reserved1, isBig), contentSize / 4); 362280461Sdim } 363280461Sdim f->sections.push_back(section); 364280461Sdim } 365280461Sdim } 366280461Sdim break; 367280461Sdim case LC_SYMTAB: { 368280461Sdim const symtab_command *st = reinterpret_cast<const symtab_command*>(lc); 369280461Sdim const char *strings = start + read32(&st->stroff, isBig); 370280461Sdim const uint32_t strSize = read32(&st->strsize, isBig); 371280461Sdim // Validate string pool and symbol table all in buffer. 372280461Sdim if (read32((const uint8_t *)&st->stroff, isBig) + 373280461Sdim read32((const uint8_t *)&st->strsize, isBig) > 374280461Sdim objSize) 375280461Sdim return true; 376280461Sdim if (is64) { 377280461Sdim const uint32_t symOffset = read32(&st->symoff, isBig); 378280461Sdim const uint32_t symCount = read32(&st->nsyms, isBig); 379280461Sdim if ( symOffset+(symCount*sizeof(nlist_64)) > objSize) 380280461Sdim return true; 381280461Sdim const nlist_64 *symbols = 382280461Sdim reinterpret_cast<const nlist_64 *>(start + symOffset); 383280461Sdim // Convert each nlist_64 to a lld::mach_o::normalized::Symbol. 384280461Sdim for(uint32_t i=0; i < symCount; ++i) { 385280461Sdim nlist_64 tempSym; 386303239Sdim memcpy(&tempSym, &symbols[i], sizeof(nlist_64)); 387303239Sdim const nlist_64 *sin = &tempSym; 388303239Sdim if (isBig != llvm::sys::IsBigEndianHost) 389303239Sdim swapStruct(tempSym); 390280461Sdim Symbol sout; 391280461Sdim if (sin->n_strx > strSize) 392280461Sdim return true; 393280461Sdim sout.name = &strings[sin->n_strx]; 394314564Sdim sout.type = static_cast<NListType>(sin->n_type & (N_STAB|N_TYPE)); 395280461Sdim sout.scope = (sin->n_type & (N_PEXT|N_EXT)); 396280461Sdim sout.sect = sin->n_sect; 397280461Sdim sout.desc = sin->n_desc; 398280461Sdim sout.value = sin->n_value; 399314564Sdim if (sin->n_type & N_STAB) 400314564Sdim f->stabsSymbols.push_back(sout); 401314564Sdim else if (sout.type == N_UNDF) 402280461Sdim f->undefinedSymbols.push_back(sout); 403280461Sdim else if (sin->n_type & N_EXT) 404280461Sdim f->globalSymbols.push_back(sout); 405280461Sdim else 406280461Sdim f->localSymbols.push_back(sout); 407280461Sdim } 408280461Sdim } else { 409280461Sdim const uint32_t symOffset = read32(&st->symoff, isBig); 410280461Sdim const uint32_t symCount = read32(&st->nsyms, isBig); 411280461Sdim if ( symOffset+(symCount*sizeof(nlist)) > objSize) 412280461Sdim return true; 413280461Sdim const nlist *symbols = 414280461Sdim reinterpret_cast<const nlist *>(start + symOffset); 415280461Sdim // Convert each nlist to a lld::mach_o::normalized::Symbol. 416280461Sdim for(uint32_t i=0; i < symCount; ++i) { 417280461Sdim const nlist *sin = &symbols[i]; 418280461Sdim nlist tempSym; 419280461Sdim if (isBig != llvm::sys::IsBigEndianHost) { 420280461Sdim tempSym = *sin; swapStruct(tempSym); sin = &tempSym; 421280461Sdim } 422280461Sdim Symbol sout; 423280461Sdim if (sin->n_strx > strSize) 424280461Sdim return true; 425280461Sdim sout.name = &strings[sin->n_strx]; 426280461Sdim sout.type = (NListType)(sin->n_type & N_TYPE); 427280461Sdim sout.scope = (sin->n_type & (N_PEXT|N_EXT)); 428280461Sdim sout.sect = sin->n_sect; 429280461Sdim sout.desc = sin->n_desc; 430280461Sdim sout.value = sin->n_value; 431280461Sdim if (sout.type == N_UNDF) 432280461Sdim f->undefinedSymbols.push_back(sout); 433280461Sdim else if (sout.scope == (SymbolScope)N_EXT) 434280461Sdim f->globalSymbols.push_back(sout); 435314564Sdim else if (sin->n_type & N_STAB) 436314564Sdim f->stabsSymbols.push_back(sout); 437280461Sdim else 438280461Sdim f->localSymbols.push_back(sout); 439280461Sdim } 440280461Sdim } 441280461Sdim } 442280461Sdim break; 443280461Sdim case LC_ID_DYLIB: { 444280461Sdim const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc); 445280461Sdim f->installName = lc + read32(&dl->dylib.name, isBig); 446280461Sdim f->currentVersion = read32(&dl->dylib.current_version, isBig); 447280461Sdim f->compatVersion = read32(&dl->dylib.compatibility_version, isBig); 448280461Sdim } 449280461Sdim break; 450280461Sdim case LC_DATA_IN_CODE: { 451280461Sdim const linkedit_data_command *ldc = 452280461Sdim reinterpret_cast<const linkedit_data_command*>(lc); 453280461Sdim dataInCode = reinterpret_cast<const data_in_code_entry *>( 454280461Sdim start + read32(&ldc->dataoff, isBig)); 455280461Sdim dataInCodeSize = read32(&ldc->datasize, isBig); 456280461Sdim } 457280461Sdim break; 458280461Sdim case LC_LOAD_DYLIB: 459280461Sdim case LC_LOAD_WEAK_DYLIB: 460280461Sdim case LC_REEXPORT_DYLIB: 461280461Sdim case LC_LOAD_UPWARD_DYLIB: { 462280461Sdim const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc); 463280461Sdim DependentDylib entry; 464280461Sdim entry.path = lc + read32(&dl->dylib.name, isBig); 465280461Sdim entry.kind = LoadCommandType(cmd); 466280461Sdim entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig); 467280461Sdim entry.currentVersion = read32(&dl->dylib.current_version, isBig); 468280461Sdim f->dependentDylibs.push_back(entry); 469280461Sdim } 470280461Sdim break; 471280461Sdim case LC_RPATH: { 472280461Sdim const rpath_command *rpc = reinterpret_cast<const rpath_command *>(lc); 473280461Sdim f->rpaths.push_back(lc + read32(&rpc->path, isBig)); 474280461Sdim } 475280461Sdim break; 476280461Sdim case LC_DYLD_INFO: 477280461Sdim case LC_DYLD_INFO_ONLY: 478280461Sdim dyldInfo = reinterpret_cast<const dyld_info_command*>(lc); 479280461Sdim break; 480303239Sdim case LC_VERSION_MIN_MACOSX: 481303239Sdim case LC_VERSION_MIN_IPHONEOS: 482303239Sdim case LC_VERSION_MIN_WATCHOS: 483303239Sdim case LC_VERSION_MIN_TVOS: 484303239Sdim // If we are emitting an object file, then we may take the load command 485303239Sdim // kind from these commands and pass it on to the output 486303239Sdim // file. 487303239Sdim f->minOSVersionKind = (LoadCommandType)cmd; 488303239Sdim break; 489280461Sdim } 490280461Sdim return false; 491280461Sdim }); 492280461Sdim if (ec) 493303239Sdim return std::move(ec); 494280461Sdim 495280461Sdim if (dataInCode) { 496280461Sdim // Convert on-disk data_in_code_entry array to DataInCode vector. 497280461Sdim for (unsigned i=0; i < dataInCodeSize/sizeof(data_in_code_entry); ++i) { 498280461Sdim DataInCode entry; 499280461Sdim entry.offset = read32(&dataInCode[i].offset, isBig); 500280461Sdim entry.length = read16(&dataInCode[i].length, isBig); 501280461Sdim entry.kind = 502280461Sdim (DataRegionType)read16((const uint8_t *)&dataInCode[i].kind, isBig); 503280461Sdim f->dataInCode.push_back(entry); 504280461Sdim } 505280461Sdim } 506280461Sdim 507280461Sdim if (dyldInfo) { 508280461Sdim // If any exports, extract and add to normalized exportInfo vector. 509280461Sdim if (dyldInfo->export_size) { 510321369Sdim const uint8_t *trieStart = reinterpret_cast<const uint8_t *>( 511321369Sdim start + read32(&dyldInfo->export_off, isBig)); 512321369Sdim ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig)); 513327952Sdim Error Err = Error::success(); 514327952Sdim for (const ExportEntry &trieExport : MachOObjectFile::exports(Err, trie)) { 515280461Sdim Export normExport; 516280461Sdim normExport.name = trieExport.name().copy(f->ownedAllocations); 517280461Sdim normExport.offset = trieExport.address(); 518280461Sdim normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK); 519280461Sdim normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK; 520280461Sdim normExport.otherOffset = trieExport.other(); 521280461Sdim if (!trieExport.otherName().empty()) 522280461Sdim normExport.otherName = trieExport.otherName().copy(f->ownedAllocations); 523280461Sdim f->exportInfo.push_back(normExport); 524280461Sdim } 525327952Sdim if (Err) 526327952Sdim return std::move(Err); 527280461Sdim } 528280461Sdim } 529280461Sdim 530280461Sdim return std::move(f); 531280461Sdim} 532280461Sdim 533280461Sdimclass MachOObjectReader : public Reader { 534280461Sdimpublic: 535280461Sdim MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {} 536280461Sdim 537292934Sdim bool canParse(file_magic magic, MemoryBufferRef mb) const override { 538321369Sdim return (magic == file_magic::macho_object && mb.getBufferSize() > 32); 539280461Sdim } 540280461Sdim 541292934Sdim ErrorOr<std::unique_ptr<File>> 542292934Sdim loadFile(std::unique_ptr<MemoryBuffer> mb, 543292934Sdim const Registry ®istry) const override { 544292934Sdim std::unique_ptr<File> ret = 545360784Sdim std::make_unique<MachOFile>(std::move(mb), &_ctx); 546292934Sdim return std::move(ret); 547280461Sdim } 548280461Sdim 549280461Sdimprivate: 550280461Sdim MachOLinkingContext &_ctx; 551280461Sdim}; 552280461Sdim 553280461Sdimclass MachODylibReader : public Reader { 554280461Sdimpublic: 555280461Sdim MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {} 556280461Sdim 557292934Sdim bool canParse(file_magic magic, MemoryBufferRef mb) const override { 558280461Sdim switch (magic) { 559321369Sdim case file_magic::macho_dynamically_linked_shared_lib: 560321369Sdim case file_magic::macho_dynamically_linked_shared_lib_stub: 561292934Sdim return mb.getBufferSize() > 32; 562280461Sdim default: 563280461Sdim return false; 564280461Sdim } 565280461Sdim } 566280461Sdim 567292934Sdim ErrorOr<std::unique_ptr<File>> 568292934Sdim loadFile(std::unique_ptr<MemoryBuffer> mb, 569292934Sdim const Registry ®istry) const override { 570292934Sdim std::unique_ptr<File> ret = 571360784Sdim std::make_unique<MachODylibFile>(std::move(mb), &_ctx); 572292934Sdim return std::move(ret); 573280461Sdim } 574280461Sdim 575280461Sdimprivate: 576280461Sdim MachOLinkingContext &_ctx; 577280461Sdim}; 578280461Sdim 579280461Sdim} // namespace normalized 580280461Sdim} // namespace mach_o 581280461Sdim 582280461Sdimvoid Registry::addSupportMachOObjects(MachOLinkingContext &ctx) { 583280461Sdim MachOLinkingContext::Arch arch = ctx.arch(); 584280461Sdim add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx))); 585280461Sdim add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx))); 586280461Sdim addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), 587280461Sdim ctx.archHandler().kindStrings()); 588280461Sdim add(std::unique_ptr<YamlIOTaggedDocumentHandler>( 589280461Sdim new mach_o::MachOYamlIOTaggedDocumentHandler(arch))); 590280461Sdim} 591280461Sdim 592280461Sdim 593280461Sdim} // namespace lld 594