summaryrefslogtreecommitdiffstats
path: root/lld/tools/lld-core/lld-core.cpp
blob: 96744a2d819872f65dbcaebbab457eb212aa7b7c (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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//===- tools/lld/lld-core.cpp - Linker Core Test Driver -----------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/InputFiles.h"
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/YamlReader.h"
#include "lld/Core/YamlWriter.h"
#include "lld/Core/NativeReader.h"
#include "lld/Core/NativeWriter.h"
#include "lld/Platform/Platform.h"

#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"

#include <vector>

using namespace lld;

static void error(llvm::Twine message) {
  llvm::errs() << "lld-core: " << message << ".\n";
}

static bool error(llvm::error_code ec) {
  if (ec) {
    error(ec.message());
    return true;
  }
  return false;
}

namespace {
class LdCore : public InputFiles, public Platform {
public:
  LdCore(std::vector<File *> &f) : _files(f) { }

  // InputFiles interface
  virtual void forEachInitialAtom(File::AtomHandler &) const;
  virtual bool searchLibraries(llvm::StringRef name, bool searchDylibs,
                               bool searchArchives, bool dataSymbolOnly,
                               File::AtomHandler &) const;

  virtual void initialize() { }

  // tell platform object another file has been added
  virtual void fileAdded(const File &file) { }

  // tell platform object another atom has been added
  virtual void atomAdded(const Atom &file) { }

  // give platform a chance to change each atom's scope
  virtual void adjustScope(const DefinedAtom &atom) { }

  // if specified atom needs alternate names, return AliasAtom(s)
  virtual bool getAliasAtoms(const Atom &atom,
                             std::vector<const DefinedAtom *>&) {
    return false;
  }

  // give platform a chance to resolve platform-specific undefs
  virtual bool getPlatformAtoms(llvm::StringRef undefined,
                                std::vector<const DefinedAtom *>&) {
    return false;
  }

  // resolver should remove unreferenced atoms
  virtual bool deadCodeStripping() {
    return false;
  }

  // atom must be kept so should be root of dead-strip graph
  virtual bool isDeadStripRoot(const Atom &atom) {
    return false;
  }

  // if target must have some atoms, denote here
  virtual bool getImplicitDeadStripRoots(std::vector<const DefinedAtom *>&) {
    return false;
  }

  // return entry point for output file (e.g. "main") or NULL
  virtual llvm::StringRef entryPointName() {
    return NULL;
  }

  // for iterating must-be-defined symbols ("main" or -u command line option)
  typedef llvm::StringRef const *UndefinesIterator;
  virtual UndefinesIterator initialUndefinesBegin() const {
    return NULL;
  }
  virtual UndefinesIterator initialUndefinesEnd() const {
    return NULL;
  }

  // if platform wants resolvers to search libraries for overrides
  virtual bool searchArchivesToOverrideTentativeDefinitions() {
    return false;
  }

  virtual bool searchSharedLibrariesToOverrideTentativeDefinitions() {
    return false;
  }

  // if platform allows symbol to remain undefined (e.g. -r)
  virtual bool allowUndefinedSymbol(llvm::StringRef name) {
    return true;
  }

  // for debugging dead code stripping, -why_live
  virtual bool printWhyLive(llvm::StringRef name) {
    return false;
  }

  virtual const Atom& handleMultipleDefinitions(const Atom& def1, 
                                                const Atom& def2) {
    llvm::report_fatal_error("symbol '" 
                            + llvm::Twine(def1.name()) 
                            + "' multiply defined");
  }

  // print out undefined symbol error messages in platform specific way
  virtual void errorWithUndefines(const std::vector<const Atom *> &undefs,
                                  const std::vector<const Atom *> &all) {}

  // last chance for platform to tweak atoms
  virtual void postResolveTweaks(std::vector<const Atom *> &all) {}

private:
  std::vector<File *> &_files;
};
}

void LdCore::forEachInitialAtom(File::AtomHandler &handler) const {
  for (std::vector<File *>::iterator it = _files.begin();
       it != _files.end(); ++it) {
    const File *file = *it;
    handler.doFile(*file);
    file->forEachAtom(handler);
  }
}

bool LdCore::searchLibraries(llvm::StringRef name, bool searchDylibs,
                             bool searchArchives, bool dataSymbolOnly,
                             File::AtomHandler &) const {
  return false;
}

namespace {
class MergedFile : public File {
public:
  MergedFile(std::vector<const Atom *> &a)
    : File("path"), _atoms(a) { }

  virtual bool forEachAtom(File::AtomHandler &handler) const {
    handler.doFile(*this);
    for (std::vector<const Atom *>::iterator it = _atoms.begin();
         it != _atoms.end(); ++it) {
      const Atom* atom = *it;
      switch ( atom->definition() ) {
        case Atom::definitionRegular:
          handler.doDefinedAtom(*(DefinedAtom*)atom);
          break;
        case Atom::definitionUndefined:
          handler.doUndefinedAtom(*(UndefinedAtom*)atom);
          break;
        default:
          // TO DO
          break;
      }
    }
    return true;
  }

  virtual bool justInTimeforEachAtom(llvm::StringRef name,
                                     File::AtomHandler &) const {
    return false;
  }

private:
  std::vector<const Atom *> &_atoms;
};
}

int main(int argc, const char *argv[]) {
  // Print a stack trace if we signal out.
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm::llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.

  // read input YAML doc into object file(s)
  std::vector<File *> files;
  if (error(yaml::parseObjectTextFileOrSTDIN(llvm::StringRef(argv[1]), files)))
    return 1;

  // merge all atom graphs
  LdCore core(files);
  Resolver resolver(core, core);
  std::vector<const Atom *> &mergedAtoms = resolver.resolve();
  MergedFile outFile(mergedAtoms);

  // write new atom graph out as YAML doc
  std::string errorInfo;
  llvm::raw_fd_ostream out("-", errorInfo);
//  yaml::writeObjectText(outFile, out);

  // make unique temp .o file to put generated object file
  int fd;
  llvm::SmallString<128> tempPath;
  llvm::sys::fs::unique_file("temp%%%%%.o", fd, tempPath);
  llvm::raw_fd_ostream  binaryOut(fd, /*shouldClose=*/true);
  
  // write native file
  writeNativeObjectFile(outFile, binaryOut);
  binaryOut.close();  // manually close so that file can be read next

  // read native file
  lld::File* natFile;
  parseNativeObjectFileOrSTDIN(tempPath, natFile);

  // write new atom graph out as YAML doc
  yaml::writeObjectText(*natFile, out);

  // delete temp .o file
  bool existed;
  llvm::sys::fs::remove(tempPath.str(), existed);

  return 0;
}
OpenPOWER on IntegriCloud