llvm-project/lld/lib/Passes/StubsPass.cpp
Nick Kledzik abb6981f68 Major refactoring: Remove Platform concept. In its place there are
now Reader and Writer subclasses for each file format.  Each Reader and
Writer subclass defines an "options" class which controls how that Reader
or Writer operates.

llvm-svn: 157774
2012-05-31 22:34:00 +00:00

70 lines
2.4 KiB
C++

//===- Passes/StubsPass.cpp - Adds stubs ----------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This linker pass updates call-sites which have references to shared library
// atoms to instead have a reference to a stub (PLT entry) for the specified
// symbol. Each file format defines a subclass of StubsPass which implements
// the abstract methods for creating the file format specific StubAtoms.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Pass.h"
#include "lld/Core/Reference.h"
#include "llvm/ADT/DenseMap.h"
namespace lld {
void StubsPass::perform(File& 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);
}
}