1 //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 /// 11 /// \file For mach-o object files, this implementation converts from 12 /// mach-o on-disk binary format to in-memory normalized mach-o. 13 /// 14 /// +---------------+ 15 /// | binary mach-o | 16 /// +---------------+ 17 /// | 18 /// | 19 /// v 20 /// +------------+ 21 /// | normalized | 22 /// +------------+ 23 24 #include "ArchHandler.h" 25 #include "MachONormalizedFile.h" 26 #include "MachONormalizedFileBinaryUtils.h" 27 #include "lld/Common/LLVM.h" 28 #include "lld/Core/Error.h" 29 #include "lld/Core/SharedLibraryFile.h" 30 #include "llvm/ADT/STLExtras.h" 31 #include "llvm/ADT/SmallString.h" 32 #include "llvm/ADT/StringRef.h" 33 #include "llvm/ADT/StringSwitch.h" 34 #include "llvm/ADT/Twine.h" 35 #include "llvm/BinaryFormat/MachO.h" 36 #include "llvm/BinaryFormat/Magic.h" 37 #include "llvm/Object/MachO.h" 38 #include "llvm/Support/Casting.h" 39 #include "llvm/Support/Errc.h" 40 #include "llvm/Support/ErrorHandling.h" 41 #include "llvm/Support/FileOutputBuffer.h" 42 #include "llvm/Support/Host.h" 43 #include "llvm/Support/MemoryBuffer.h" 44 #include "llvm/Support/raw_ostream.h" 45 #include <functional> 46 #include <system_error> 47 48 using namespace llvm::MachO; 49 using llvm::object::ExportEntry; 50 using llvm::file_magic; 51 using llvm::object::MachOObjectFile; 52 53 namespace lld { 54 namespace mach_o { 55 namespace normalized { 56 57 // Utility to call a lambda expression on each load command. 58 static llvm::Error forEachLoadCommand( 59 StringRef lcRange, unsigned lcCount, bool isBig, bool is64, 60 std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) { 61 const char* p = lcRange.begin(); 62 for (unsigned i=0; i < lcCount; ++i) { 63 const load_command *lc = reinterpret_cast<const load_command*>(p); 64 load_command lcCopy; 65 const load_command *slc = lc; 66 if (isBig != llvm::sys::IsBigEndianHost) { 67 memcpy(&lcCopy, lc, sizeof(load_command)); 68 swapStruct(lcCopy); 69 slc = &lcCopy; 70 } 71 if ( (p + slc->cmdsize) > lcRange.end() ) 72 return llvm::make_error<GenericError>("Load command exceeds range"); 73 74 if (func(slc->cmd, slc->cmdsize, p)) 75 return llvm::Error::success(); 76 77 p += slc->cmdsize; 78 } 79 80 return llvm::Error::success(); 81 } 82 83 static std::error_code appendRelocations(Relocations &relocs, StringRef buffer, 84 bool bigEndian, 85 uint32_t reloff, uint32_t nreloc) { 86 if ((reloff + nreloc*8) > buffer.size()) 87 return make_error_code(llvm::errc::executable_format_error); 88 const any_relocation_info* relocsArray = 89 reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff); 90 91 for(uint32_t i=0; i < nreloc; ++i) { 92 relocs.push_back(unpackRelocation(relocsArray[i], bigEndian)); 93 } 94 return std::error_code(); 95 } 96 97 static std::error_code 98 appendIndirectSymbols(IndirectSymbols &isyms, StringRef buffer, bool isBig, 99 uint32_t istOffset, uint32_t istCount, 100 uint32_t startIndex, uint32_t count) { 101 if ((istOffset + istCount*4) > buffer.size()) 102 return make_error_code(llvm::errc::executable_format_error); 103 if (startIndex+count > istCount) 104 return make_error_code(llvm::errc::executable_format_error); 105 const uint8_t *indirectSymbolArray = (const uint8_t *)buffer.data(); 106 107 for(uint32_t i=0; i < count; ++i) { 108 isyms.push_back(read32( 109 indirectSymbolArray + (startIndex + i) * sizeof(uint32_t), isBig)); 110 } 111 return std::error_code(); 112 } 113 114 115 template <typename T> static T readBigEndian(T t) { 116 if (llvm::sys::IsLittleEndianHost) 117 llvm::sys::swapByteOrder(t); 118 return t; 119 } 120 121 122 static bool isMachOHeader(const mach_header *mh, bool &is64, bool &isBig) { 123 switch (read32(&mh->magic, false)) { 124 case llvm::MachO::MH_MAGIC: 125 is64 = false; 126 isBig = false; 127 return true; 128 case llvm::MachO::MH_MAGIC_64: 129 is64 = true; 130 isBig = false; 131 return true; 132 case llvm::MachO::MH_CIGAM: 133 is64 = false; 134 isBig = true; 135 return true; 136 case llvm::MachO::MH_CIGAM_64: 137 is64 = true; 138 isBig = true; 139 return true; 140 default: 141 return false; 142 } 143 } 144 145 146 bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) { 147 // Try opening and mapping file at path. 148 ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path); 149 if (b.getError()) 150 return false; 151 152 // If file length < 32 it is too small to be mach-o object file. 153 StringRef fileBuffer = b->get()->getBuffer(); 154 if (fileBuffer.size() < 32) 155 return false; 156 157 // If file buffer does not start with MH_MAGIC (and variants), not obj file. 158 const mach_header *mh = reinterpret_cast<const mach_header *>( 159 fileBuffer.begin()); 160 bool is64, isBig; 161 if (!isMachOHeader(mh, is64, isBig)) 162 return false; 163 164 // If not MH_OBJECT, not object file. 165 if (read32(&mh->filetype, isBig) != MH_OBJECT) 166 return false; 167 168 // Lookup up arch from cpu/subtype pair. 169 arch = MachOLinkingContext::archFromCpuType( 170 read32(&mh->cputype, isBig), 171 read32(&mh->cpusubtype, isBig)); 172 return true; 173 } 174 175 bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch, 176 uint32_t &offset, uint32_t &size) { 177 const char *start = mb.getBufferStart(); 178 const llvm::MachO::fat_header *fh = 179 reinterpret_cast<const llvm::MachO::fat_header *>(start); 180 if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC) 181 return false; 182 uint32_t nfat_arch = readBigEndian(fh->nfat_arch); 183 const fat_arch *fstart = 184 reinterpret_cast<const fat_arch *>(start + sizeof(fat_header)); 185 const fat_arch *fend = 186 reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) + 187 sizeof(fat_arch) * nfat_arch); 188 const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch); 189 const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch); 190 for (const fat_arch *fa = fstart; fa < fend; ++fa) { 191 if ((readBigEndian(fa->cputype) == reqCpuType) && 192 (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) { 193 offset = readBigEndian(fa->offset); 194 size = readBigEndian(fa->size); 195 if ((offset + size) > mb.getBufferSize()) 196 return false; 197 return true; 198 } 199 } 200 return false; 201 } 202 203 /// Reads a mach-o file and produces an in-memory normalized view. 204 llvm::Expected<std::unique_ptr<NormalizedFile>> 205 readBinary(std::unique_ptr<MemoryBuffer> &mb, 206 const MachOLinkingContext::Arch arch) { 207 // Make empty NormalizedFile. 208 std::unique_ptr<NormalizedFile> f(new NormalizedFile()); 209 210 const char *start = mb->getBufferStart(); 211 size_t objSize = mb->getBufferSize(); 212 const mach_header *mh = reinterpret_cast<const mach_header *>(start); 213 214 uint32_t sliceOffset; 215 uint32_t sliceSize; 216 if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) { 217 start = &start[sliceOffset]; 218 objSize = sliceSize; 219 mh = reinterpret_cast<const mach_header *>(start); 220 } 221 222 // Determine endianness and pointer size for mach-o file. 223 bool is64, isBig; 224 if (!isMachOHeader(mh, is64, isBig)) 225 return llvm::make_error<GenericError>("File is not a mach-o"); 226 227 // Endian swap header, if needed. 228 mach_header headerCopy; 229 const mach_header *smh = mh; 230 if (isBig != llvm::sys::IsBigEndianHost) { 231 memcpy(&headerCopy, mh, sizeof(mach_header)); 232 swapStruct(headerCopy); 233 smh = &headerCopy; 234 } 235 236 // Validate head and load commands fit in buffer. 237 const uint32_t lcCount = smh->ncmds; 238 const char *lcStart = 239 start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header)); 240 StringRef lcRange(lcStart, smh->sizeofcmds); 241 if (lcRange.end() > (start + objSize)) 242 return llvm::make_error<GenericError>("Load commands exceed file size"); 243 244 // Get architecture from mach_header. 245 f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype); 246 if (f->arch != arch) { 247 return llvm::make_error<GenericError>( 248 Twine("file is wrong architecture. Expected " 249 "(" + MachOLinkingContext::nameFromArch(arch) 250 + ") found (" 251 + MachOLinkingContext::nameFromArch(f->arch) 252 + ")" )); 253 } 254 // Copy file type and flags 255 f->fileType = HeaderFileType(smh->filetype); 256 f->flags = smh->flags; 257 258 259 // Pre-scan load commands looking for indirect symbol table. 260 uint32_t indirectSymbolTableOffset = 0; 261 uint32_t indirectSymbolTableCount = 0; 262 auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64, 263 [&](uint32_t cmd, uint32_t size, 264 const char *lc) -> bool { 265 if (cmd == LC_DYSYMTAB) { 266 const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc); 267 indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig); 268 indirectSymbolTableCount = read32(&d->nindirectsyms, isBig); 269 return true; 270 } 271 return false; 272 }); 273 if (ec) 274 return std::move(ec); 275 276 // Walk load commands looking for segments/sections and the symbol table. 277 const data_in_code_entry *dataInCode = nullptr; 278 const dyld_info_command *dyldInfo = nullptr; 279 uint32_t dataInCodeSize = 0; 280 ec = forEachLoadCommand(lcRange, lcCount, isBig, is64, 281 [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool { 282 switch(cmd) { 283 case LC_SEGMENT_64: 284 if (is64) { 285 const segment_command_64 *seg = 286 reinterpret_cast<const segment_command_64*>(lc); 287 const unsigned sectionCount = read32(&seg->nsects, isBig); 288 const section_64 *sects = reinterpret_cast<const section_64*> 289 (lc + sizeof(segment_command_64)); 290 const unsigned lcSize = sizeof(segment_command_64) 291 + sectionCount*sizeof(section_64); 292 // Verify sections don't extend beyond end of segment load command. 293 if (lcSize > size) 294 return true; 295 for (unsigned i=0; i < sectionCount; ++i) { 296 const section_64 *sect = §s[i]; 297 Section section; 298 section.segmentName = getString16(sect->segname); 299 section.sectionName = getString16(sect->sectname); 300 section.type = (SectionType)(read32(§->flags, isBig) & 301 SECTION_TYPE); 302 section.attributes = read32(§->flags, isBig) & SECTION_ATTRIBUTES; 303 section.alignment = 1 << read32(§->align, isBig); 304 section.address = read64(§->addr, isBig); 305 const uint8_t *content = 306 (const uint8_t *)start + read32(§->offset, isBig); 307 size_t contentSize = read64(§->size, isBig); 308 // Note: this assign() is copying the content bytes. Ideally, 309 // we can use a custom allocator for vector to avoid the copy. 310 section.content = llvm::makeArrayRef(content, contentSize); 311 appendRelocations(section.relocations, mb->getBuffer(), isBig, 312 read32(§->reloff, isBig), 313 read32(§->nreloc, isBig)); 314 if (section.type == S_NON_LAZY_SYMBOL_POINTERS) { 315 appendIndirectSymbols(section.indirectSymbols, mb->getBuffer(), 316 isBig, 317 indirectSymbolTableOffset, 318 indirectSymbolTableCount, 319 read32(§->reserved1, isBig), 320 contentSize/4); 321 } 322 f->sections.push_back(section); 323 } 324 } 325 break; 326 case LC_SEGMENT: 327 if (!is64) { 328 const segment_command *seg = 329 reinterpret_cast<const segment_command*>(lc); 330 const unsigned sectionCount = read32(&seg->nsects, isBig); 331 const section *sects = reinterpret_cast<const section*> 332 (lc + sizeof(segment_command)); 333 const unsigned lcSize = sizeof(segment_command) 334 + sectionCount*sizeof(section); 335 // Verify sections don't extend beyond end of segment load command. 336 if (lcSize > size) 337 return true; 338 for (unsigned i=0; i < sectionCount; ++i) { 339 const section *sect = §s[i]; 340 Section section; 341 section.segmentName = getString16(sect->segname); 342 section.sectionName = getString16(sect->sectname); 343 section.type = (SectionType)(read32(§->flags, isBig) & 344 SECTION_TYPE); 345 section.attributes = 346 read32((const uint8_t *)§->flags, isBig) & SECTION_ATTRIBUTES; 347 section.alignment = 1 << read32(§->align, isBig); 348 section.address = read32(§->addr, isBig); 349 const uint8_t *content = 350 (const uint8_t *)start + read32(§->offset, isBig); 351 size_t contentSize = read32(§->size, isBig); 352 // Note: this assign() is copying the content bytes. Ideally, 353 // we can use a custom allocator for vector to avoid the copy. 354 section.content = llvm::makeArrayRef(content, contentSize); 355 appendRelocations(section.relocations, mb->getBuffer(), isBig, 356 read32(§->reloff, isBig), 357 read32(§->nreloc, isBig)); 358 if (section.type == S_NON_LAZY_SYMBOL_POINTERS) { 359 appendIndirectSymbols( 360 section.indirectSymbols, mb->getBuffer(), isBig, 361 indirectSymbolTableOffset, indirectSymbolTableCount, 362 read32(§->reserved1, isBig), contentSize / 4); 363 } 364 f->sections.push_back(section); 365 } 366 } 367 break; 368 case LC_SYMTAB: { 369 const symtab_command *st = reinterpret_cast<const symtab_command*>(lc); 370 const char *strings = start + read32(&st->stroff, isBig); 371 const uint32_t strSize = read32(&st->strsize, isBig); 372 // Validate string pool and symbol table all in buffer. 373 if (read32((const uint8_t *)&st->stroff, isBig) + 374 read32((const uint8_t *)&st->strsize, isBig) > 375 objSize) 376 return true; 377 if (is64) { 378 const uint32_t symOffset = read32(&st->symoff, isBig); 379 const uint32_t symCount = read32(&st->nsyms, isBig); 380 if ( symOffset+(symCount*sizeof(nlist_64)) > objSize) 381 return true; 382 const nlist_64 *symbols = 383 reinterpret_cast<const nlist_64 *>(start + symOffset); 384 // Convert each nlist_64 to a lld::mach_o::normalized::Symbol. 385 for(uint32_t i=0; i < symCount; ++i) { 386 nlist_64 tempSym; 387 memcpy(&tempSym, &symbols[i], sizeof(nlist_64)); 388 const nlist_64 *sin = &tempSym; 389 if (isBig != llvm::sys::IsBigEndianHost) 390 swapStruct(tempSym); 391 Symbol sout; 392 if (sin->n_strx > strSize) 393 return true; 394 sout.name = &strings[sin->n_strx]; 395 sout.type = static_cast<NListType>(sin->n_type & (N_STAB|N_TYPE)); 396 sout.scope = (sin->n_type & (N_PEXT|N_EXT)); 397 sout.sect = sin->n_sect; 398 sout.desc = sin->n_desc; 399 sout.value = sin->n_value; 400 if (sin->n_type & N_STAB) 401 f->stabsSymbols.push_back(sout); 402 else if (sout.type == N_UNDF) 403 f->undefinedSymbols.push_back(sout); 404 else if (sin->n_type & N_EXT) 405 f->globalSymbols.push_back(sout); 406 else 407 f->localSymbols.push_back(sout); 408 } 409 } else { 410 const uint32_t symOffset = read32(&st->symoff, isBig); 411 const uint32_t symCount = read32(&st->nsyms, isBig); 412 if ( symOffset+(symCount*sizeof(nlist)) > objSize) 413 return true; 414 const nlist *symbols = 415 reinterpret_cast<const nlist *>(start + symOffset); 416 // Convert each nlist to a lld::mach_o::normalized::Symbol. 417 for(uint32_t i=0; i < symCount; ++i) { 418 const nlist *sin = &symbols[i]; 419 nlist tempSym; 420 if (isBig != llvm::sys::IsBigEndianHost) { 421 tempSym = *sin; swapStruct(tempSym); sin = &tempSym; 422 } 423 Symbol sout; 424 if (sin->n_strx > strSize) 425 return true; 426 sout.name = &strings[sin->n_strx]; 427 sout.type = (NListType)(sin->n_type & N_TYPE); 428 sout.scope = (sin->n_type & (N_PEXT|N_EXT)); 429 sout.sect = sin->n_sect; 430 sout.desc = sin->n_desc; 431 sout.value = sin->n_value; 432 if (sout.type == N_UNDF) 433 f->undefinedSymbols.push_back(sout); 434 else if (sout.scope == (SymbolScope)N_EXT) 435 f->globalSymbols.push_back(sout); 436 else if (sin->n_type & N_STAB) 437 f->stabsSymbols.push_back(sout); 438 else 439 f->localSymbols.push_back(sout); 440 } 441 } 442 } 443 break; 444 case LC_ID_DYLIB: { 445 const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc); 446 f->installName = lc + read32(&dl->dylib.name, isBig); 447 f->currentVersion = read32(&dl->dylib.current_version, isBig); 448 f->compatVersion = read32(&dl->dylib.compatibility_version, isBig); 449 } 450 break; 451 case LC_DATA_IN_CODE: { 452 const linkedit_data_command *ldc = 453 reinterpret_cast<const linkedit_data_command*>(lc); 454 dataInCode = reinterpret_cast<const data_in_code_entry *>( 455 start + read32(&ldc->dataoff, isBig)); 456 dataInCodeSize = read32(&ldc->datasize, isBig); 457 } 458 break; 459 case LC_LOAD_DYLIB: 460 case LC_LOAD_WEAK_DYLIB: 461 case LC_REEXPORT_DYLIB: 462 case LC_LOAD_UPWARD_DYLIB: { 463 const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc); 464 DependentDylib entry; 465 entry.path = lc + read32(&dl->dylib.name, isBig); 466 entry.kind = LoadCommandType(cmd); 467 entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig); 468 entry.currentVersion = read32(&dl->dylib.current_version, isBig); 469 f->dependentDylibs.push_back(entry); 470 } 471 break; 472 case LC_RPATH: { 473 const rpath_command *rpc = reinterpret_cast<const rpath_command *>(lc); 474 f->rpaths.push_back(lc + read32(&rpc->path, isBig)); 475 } 476 break; 477 case LC_DYLD_INFO: 478 case LC_DYLD_INFO_ONLY: 479 dyldInfo = reinterpret_cast<const dyld_info_command*>(lc); 480 break; 481 case LC_VERSION_MIN_MACOSX: 482 case LC_VERSION_MIN_IPHONEOS: 483 case LC_VERSION_MIN_WATCHOS: 484 case LC_VERSION_MIN_TVOS: 485 // If we are emitting an object file, then we may take the load command 486 // kind from these commands and pass it on to the output 487 // file. 488 f->minOSVersionKind = (LoadCommandType)cmd; 489 break; 490 } 491 return false; 492 }); 493 if (ec) 494 return std::move(ec); 495 496 if (dataInCode) { 497 // Convert on-disk data_in_code_entry array to DataInCode vector. 498 for (unsigned i=0; i < dataInCodeSize/sizeof(data_in_code_entry); ++i) { 499 DataInCode entry; 500 entry.offset = read32(&dataInCode[i].offset, isBig); 501 entry.length = read16(&dataInCode[i].length, isBig); 502 entry.kind = 503 (DataRegionType)read16((const uint8_t *)&dataInCode[i].kind, isBig); 504 f->dataInCode.push_back(entry); 505 } 506 } 507 508 if (dyldInfo) { 509 // If any exports, extract and add to normalized exportInfo vector. 510 if (dyldInfo->export_size) { 511 const uint8_t *trieStart = reinterpret_cast<const uint8_t *>( 512 start + read32(&dyldInfo->export_off, isBig)); 513 ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig)); 514 Error Err = Error::success(); 515 for (const ExportEntry &trieExport : MachOObjectFile::exports(Err, trie)) { 516 Export normExport; 517 normExport.name = trieExport.name().copy(f->ownedAllocations); 518 normExport.offset = trieExport.address(); 519 normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK); 520 normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK; 521 normExport.otherOffset = trieExport.other(); 522 if (!trieExport.otherName().empty()) 523 normExport.otherName = trieExport.otherName().copy(f->ownedAllocations); 524 f->exportInfo.push_back(normExport); 525 } 526 if (Err) 527 return std::move(Err); 528 } 529 } 530 531 return std::move(f); 532 } 533 534 class MachOObjectReader : public Reader { 535 public: 536 MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {} 537 538 bool canParse(file_magic magic, MemoryBufferRef mb) const override { 539 return (magic == file_magic::macho_object && mb.getBufferSize() > 32); 540 } 541 542 ErrorOr<std::unique_ptr<File>> 543 loadFile(std::unique_ptr<MemoryBuffer> mb, 544 const Registry ®istry) const override { 545 std::unique_ptr<File> ret = 546 llvm::make_unique<MachOFile>(std::move(mb), &_ctx); 547 return std::move(ret); 548 } 549 550 private: 551 MachOLinkingContext &_ctx; 552 }; 553 554 class MachODylibReader : public Reader { 555 public: 556 MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {} 557 558 bool canParse(file_magic magic, MemoryBufferRef mb) const override { 559 switch (magic) { 560 case file_magic::macho_dynamically_linked_shared_lib: 561 case file_magic::macho_dynamically_linked_shared_lib_stub: 562 return mb.getBufferSize() > 32; 563 default: 564 return false; 565 } 566 } 567 568 ErrorOr<std::unique_ptr<File>> 569 loadFile(std::unique_ptr<MemoryBuffer> mb, 570 const Registry ®istry) const override { 571 std::unique_ptr<File> ret = 572 llvm::make_unique<MachODylibFile>(std::move(mb), &_ctx); 573 return std::move(ret); 574 } 575 576 private: 577 MachOLinkingContext &_ctx; 578 }; 579 580 } // namespace normalized 581 } // namespace mach_o 582 583 void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) { 584 MachOLinkingContext::Arch arch = ctx.arch(); 585 add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx))); 586 add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx))); 587 addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), 588 ctx.archHandler().kindStrings()); 589 add(std::unique_ptr<YamlIOTaggedDocumentHandler>( 590 new mach_o::MachOYamlIOTaggedDocumentHandler(arch))); 591 } 592 593 594 } // namespace lld 595