blob: c3b83756e1bc867b6de261cccd09c4ded2a77dea [file] [log] [blame]
Michael J. Spencer773a8fb2011-12-18 08:27:59 +00001//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lld/Core/Resolver.h"
11#include "lld/Core/Atom.h"
12#include "lld/Core/File.h"
13#include "lld/Core/InputFiles.h"
14#include "lld/Core/SymbolTable.h"
15#include "lld/Core/UndefinedAtom.h"
16#include "lld/Platform/Platform.h"
17
18#include "llvm/Support/raw_ostream.h"
19
20#include <algorithm>
21#include <cassert>
22#include <vector>
23
24namespace lld {
25
26class NotLive {
27public:
28 bool operator()(const Atom *atom) const {
29 return !(atom->live() || !atom->deadStrip());
30 }
31};
32
33class AtomCoalescedAway {
34public:
35 AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}
36
37 bool operator()(const Atom *atom) const {
38 const Atom *rep = _symbolTable.replacement(atom);
39 return rep != atom;
40 }
41
42private:
43 SymbolTable &_symbolTable;
44};
45
46void Resolver::initializeState() {
47 _platform.initialize();
48}
49
50// add initial undefines from -u option
51void Resolver::addInitialUndefines() {
52
53}
54
55// add all atoms from all initial .o files
56void Resolver::buildInitialAtomList() {
57 // each input files contributes initial atoms
58 _atoms.reserve(1024);
59 _inputFiles.forEachInitialAtom(*this);
60
61 _completedInitialObjectFiles = true;
62}
63
64
65// called before the first atom in any file is added with doAtom()
66void Resolver::doFile(const File &file) {
67 // notify platform
68 _platform.fileAdded(file);
69}
70
71// called on each atom when a file is added
72void Resolver::doAtom(const Atom &atom) {
73 // notify platform
74 _platform.atomAdded(atom);
75
76 // add to list of known atoms
77 _atoms.push_back(&atom);
78
79 // adjust scope (e.g. force some globals to be hidden)
80 _platform.adjustScope(atom);
81
82 // non-static atoms need extra handling
83 if (atom.scope() != Atom::scopeTranslationUnit) {
84 // tell symbol table about non-static atoms
85 _symbolTable.add(atom);
86
87 // platform can add aliases for any symbol
88 std::vector<const Atom *> aliases;
89 if (_platform.getAliasAtoms(atom, aliases))
90 this->addAtoms(aliases);
91 }
92
93 if (_platform.deadCodeStripping()) {
94 // add to set of dead-strip-roots, all symbols that
95 // the compiler marks as don't strip
96 if (!atom.deadStrip())
97 _deadStripRoots.insert(&atom);
98
99 // add to set of dead-strip-roots, all symbols that
100 // the platform decided must remain
101 if (_platform.isDeadStripRoot(atom))
102 _deadStripRoots.insert(&atom);
103 }
104}
105
106// utility to add a vector of atoms
107void Resolver::addAtoms(const std::vector<const Atom *> &newAtoms) {
108 for (std::vector<const Atom *>::const_iterator it = newAtoms.begin();
109 it != newAtoms.end(); ++it) {
110 this->doAtom(**it);
111 }
112}
113
114// ask symbol table if any definitionUndefined atoms still exist
115// if so, keep searching libraries until no more atoms being added
116void Resolver::resolveUndefines() {
117 const bool searchArchives =
118 _platform.searchArchivesToOverrideTentativeDefinitions();
119 const bool searchDylibs =
120 _platform.searchSharedLibrariesToOverrideTentativeDefinitions();
121
122 // keep looping until no more undefines were added in last loop
123 unsigned int undefineGenCount = 0xFFFFFFFF;
124 while (undefineGenCount != _symbolTable.size()) {
125 undefineGenCount = _symbolTable.size();
126 std::vector<const Atom *> undefines;
127 _symbolTable.undefines(undefines);
128 for (std::vector<const Atom *>::iterator it = undefines.begin();
129 it != undefines.end(); ++it) {
130 llvm::StringRef undefName = (*it)->name();
131 // load for previous undefine may also have loaded this undefine
132 if (!_symbolTable.isDefined(undefName)) {
133 _inputFiles.searchLibraries(undefName, true, true, false, *this);
134
135 // give platform a chance to instantiate platform
136 // specific atoms (e.g. section boundary)
137 if (!_symbolTable.isDefined(undefName)) {
138 std::vector<const Atom *> platAtoms;
139 if (_platform.getPlatformAtoms(undefName, platAtoms))
140 this->addAtoms(platAtoms);
141 }
142 }
143 }
144 // search libraries for overrides of common symbols
145 if (searchArchives || searchDylibs) {
146 std::vector<const Atom *> tents;
147 for (std::vector<const Atom *>::iterator ait = _atoms.begin();
148 ait != _atoms.end(); ++ait) {
149 const Atom *atom = *ait;
150 if (atom->definition() == Atom::definitionTentative)
151 tents.push_back(atom);
152 }
153 for (std::vector<const Atom *>::iterator dit = tents.begin();
154 dit != tents.end(); ++dit) {
155 // load for previous tentative may also have loaded
156 // this tentative, so check again
157 llvm::StringRef tentName = (*dit)->name();
158 const Atom *curAtom = _symbolTable.findByName(tentName);
159 assert(curAtom != NULL);
160 if (curAtom->definition() == Atom::definitionTentative) {
161 _inputFiles.searchLibraries(tentName, searchDylibs, true, true,
162 *this);
163 }
164 }
165 }
166 }
167}
168
169// switch all references to undefined or coalesced away atoms
170// to the new defined atom
171void Resolver::updateReferences() {
172 for (std::vector<const Atom *>::iterator it = _atoms.begin();
173 it != _atoms.end(); ++it) {
174 const Atom *atom = *it;
175 for (Reference::iterator rit = atom->referencesBegin(),
176 end = atom->referencesEnd(); rit != end; ++rit) {
177 rit->target = _symbolTable.replacement(rit->target);
178 }
179 }
180}
181
182// for dead code stripping, recursively mark atom "live"
183void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) {
184 // if -why_live cares about this symbol, then dump chain
185 if ((previous->referer != NULL) && _platform.printWhyLive(atom.name())) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000186 llvm::errs() << atom.name() << " from " << atom.file().path() << "\n";
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000187 int depth = 1;
188 for (WhyLiveBackChain *p = previous; p != NULL;
189 p = p->previous, ++depth) {
190 for (int i = depth; i > 0; --i)
191 llvm::errs() << " ";
192 llvm::errs() << p->referer->name() << " from "
Nick Kledzikf46669c2011-12-21 23:29:36 +0000193 << p->referer->file().path() << "\n";
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000194 }
195 }
196
197 // if already marked live, then done (stop recursion)
198 if (atom.live())
199 return;
200
201 // mark this atom is live
202 const_cast<Atom *>(&atom)->setLive(true);
203
204 // mark all atoms it references as live
205 WhyLiveBackChain thisChain;
206 thisChain.previous = previous;
207 thisChain.referer = &atom;
208 for (Reference::iterator rit = atom.referencesBegin(),
209 end = atom.referencesEnd(); rit != end; ++rit) {
210 this->markLive(*(rit->target), &thisChain);
211 }
212}
213
214// remove all atoms not actually used
215void Resolver::deadStripOptimize() {
216 // only do this optimization with -dead_strip
217 if (!_platform.deadCodeStripping())
218 return;
219
220 // clear liveness on all atoms
221 for (std::vector<const Atom *>::iterator it = _atoms.begin();
222 it != _atoms.end(); ++it) {
223 const Atom *atom = *it;
224 const_cast<Atom *>(atom)->setLive(0);
225 }
226
227 // add entry point (main) to live roots
228 const Atom *entry = this->entryPoint();
229 if (entry != NULL)
230 _deadStripRoots.insert(entry);
231
232 // add -exported_symbols_list, -init, and -u entries to live roots
233 for (Platform::UndefinesIterator uit = _platform.initialUndefinesBegin();
234 uit != _platform.initialUndefinesEnd(); ++uit) {
235 llvm::StringRef sym = *uit;
236 const Atom *symAtom = _symbolTable.findByName(sym);
237 assert(symAtom->definition() != Atom::definitionUndefined);
238 _deadStripRoots.insert(symAtom);
239 }
240
241 // add platform specific helper atoms
242 std::vector<const Atom *> platRootAtoms;
243 if (_platform.getImplicitDeadStripRoots(platRootAtoms))
244 this->addAtoms(platRootAtoms);
245
246 // mark all roots as live, and recursively all atoms they reference
247 for (std::set<const Atom *>::iterator it = _deadStripRoots.begin();
248 it != _deadStripRoots.end(); ++it) {
249 WhyLiveBackChain rootChain;
250 rootChain.previous = NULL;
251 rootChain.referer = *it;
252 this->markLive(**it, &rootChain);
253 }
254
255 // now remove all non-live atoms from _atoms
256 _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
257 NotLive()), _atoms.end());
258}
259
260// error out if some undefines remain
261void Resolver::checkUndefines(bool final) {
262 // when using LTO, undefines are checked after bitcode is optimized
263 if (_haveLLVMObjs && !final)
264 return;
265
266 // build vector of remaining undefined symbols
267 std::vector<const Atom *> undefinedAtoms;
268 _symbolTable.undefines(undefinedAtoms);
269 if (_platform.deadCodeStripping()) {
270 // when dead code stripping we don't care if dead atoms are undefined
271 undefinedAtoms.erase(std::remove_if(
272 undefinedAtoms.begin(), undefinedAtoms.end(),
273 NotLive()), undefinedAtoms.end());
274 }
275
276 // let platform make error message about missing symbols
277 if (undefinedAtoms.size() != 0)
278 _platform.errorWithUndefines(undefinedAtoms, _atoms);
279}
280
281// remove from _atoms all coaleseced away atoms
282void Resolver::removeCoalescedAwayAtoms() {
283 _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
284 AtomCoalescedAway(_symbolTable)), _atoms.end());
285}
286
287// check for interactions between symbols defined in this linkage unit
288// and same symbol name in linked dynamic shared libraries
289void Resolver::checkDylibSymbolCollisions() {
290 for (std::vector<const Atom *>::const_iterator it = _atoms.begin();
291 it != _atoms.end(); ++it) {
292 const Atom *atom = *it;
293 if (atom->scope() == Atom::scopeGlobal) {
294 if (atom->definition() == Atom::definitionTentative) {
295 // See if any shared library also has symbol which
296 // collides with the tentative definition.
297 // SymbolTable will warn if needed.
298 _inputFiles.searchLibraries(atom->name(), true, false, false, *this);
299 }
300 }
301 }
302}
303
304// get "main" atom for linkage unit
305const Atom *Resolver::entryPoint() {
306 llvm::StringRef symbolName = _platform.entryPointName();
307 if (symbolName != NULL)
308 return _symbolTable.findByName(symbolName);
309
310 return NULL;
311}
312
313// give platform a chance to tweak the set of atoms
314void Resolver::tweakAtoms() {
315 _platform.postResolveTweaks(_atoms);
316}
317
318void Resolver::linkTimeOptimize() {
319 // FIX ME
320}
321
322std::vector<const Atom *> &Resolver::resolve() {
323 this->initializeState();
324 this->addInitialUndefines();
325 this->buildInitialAtomList();
326 this->resolveUndefines();
327 this->updateReferences();
328 this->deadStripOptimize();
329 this->checkUndefines(false);
330 this->removeCoalescedAwayAtoms();
331 this->checkDylibSymbolCollisions();
332 this->linkTimeOptimize();
333 this->tweakAtoms();
334 return _atoms;
335}
336
337} // namespace lld