/// Every atom defined in __TEXT,__text needs an entry in the final /// __unwind_info section (in order). These comes from two sources: /// + Input __compact_unwind sections where possible (after adding the /// personality function offset which is only known now). /// + A synthesised reference to __eh_frame if there's no __compact_unwind /// or too many personality functions to be accommodated. std::vector<CompactUnwindEntry> createUnwindInfoEntries( const SimpleFile &mergedFile, const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, const std::vector<const Atom *> &personalities, const std::map<const Atom *, const Atom *> &dwarfFrames) { std::vector<CompactUnwindEntry> unwindInfos; DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n"); // The final order in the __unwind_info section must be derived from the // order of typeCode atoms, since that's how they'll be put into the object // file eventually (yuck!). for (const DefinedAtom *atom : mergedFile.defined()) { if (atom->contentType() != DefinedAtom::typeCode) continue; unwindInfos.push_back(finalizeUnwindInfoEntryForAtom( atom, unwindLocs, personalities, dwarfFrames)); DEBUG(llvm::dbgs() << " Entry for " << atom->name() << ", final encoding=" << llvm::format("0x%08x", unwindInfos.back().encoding) << '\n'); } return unwindInfos; }
void collectDwarfFrameEntries(const SimpleFile &mergedFile, std::map<const Atom *, const Atom *> &dwarfFrames) { for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) { if (ehFrameAtom->contentType() != DefinedAtom::typeCFI) continue; if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom)) continue; if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom)) dwarfFrames[function] = ehFrameAtom; } }
llvm::Error perform(SimpleFile &mergedFile) override { // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { // Look at instructions accessing the GOT. bool canBypassGOT; if (!_archHandler.isGOTAccess(*ref, canBypassGOT)) continue; const Atom *target = ref->target(); assert(target != nullptr); if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) { // Update reference kind to reflect that target is a direct accesss. _archHandler.updateReferenceToGOT(ref, false); } else { // Replace the target with a reference to a GOT entry. const DefinedAtom *gotEntry = makeGOTEntry(target); const_cast<Reference *>(ref)->setTarget(gotEntry); // Update reference kind to reflect that target is now a GOT entry. _archHandler.updateReferenceToGOT(ref, true); } } } // Sort and add all created GOT Atoms to master file std::vector<const GOTEntryAtom *> entries; entries.reserve(_targetToGOT.size()); for (auto &it : _targetToGOT) entries.push_back(it.second); std::sort(entries.begin(), entries.end(), [](const GOTEntryAtom *left, const GOTEntryAtom *right) { return (left->slotName().compare(right->slotName()) < 0); }); for (const GOTEntryAtom *slot : entries) mergedFile.addAtom(*slot); return llvm::Error::success(); }
void collectCompactUnwindEntries( const SimpleFile &mergedFile, std::map<const Atom *, CompactUnwindEntry> &unwindLocs, std::vector<const Atom *> &personalities, uint32_t &numLSDAs) { DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n"); for (const DefinedAtom *atom : mergedFile.defined()) { if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo) continue; auto unwindEntry = extractCompactUnwindEntry(atom); unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry)); DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() << ", encoding=" << llvm::format("0x%08x", unwindEntry.encoding)); if (unwindEntry.personalityFunction) DEBUG(llvm::dbgs() << ", personality=" << unwindEntry.personalityFunction->name() << ", lsdaLoc=" << unwindEntry.lsdaLocation->name()); DEBUG(llvm::dbgs() << '\n'); // Count number of LSDAs we see, since we need to know how big the index // will be while laying out the section. if (unwindEntry.lsdaLocation) ++numLSDAs; // Gather the personality functions now, so that they're in deterministic // order (derived from the DefinedAtom order). if (unwindEntry.personalityFunction) { auto pFunc = std::find(personalities.begin(), personalities.end(), unwindEntry.personalityFunction); if (pFunc == personalities.end()) personalities.push_back(unwindEntry.personalityFunction); } } }
std::error_code perform(SimpleFile &mergedFile) override { // Skip this pass if output format uses text relocations instead of stubs. if (!this->noTextRelocs()) return std::error_code(); // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { // Look at call-sites. if (!this->isCallSite(*ref)) continue; const Atom *target = ref->target(); assert(target != nullptr); if (isa<SharedLibraryAtom>(target)) { // Calls to shared libraries go through stubs. _targetToUses[target].push_back(ref); continue; } const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target); if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){ // Calls to interposable functions in same linkage unit must also go // through a stub. assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); _targetToUses[target].push_back(ref); } } } // Exit early if no stubs needed. if (_targetToUses.empty()) return std::error_code(); // First add help-common and GOT slots used by lazy binding. SimpleDefinedAtom *helperCommonAtom = new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo); SimpleDefinedAtom *helperCacheNLPAtom = new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit()); SimpleDefinedAtom *helperBinderNLPAtom = new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit()); addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache, helperCacheNLPAtom); addOptReference( helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache, _stubInfo.optStubHelperCommonReferenceToCache, helperCacheNLPAtom); addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder, helperBinderNLPAtom); addOptReference( helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder, _stubInfo.optStubHelperCommonReferenceToBinder, helperBinderNLPAtom); mergedFile.addAtom(*helperCommonAtom); mergedFile.addAtom(*helperBinderNLPAtom); mergedFile.addAtom(*helperCacheNLPAtom); // Add reference to dyld_stub_binder in libSystem.dylib auto I = std::find_if( mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(), [&](const SharedLibraryAtom *atom) { return atom->name().equals(_stubInfo.binderSymbolName); }); assert(I != mergedFile.sharedLibrary().end() && "dyld_stub_binder not found"); addReference(helperBinderNLPAtom, _stubInfo.nonLazyPointerReferenceToBinder, *I); // Sort targets by name, so stubs and lazy pointers are consistent std::vector<const Atom *> targetsNeedingStubs; for (auto it : _targetToUses) targetsNeedingStubs.push_back(it.first); std::sort(targetsNeedingStubs.begin(), targetsNeedingStubs.end(), [](const Atom * left, const Atom * right) { return (left->name().compare(right->name()) < 0); }); // Make and append stubs, lazy pointers, and helpers in alphabetical order. unsigned lazyOffset = 0; for (const Atom *target : targetsNeedingStubs) { auto *stub = new (_file.allocator()) StubAtom(_file, _stubInfo); auto *lp = new (_file.allocator()) LazyPointerAtom(_file, _ctx.is64Bit()); auto *helper = new (_file.allocator()) StubHelperAtom(_file, _stubInfo); addReference(stub, _stubInfo.stubReferenceToLP, lp); addOptReference(stub, _stubInfo.stubReferenceToLP, _stubInfo.optStubReferenceToLP, lp); addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper); addReference(lp, _stubInfo.lazyPointerReferenceToFinal, target); addReference(helper, _stubInfo.stubHelperReferenceToImm, helper); addReferenceAddend(helper, _stubInfo.stubHelperReferenceToImm, helper, lazyOffset); addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon, helperCommonAtom); mergedFile.addAtom(*stub); mergedFile.addAtom(*lp); mergedFile.addAtom(*helper); // Update each reference to use stub. for (const Reference *ref : _targetToUses[target]) { assert(ref->target() == target); // Switch call site to reference stub atom instead. const_cast<Reference *>(ref)->setTarget(stub); } // Calculate new offset lazyOffset += target->name().size() + 12; } return std::error_code(); }