llvm-project/lld/lib/Passes/StubsPass.cpp
Nick Kledzik 1a6615dc88 Sources now require C++11 to build.
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
2012-03-08 00:18:30 +00:00

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);
}
}
}