Example #1
0
  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();
  }
Example #2
0
  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();
  }
Example #3
0
File: ObjCPass.cpp Project: sas/lld
  std::error_code perform(SimpleFile &mergedFile) override {
    // Add the image info.
    mergedFile.addAtom(*getImageInfo());

    return std::error_code();
  }
  llvm::Error perform(SimpleFile &mergedFile) override {
    DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");

    std::map<const Atom *, CompactUnwindEntry> unwindLocs;
    std::map<const Atom *, const Atom *> dwarfFrames;
    std::vector<const Atom *> personalities;
    uint32_t numLSDAs = 0;

    // First collect all __compact_unwind and __eh_frame entries, addressable by
    // the function referred to.
    collectCompactUnwindEntries(mergedFile, unwindLocs, personalities,
                                numLSDAs);

    collectDwarfFrameEntries(mergedFile, dwarfFrames);

    // Skip rest of pass if no unwind info.
    if (unwindLocs.empty() && dwarfFrames.empty())
      return llvm::Error::success();

    // FIXME: if there are more than 4 personality functions then we need to
    // defer to DWARF info for the ones we don't put in the list. They should
    // also probably be sorted by frequency.
    assert(personalities.size() <= 4);

    // TODO: Find commmon encodings for use by compressed pages.
    std::vector<uint32_t> commonEncodings;

    // Now sort the entries by final address and fixup the compact encoding to
    // its final form (i.e. set personality function bits & create DWARF
    // references where needed).
    std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries(
        mergedFile, unwindLocs, personalities, dwarfFrames);

    // Remove any unused eh-frame atoms.
    pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames);

    // Finally, we can start creating pages based on these entries.

    DEBUG(llvm::dbgs() << "  Splitting entries into pages\n");
    // FIXME: we split the entries into pages naively: lots of 4k pages followed
    // by a small one. ld64 tried to minimize space and align them to real 4k
    // boundaries. That might be worth doing, or perhaps we could perform some
    // minor balancing for expected number of lookups.
    std::vector<UnwindInfoPage> pages;
    auto remainingInfos = llvm::makeArrayRef(unwindInfos);
    do {
      pages.push_back(UnwindInfoPage());

      // FIXME: we only create regular pages at the moment. These can hold up to
      // 1021 entries according to the documentation.
      unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());

      pages.back().entries = remainingInfos.slice(0, entriesInPage);
      remainingInfos = remainingInfos.slice(entriesInPage);

      DEBUG(llvm::dbgs()
            << "    Page from " << pages.back().entries[0].rangeStart->name()
            << " to " << pages.back().entries.back().rangeStart->name() << " + "
            << llvm::format("0x%x", pages.back().entries.back().rangeLength)
            << " has " << entriesInPage << " entries\n");
    } while (!remainingInfos.empty());

    auto *unwind = new (_file.allocator())
        UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
                       commonEncodings, pages, numLSDAs);
    mergedFile.addAtom(*unwind);

    // Finally, remove all __compact_unwind atoms now that we've processed them.
    mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
      return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
    });

    return llvm::Error::success();
  }