forked from OSchip/llvm-project
67 lines
2.4 KiB
C++
67 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(std::unique_ptr<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()))
|
|
continue;
|
|
const Atom *target = ref->target();
|
|
assert(target != nullptr);
|
|
if (target->definition() == Atom::definitionSharedLibrary) {
|
|
// Calls to shared libraries go through stubs.
|
|
replaceCalleeWithStub(target, 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);
|
|
replaceCalleeWithStub(target, ref);
|
|
}
|
|
}
|
|
}
|
|
// Add all created stubs and support Atoms.
|
|
this->addStubAtoms(*mergedFile);
|
|
}
|
|
|
|
void StubsPass::replaceCalleeWithStub(const Atom *target,
|
|
const Reference *ref) {
|
|
// 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);
|
|
}
|
|
|
|
} // end namespace lld
|