summaryrefslogtreecommitdiffstats
path: root/lld/lib/Passes/StubsPass.cpp
blob: b81d0a27a392f37a26a0173e5c5b32b42da1c2e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//===- 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.  The platform object does the work of creating the platform-specific
// StubAtom.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Pass.h"
#include "lld/Core/Platform.h"
#include "lld/Core/Reference.h"

#include "llvm/ADT/DenseMap.h"

namespace lld {

void StubsPass::perform() {
  // Skip this pass if output format uses text relocations instead of stubs.
  if ( !_platform.noTextRelocs() )
    return;

  // Scan all references in all atoms.
  for(const DefinedAtom *atom : _file.defined()) {
    for (const Reference *ref : *atom) {
      // Look at call-sites.
      if ( _platform.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 ) {
          // Ask platform to make stub and other support atoms.
          const DefinedAtom* stub = _platform.getStub(*target, _file);
          assert(stub != nullptr);
          // Switch call site to reference stub atom instead.
          (const_cast<Reference*>(ref))->setTarget(stub);
         }
      }
    }
  }

  // Tell platform to add all created stubs and support Atoms to file.
  _platform.addStubAtoms(_file);
}



}
OpenPOWER on IntegriCloud