void StubsPass::perform(MutableFile &mergedFile) { // Skip this pass if output format uses text relocations instead of stubs. if ( ! this->noTextRelocs() ) return; // 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->kind()) ) { const Atom* target = ref->target(); assert(target != nullptr); bool replaceCalleeWithStub = false; if ( target->definition() == Atom::definitionSharedLibrary ) { // Calls to shared libraries go through stubs. replaceCalleeWithStub = true; } else if (const DefinedAtom* defTarget = dyn_cast<DefinedAtom>(target)) { if ( defTarget->interposable() != DefinedAtom::interposeNo ) { // Calls to interposable functions in same linkage unit // must also go through a stub. assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); replaceCalleeWithStub = true; } } if ( replaceCalleeWithStub ) { // Make file-format specific stub and other support atoms. const DefinedAtom* stub = this->getStub(*target); assert(stub != nullptr); // Switch call site to reference stub atom instead. (const_cast<Reference*>(ref))->setTarget(stub); } } } } // Add all created stubs and support Atoms. this->addStubAtoms(mergedFile); }
void GOTPass::perform(MutableFile &mergedFile) { // Use map so all pointers to same symbol use same GOT entry. llvm::DenseMap<const Atom*, const DefinedAtom*> targetToGOT; // 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 (!isGOTAccess(ref->kind(), 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. updateReferenceToGOT(ref, false); continue; } // Replace the target with a reference to a GOT entry. const DefinedAtom *gotEntry = findGOTAtom(target, targetToGOT); if (!gotEntry) { gotEntry = makeGOTEntry(*target); assert(gotEntry != nullptr); assert(gotEntry->contentType() == DefinedAtom::typeGOT); targetToGOT[target] = gotEntry; } const_cast<Reference *>(ref)->setTarget(gotEntry); // Update reference kind to reflect that target is now a GOT entry. updateReferenceToGOT(ref, true); } } // add all created GOT Atoms to master file for (auto &it : targetToGOT) { mergedFile.addAtom(*it.second); } }