Add first linker pass (StubsPass) which looks for calls to shared library symbols and replaces them with calls to a StubAtom. On ELF system, a "stub" is a PLT entry. Added a simple test case. Pass a Platform object to YAML reader and writer for converting fixup kinds between names and values. Change output of Resolver to be a File object instead of a vector of Atoms. Thus, passes operate on a File instead of just Atoms. Rework how to walk through a File's Atoms. Now iterator based instead of a method that visits each atom. llvm-svn: 152269
80 lines
2.3 KiB
C++
80 lines
2.3 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 is
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "lld/Core/Pass.h"
|
|
#include "lld/Core/File.h"
|
|
#include "lld/Core/Reference.h"
|
|
#include "lld/Platform/Platform.h"
|
|
|
|
|
|
namespace lld {
|
|
|
|
void StubsPass::perform() {
|
|
// Skip this pass if output format does not need stubs.
|
|
if ( !_platform.outputUsesStubs() )
|
|
return;
|
|
|
|
// Use map so all call sites to same shlib symbol use same stub
|
|
llvm::DenseMap<const SharedLibraryAtom*, const Atom*> shlibToStub;
|
|
|
|
// Scan all references in all atoms.
|
|
for(auto ait=_file.definedAtomsBegin(), aend=_file.definedAtomsEnd();
|
|
ait != aend; ++ait) {
|
|
const DefinedAtom* atom = *ait;
|
|
for (auto rit=atom->referencesBegin(), rend=atom->referencesEnd();
|
|
rit != rend; ++rit) {
|
|
const Reference* ref = *rit;
|
|
const Atom* target = ref->target();
|
|
assert(target != NULL);
|
|
// If the target of this reference is in a shared library
|
|
if ( const SharedLibraryAtom* shlbTarget = target->sharedLibraryAtom() ) {
|
|
// and this is a call to that shared library symbol.
|
|
if ( _platform.isBranch(ref) ) {
|
|
const Atom* stub;
|
|
// Replace the target with a reference to a stub
|
|
auto pos = shlibToStub.find(shlbTarget);
|
|
if ( pos == shlibToStub.end() ) {
|
|
// This is no existing stub. Create a new one.
|
|
stub = _platform.makeStub(*shlbTarget, _file);
|
|
shlibToStub[shlbTarget] = stub;
|
|
}
|
|
else {
|
|
// Reuse and existing stub
|
|
stub = pos->second;
|
|
}
|
|
assert(stub != NULL);
|
|
// Switch call site in atom to refrence stub instead of shlib atom.
|
|
(const_cast<Reference*>(ref))->setTarget(stub);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// add all created stubs to file
|
|
for (auto it=shlibToStub.begin(), end=shlibToStub.end(); it != end; ++it) {
|
|
_file.addAtom(*it->second);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|