std::map<StringRef, std::vector<COFFSharedLibraryAtom *> > IdataPass::groupByLoadName(MutableFile &file) { std::map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms; for (const SharedLibraryAtom *atom : file.sharedLibrary()) uniqueAtoms[atom->name()] = (COFFSharedLibraryAtom *)atom; std::map<StringRef, std::vector<COFFSharedLibraryAtom *> > ret; for (auto i : uniqueAtoms) { COFFSharedLibraryAtom *atom = i.second; ret[atom->loadName()].push_back(atom); } return ret; }
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); } }
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); }
/// Perform the actual pass void LayoutPass::perform(MutableFile &mergedFile) { ScopedTask task(getDefaultDomain(), "LayoutPass"); MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms(); // Build follow on tables buildFollowOnTable(atomRange); // Build Ingroup reference table buildInGroupTable(atomRange); // Build preceded by tables buildPrecededByTable(atomRange); // Check the structure of followon graph if running in debug mode. DEBUG(checkFollowonChain(atomRange)); // Build override maps buildOrdinalOverrideMap(atomRange); DEBUG({ llvm::dbgs() << "unsorted atoms:\n"; printDefinedAtoms(atomRange); });
nsresult FileService::Enqueue(FileHandle* aFileHandle, FileHelper* aFileHelper) { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); MOZ_ASSERT(aFileHandle, "Null pointer!"); MutableFile* mutableFile = aFileHandle->mMutableFile; if (mutableFile->IsInvalid()) { return NS_ERROR_NOT_AVAILABLE; } const nsACString& storageId = mutableFile->mStorageId; const nsAString& fileName = mutableFile->mFileName; bool modeIsWrite = aFileHandle->mMode == FileMode::Readwrite; StorageInfo* storageInfo; if (!mStorageInfos.Get(storageId, &storageInfo)) { nsAutoPtr<StorageInfo> newStorageInfo(new StorageInfo()); mStorageInfos.Put(storageId, newStorageInfo); storageInfo = newStorageInfo.forget(); } FileHandleQueue* existingFileHandleQueue = storageInfo->GetFileHandleQueue(aFileHandle); if (existingFileHandleQueue) { existingFileHandleQueue->Enqueue(aFileHelper); return NS_OK; } bool lockedForReading = storageInfo->IsFileLockedForReading(fileName); bool lockedForWriting = storageInfo->IsFileLockedForWriting(fileName); if (modeIsWrite) { if (!lockedForWriting) { storageInfo->LockFileForWriting(fileName); } } else { if (!lockedForReading) { storageInfo->LockFileForReading(fileName); } } if (lockedForWriting || (lockedForReading && modeIsWrite)) { storageInfo->CreateDelayedEnqueueInfo(aFileHandle, aFileHelper); } else { FileHandleQueue* fileHandleQueue = storageInfo->CreateFileHandleQueue(aFileHandle); if (aFileHelper) { // Enqueue() will queue the file helper if there's already something // running. That can't fail, so no need to eventually remove // storageInfo from the hash table. // // If the file helper is free to run then AsyncRun() is called on the // file helper. AsyncRun() is responsible for calling all necessary // callbacks when something fails. We're propagating the error here, // however there's no need to eventually remove storageInfo from // the hash table. Code behind AsyncRun() will take care of it. The last // item in the code path is NotifyFileHandleCompleted() which removes // storageInfo from the hash table if there are no file handles for // the file storage. nsresult rv = fileHandleQueue->Enqueue(aFileHelper); NS_ENSURE_SUCCESS(rv, rv); } } return NS_OK; }