CompactUnwindPass.cpp revision 309124
1//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===// 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/// \file A pass to convert MachO's __compact_unwind sections into the final 11/// __unwind_info format used during runtime. See 12/// mach-o/compact_unwind_encoding.h for more details on the formats involved. 13/// 14//===----------------------------------------------------------------------===// 15 16#include "ArchHandler.h" 17#include "File.h" 18#include "MachONormalizedFileBinaryUtils.h" 19#include "MachOPasses.h" 20#include "lld/Core/DefinedAtom.h" 21#include "lld/Core/File.h" 22#include "lld/Core/LLVM.h" 23#include "lld/Core/Reference.h" 24#include "lld/Core/Simple.h" 25#include "llvm/ADT/DenseMap.h" 26#include "llvm/Support/Debug.h" 27#include "llvm/Support/Format.h" 28 29#define DEBUG_TYPE "macho-compact-unwind" 30 31namespace lld { 32namespace mach_o { 33 34namespace { 35struct CompactUnwindEntry { 36 const Atom *rangeStart; 37 const Atom *personalityFunction; 38 const Atom *lsdaLocation; 39 const Atom *ehFrame; 40 41 uint32_t rangeLength; 42 43 // There are 3 types of compact unwind entry, distinguished by the encoding 44 // value: 0 indicates a function with no unwind info; 45 // _archHandler.dwarfCompactUnwindType() indicates that the entry defers to 46 // __eh_frame, and that the ehFrame entry will be valid; any other value is a 47 // real compact unwind entry -- personalityFunction will be set and 48 // lsdaLocation may be. 49 uint32_t encoding; 50 51 CompactUnwindEntry(const DefinedAtom *function) 52 : rangeStart(function), personalityFunction(nullptr), 53 lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()), 54 encoding(0) {} 55 56 CompactUnwindEntry() 57 : rangeStart(nullptr), personalityFunction(nullptr), 58 lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {} 59}; 60 61struct UnwindInfoPage { 62 ArrayRef<CompactUnwindEntry> entries; 63}; 64} 65 66class UnwindInfoAtom : public SimpleDefinedAtom { 67public: 68 UnwindInfoAtom(ArchHandler &archHandler, const File &file, bool isBig, 69 std::vector<const Atom *> &personalities, 70 std::vector<uint32_t> &commonEncodings, 71 std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) 72 : SimpleDefinedAtom(file), _archHandler(archHandler), 73 _commonEncodingsOffset(7 * sizeof(uint32_t)), 74 _personalityArrayOffset(_commonEncodingsOffset + 75 commonEncodings.size() * sizeof(uint32_t)), 76 _topLevelIndexOffset(_personalityArrayOffset + 77 personalities.size() * sizeof(uint32_t)), 78 _lsdaIndexOffset(_topLevelIndexOffset + 79 3 * (pages.size() + 1) * sizeof(uint32_t)), 80 _firstPageOffset(_lsdaIndexOffset + 2 * numLSDAs * sizeof(uint32_t)), 81 _isBig(isBig) { 82 83 addHeader(commonEncodings.size(), personalities.size(), pages.size()); 84 addCommonEncodings(commonEncodings); 85 addPersonalityFunctions(personalities); 86 addTopLevelIndexes(pages); 87 addLSDAIndexes(pages, numLSDAs); 88 addSecondLevelPages(pages); 89 } 90 91 ~UnwindInfoAtom() override = default; 92 93 ContentType contentType() const override { 94 return DefinedAtom::typeProcessedUnwindInfo; 95 } 96 97 Alignment alignment() const override { return 4; } 98 99 uint64_t size() const override { return _contents.size(); } 100 101 ContentPermissions permissions() const override { 102 return DefinedAtom::permR__; 103 } 104 105 ArrayRef<uint8_t> rawContent() const override { return _contents; } 106 107 void addHeader(uint32_t numCommon, uint32_t numPersonalities, 108 uint32_t numPages) { 109 using normalized::write32; 110 111 uint32_t headerSize = 7 * sizeof(uint32_t); 112 _contents.resize(headerSize); 113 114 uint8_t *headerEntries = _contents.data(); 115 // version 116 write32(headerEntries, 1, _isBig); 117 // commonEncodingsArraySectionOffset 118 write32(headerEntries + sizeof(uint32_t), _commonEncodingsOffset, _isBig); 119 // commonEncodingsArrayCount 120 write32(headerEntries + 2 * sizeof(uint32_t), numCommon, _isBig); 121 // personalityArraySectionOffset 122 write32(headerEntries + 3 * sizeof(uint32_t), _personalityArrayOffset, 123 _isBig); 124 // personalityArrayCount 125 write32(headerEntries + 4 * sizeof(uint32_t), numPersonalities, _isBig); 126 // indexSectionOffset 127 write32(headerEntries + 5 * sizeof(uint32_t), _topLevelIndexOffset, _isBig); 128 // indexCount 129 write32(headerEntries + 6 * sizeof(uint32_t), numPages + 1, _isBig); 130 } 131 132 /// Add the list of common encodings to the section; this is simply an array 133 /// of uint32_t compact values. Size has already been specified in the header. 134 void addCommonEncodings(std::vector<uint32_t> &commonEncodings) { 135 using normalized::write32; 136 137 _contents.resize(_commonEncodingsOffset + 138 commonEncodings.size() * sizeof(uint32_t)); 139 uint8_t *commonEncodingsArea = 140 reinterpret_cast<uint8_t *>(_contents.data() + _commonEncodingsOffset); 141 142 for (uint32_t encoding : commonEncodings) { 143 write32(commonEncodingsArea, encoding, _isBig); 144 commonEncodingsArea += sizeof(uint32_t); 145 } 146 } 147 148 void addPersonalityFunctions(std::vector<const Atom *> personalities) { 149 _contents.resize(_personalityArrayOffset + 150 personalities.size() * sizeof(uint32_t)); 151 152 for (unsigned i = 0; i < personalities.size(); ++i) 153 addImageReferenceIndirect(_personalityArrayOffset + i * sizeof(uint32_t), 154 personalities[i]); 155 } 156 157 void addTopLevelIndexes(std::vector<UnwindInfoPage> &pages) { 158 using normalized::write32; 159 160 uint32_t numIndexes = pages.size() + 1; 161 _contents.resize(_topLevelIndexOffset + numIndexes * 3 * sizeof(uint32_t)); 162 163 uint32_t pageLoc = _firstPageOffset; 164 165 // The most difficult job here is calculating the LSDAs; everything else 166 // follows fairly naturally, but we can't state where the first 167 uint8_t *indexData = &_contents[_topLevelIndexOffset]; 168 uint32_t numLSDAs = 0; 169 for (unsigned i = 0; i < pages.size(); ++i) { 170 // functionOffset 171 addImageReference(_topLevelIndexOffset + 3 * i * sizeof(uint32_t), 172 pages[i].entries[0].rangeStart); 173 // secondLevelPagesSectionOffset 174 write32(indexData + (3 * i + 1) * sizeof(uint32_t), pageLoc, _isBig); 175 write32(indexData + (3 * i + 2) * sizeof(uint32_t), 176 _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig); 177 178 for (auto &entry : pages[i].entries) 179 if (entry.lsdaLocation) 180 ++numLSDAs; 181 } 182 183 // Finally, write out the final sentinel index 184 auto &finalEntry = pages[pages.size() - 1].entries.back(); 185 addImageReference(_topLevelIndexOffset + 186 3 * pages.size() * sizeof(uint32_t), 187 finalEntry.rangeStart, finalEntry.rangeLength); 188 // secondLevelPagesSectionOffset => 0 189 write32(indexData + (3 * pages.size() + 2) * sizeof(uint32_t), 190 _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig); 191 } 192 193 void addLSDAIndexes(std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) { 194 _contents.resize(_lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t)); 195 196 uint32_t curOffset = _lsdaIndexOffset; 197 for (auto &page : pages) { 198 for (auto &entry : page.entries) { 199 if (!entry.lsdaLocation) 200 continue; 201 202 addImageReference(curOffset, entry.rangeStart); 203 addImageReference(curOffset + sizeof(uint32_t), entry.lsdaLocation); 204 curOffset += 2 * sizeof(uint32_t); 205 } 206 } 207 } 208 209 void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) { 210 for (auto &page : pages) { 211 addRegularSecondLevelPage(page); 212 } 213 } 214 215 void addRegularSecondLevelPage(const UnwindInfoPage &page) { 216 uint32_t curPageOffset = _contents.size(); 217 const int16_t headerSize = sizeof(uint32_t) + 2 * sizeof(uint16_t); 218 uint32_t curPageSize = 219 headerSize + 2 * page.entries.size() * sizeof(uint32_t); 220 _contents.resize(curPageOffset + curPageSize); 221 222 using normalized::write32; 223 using normalized::write16; 224 // 2 => regular page 225 write32(&_contents[curPageOffset], 2, _isBig); 226 // offset of 1st entry 227 write16(&_contents[curPageOffset + 4], headerSize, _isBig); 228 write16(&_contents[curPageOffset + 6], page.entries.size(), _isBig); 229 230 uint32_t pagePos = curPageOffset + headerSize; 231 for (auto &entry : page.entries) { 232 addImageReference(pagePos, entry.rangeStart); 233 234 write32(_contents.data() + pagePos + sizeof(uint32_t), entry.encoding, 235 _isBig); 236 if ((entry.encoding & 0x0f000000U) == 237 _archHandler.dwarfCompactUnwindType()) 238 addEhFrameReference(pagePos + sizeof(uint32_t), entry.ehFrame); 239 240 pagePos += 2 * sizeof(uint32_t); 241 } 242 } 243 244 void addEhFrameReference(uint32_t offset, const Atom *dest, 245 Reference::Addend addend = 0) { 246 addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(), 247 _archHandler.unwindRefToEhFrameKind(), offset, dest, addend); 248 } 249 250 void addImageReference(uint32_t offset, const Atom *dest, 251 Reference::Addend addend = 0) { 252 addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(), 253 _archHandler.imageOffsetKind(), offset, dest, addend); 254 } 255 256 void addImageReferenceIndirect(uint32_t offset, const Atom *dest) { 257 addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(), 258 _archHandler.imageOffsetKindIndirect(), offset, dest, 0); 259 } 260 261private: 262 mach_o::ArchHandler &_archHandler; 263 std::vector<uint8_t> _contents; 264 uint32_t _commonEncodingsOffset; 265 uint32_t _personalityArrayOffset; 266 uint32_t _topLevelIndexOffset; 267 uint32_t _lsdaIndexOffset; 268 uint32_t _firstPageOffset; 269 bool _isBig; 270}; 271 272/// Pass for instantiating and optimizing GOT slots. 273/// 274class CompactUnwindPass : public Pass { 275public: 276 CompactUnwindPass(const MachOLinkingContext &context) 277 : _ctx(context), _archHandler(_ctx.archHandler()), 278 _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")), 279 _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) { 280 _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); 281 } 282 283private: 284 llvm::Error perform(SimpleFile &mergedFile) override { 285 DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n"); 286 287 std::map<const Atom *, CompactUnwindEntry> unwindLocs; 288 std::map<const Atom *, const Atom *> dwarfFrames; 289 std::vector<const Atom *> personalities; 290 uint32_t numLSDAs = 0; 291 292 // First collect all __compact_unwind and __eh_frame entries, addressable by 293 // the function referred to. 294 collectCompactUnwindEntries(mergedFile, unwindLocs, personalities, 295 numLSDAs); 296 297 collectDwarfFrameEntries(mergedFile, dwarfFrames); 298 299 // Skip rest of pass if no unwind info. 300 if (unwindLocs.empty() && dwarfFrames.empty()) 301 return llvm::Error(); 302 303 // FIXME: if there are more than 4 personality functions then we need to 304 // defer to DWARF info for the ones we don't put in the list. They should 305 // also probably be sorted by frequency. 306 assert(personalities.size() <= 4); 307 308 // TODO: Find commmon encodings for use by compressed pages. 309 std::vector<uint32_t> commonEncodings; 310 311 // Now sort the entries by final address and fixup the compact encoding to 312 // its final form (i.e. set personality function bits & create DWARF 313 // references where needed). 314 std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries( 315 mergedFile, unwindLocs, personalities, dwarfFrames); 316 317 // Remove any unused eh-frame atoms. 318 pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames); 319 320 // Finally, we can start creating pages based on these entries. 321 322 DEBUG(llvm::dbgs() << " Splitting entries into pages\n"); 323 // FIXME: we split the entries into pages naively: lots of 4k pages followed 324 // by a small one. ld64 tried to minimize space and align them to real 4k 325 // boundaries. That might be worth doing, or perhaps we could perform some 326 // minor balancing for expected number of lookups. 327 std::vector<UnwindInfoPage> pages; 328 auto remainingInfos = llvm::makeArrayRef(unwindInfos); 329 do { 330 pages.push_back(UnwindInfoPage()); 331 332 // FIXME: we only create regular pages at the moment. These can hold up to 333 // 1021 entries according to the documentation. 334 unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size()); 335 336 pages.back().entries = remainingInfos.slice(0, entriesInPage); 337 remainingInfos = remainingInfos.slice(entriesInPage); 338 339 DEBUG(llvm::dbgs() 340 << " Page from " << pages.back().entries[0].rangeStart->name() 341 << " to " << pages.back().entries.back().rangeStart->name() << " + " 342 << llvm::format("0x%x", pages.back().entries.back().rangeLength) 343 << " has " << entriesInPage << " entries\n"); 344 } while (!remainingInfos.empty()); 345 346 auto *unwind = new (_file.allocator()) 347 UnwindInfoAtom(_archHandler, _file, _isBig, personalities, 348 commonEncodings, pages, numLSDAs); 349 mergedFile.addAtom(*unwind); 350 351 // Finally, remove all __compact_unwind atoms now that we've processed them. 352 mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) { 353 return atom->contentType() == DefinedAtom::typeCompactUnwindInfo; 354 }); 355 356 return llvm::Error(); 357 } 358 359 void collectCompactUnwindEntries( 360 const SimpleFile &mergedFile, 361 std::map<const Atom *, CompactUnwindEntry> &unwindLocs, 362 std::vector<const Atom *> &personalities, uint32_t &numLSDAs) { 363 DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n"); 364 365 for (const DefinedAtom *atom : mergedFile.defined()) { 366 if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo) 367 continue; 368 369 auto unwindEntry = extractCompactUnwindEntry(atom); 370 unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry)); 371 372 DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() 373 << ", encoding=" 374 << llvm::format("0x%08x", unwindEntry.encoding)); 375 if (unwindEntry.personalityFunction) 376 DEBUG(llvm::dbgs() << ", personality=" 377 << unwindEntry.personalityFunction->name() 378 << ", lsdaLoc=" << unwindEntry.lsdaLocation->name()); 379 DEBUG(llvm::dbgs() << '\n'); 380 381 // Count number of LSDAs we see, since we need to know how big the index 382 // will be while laying out the section. 383 if (unwindEntry.lsdaLocation) 384 ++numLSDAs; 385 386 // Gather the personality functions now, so that they're in deterministic 387 // order (derived from the DefinedAtom order). 388 if (unwindEntry.personalityFunction) { 389 auto pFunc = std::find(personalities.begin(), personalities.end(), 390 unwindEntry.personalityFunction); 391 if (pFunc == personalities.end()) 392 personalities.push_back(unwindEntry.personalityFunction); 393 } 394 } 395 } 396 397 CompactUnwindEntry extractCompactUnwindEntry(const DefinedAtom *atom) { 398 CompactUnwindEntry entry; 399 400 for (const Reference *ref : *atom) { 401 switch (ref->offsetInAtom()) { 402 case 0: 403 // FIXME: there could legitimately be functions with multiple encoding 404 // entries. However, nothing produces them at the moment. 405 assert(ref->addend() == 0 && "unexpected offset into function"); 406 entry.rangeStart = ref->target(); 407 break; 408 case 0x10: 409 assert(ref->addend() == 0 && "unexpected offset into personality fn"); 410 entry.personalityFunction = ref->target(); 411 break; 412 case 0x18: 413 assert(ref->addend() == 0 && "unexpected offset into LSDA atom"); 414 entry.lsdaLocation = ref->target(); 415 break; 416 } 417 } 418 419 if (atom->rawContent().size() < 4 * sizeof(uint32_t)) 420 return entry; 421 422 using normalized::read32; 423 entry.rangeLength = 424 read32(atom->rawContent().data() + 2 * sizeof(uint32_t), _isBig); 425 entry.encoding = 426 read32(atom->rawContent().data() + 3 * sizeof(uint32_t), _isBig); 427 return entry; 428 } 429 430 void 431 collectDwarfFrameEntries(const SimpleFile &mergedFile, 432 std::map<const Atom *, const Atom *> &dwarfFrames) { 433 for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) { 434 if (ehFrameAtom->contentType() != DefinedAtom::typeCFI) 435 continue; 436 if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom)) 437 continue; 438 439 if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom)) 440 dwarfFrames[function] = ehFrameAtom; 441 } 442 } 443 444 /// Every atom defined in __TEXT,__text needs an entry in the final 445 /// __unwind_info section (in order). These comes from two sources: 446 /// + Input __compact_unwind sections where possible (after adding the 447 /// personality function offset which is only known now). 448 /// + A synthesised reference to __eh_frame if there's no __compact_unwind 449 /// or too many personality functions to be accommodated. 450 std::vector<CompactUnwindEntry> createUnwindInfoEntries( 451 const SimpleFile &mergedFile, 452 const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, 453 const std::vector<const Atom *> &personalities, 454 const std::map<const Atom *, const Atom *> &dwarfFrames) { 455 std::vector<CompactUnwindEntry> unwindInfos; 456 457 DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n"); 458 // The final order in the __unwind_info section must be derived from the 459 // order of typeCode atoms, since that's how they'll be put into the object 460 // file eventually (yuck!). 461 for (const DefinedAtom *atom : mergedFile.defined()) { 462 if (atom->contentType() != DefinedAtom::typeCode) 463 continue; 464 465 unwindInfos.push_back(finalizeUnwindInfoEntryForAtom( 466 atom, unwindLocs, personalities, dwarfFrames)); 467 468 DEBUG(llvm::dbgs() << " Entry for " << atom->name() 469 << ", final encoding=" 470 << llvm::format("0x%08x", unwindInfos.back().encoding) 471 << '\n'); 472 } 473 474 return unwindInfos; 475 } 476 477 /// Remove unused EH frames. 478 /// 479 /// An EH frame is considered unused if there is a corresponding compact 480 /// unwind atom that doesn't require the EH frame. 481 void pruneUnusedEHFrames( 482 SimpleFile &mergedFile, 483 const std::vector<CompactUnwindEntry> &unwindInfos, 484 const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, 485 const std::map<const Atom *, const Atom *> &dwarfFrames) { 486 487 // Worklist of all 'used' FDEs. 488 std::vector<const DefinedAtom *> usedDwarfWorklist; 489 490 // We have to check two conditions when building the worklist: 491 // (1) EH frames used by compact unwind entries. 492 for (auto &entry : unwindInfos) 493 if (entry.ehFrame) 494 usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame)); 495 496 // (2) EH frames that reference functions with no corresponding compact 497 // unwind info. 498 for (auto &entry : dwarfFrames) 499 if (!unwindLocs.count(entry.first)) 500 usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second)); 501 502 // Add all transitively referenced CFI atoms by processing the worklist. 503 std::set<const Atom *> usedDwarfFrames; 504 while (!usedDwarfWorklist.empty()) { 505 const DefinedAtom *cfiAtom = usedDwarfWorklist.back(); 506 usedDwarfWorklist.pop_back(); 507 usedDwarfFrames.insert(cfiAtom); 508 for (const auto *ref : *cfiAtom) { 509 const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target()); 510 if (cfiTarget->contentType() == DefinedAtom::typeCFI) 511 usedDwarfWorklist.push_back(cfiTarget); 512 } 513 } 514 515 // Finally, delete all unreferenced CFI atoms. 516 mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) { 517 if ((atom->contentType() == DefinedAtom::typeCFI) && 518 !usedDwarfFrames.count(atom)) 519 return true; 520 return false; 521 }); 522 } 523 524 CompactUnwindEntry finalizeUnwindInfoEntryForAtom( 525 const DefinedAtom *function, 526 const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, 527 const std::vector<const Atom *> &personalities, 528 const std::map<const Atom *, const Atom *> &dwarfFrames) { 529 auto unwindLoc = unwindLocs.find(function); 530 531 CompactUnwindEntry entry; 532 if (unwindLoc == unwindLocs.end()) { 533 // Default entry has correct encoding (0 => no unwind), but we need to 534 // synthesise the function. 535 entry.rangeStart = function; 536 entry.rangeLength = function->size(); 537 } else 538 entry = unwindLoc->second; 539 540 541 // If there's no __compact_unwind entry, or it explicitly says to use 542 // __eh_frame, we need to try and fill in the correct DWARF atom. 543 if (entry.encoding == _archHandler.dwarfCompactUnwindType() || 544 entry.encoding == 0) { 545 auto dwarfFrame = dwarfFrames.find(function); 546 if (dwarfFrame != dwarfFrames.end()) { 547 entry.encoding = _archHandler.dwarfCompactUnwindType(); 548 entry.ehFrame = dwarfFrame->second; 549 } 550 } 551 552 auto personality = std::find(personalities.begin(), personalities.end(), 553 entry.personalityFunction); 554 uint32_t personalityIdx = personality == personalities.end() 555 ? 0 556 : personality - personalities.begin() + 1; 557 558 // FIXME: We should also use DWARF when there isn't enough room for the 559 // personality function in the compact encoding. 560 assert(personalityIdx < 4 && "too many personality functions"); 561 562 entry.encoding |= personalityIdx << 28; 563 564 if (entry.lsdaLocation) 565 entry.encoding |= 1U << 30; 566 567 return entry; 568 } 569 570 const MachOLinkingContext &_ctx; 571 mach_o::ArchHandler &_archHandler; 572 MachOFile &_file; 573 bool _isBig; 574}; 575 576void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) { 577 assert(ctx.needsCompactUnwindPass()); 578 pm.add(llvm::make_unique<CompactUnwindPass>(ctx)); 579} 580 581} // end namesapce mach_o 582} // end namesapce lld 583