blob: 2bf43aa8263190c23d7d425f9c1586090a0922d7 [file] [log] [blame]
Shankar Easwaran34ab70f2013-02-07 20:16:12 +00001//===- Passes/LayoutPass.cpp - Layout atoms -------------------------------===//
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
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000011#define DEBUG_TYPE "LayoutPass"
12
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000013#include "lld/Passes/LayoutPass.h"
14
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000015#include "llvm/Support/Debug.h"
16
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000017using namespace lld;
18
19/// The function compares atoms by sorting atoms in the following order
20/// a) Sorts atoms with the same permissions
21/// b) Sorts atoms with the same content Type
22/// c) Sorts atoms by Section position preference
23/// d) Sorts atoms by how they follow / precede each atom
24/// e) Sorts atoms on how they appear using File Ordinality
25/// f) Sorts atoms on how they appear within the File
26bool LayoutPass::CompareAtoms::operator()(const DefinedAtom *left,
27 const DefinedAtom *right) {
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000028 DEBUG(llvm::dbgs() << "Sorting " << left->name() << " " << right->name() << "\n");
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000029 if (left == right)
30 return false;
31
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000032 DEBUG(llvm::dbgs() << "Sorting by perms\n");
33
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000034 // Sort same permissions together.
35 DefinedAtom::ContentPermissions leftPerms = left->permissions();
36 DefinedAtom::ContentPermissions rightPerms = right->permissions();
37 if (leftPerms != rightPerms)
38 return leftPerms < rightPerms;
39
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000040 DEBUG(llvm::dbgs() << "Sorting by contentType\n");
41
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000042 // Sort same content types together.
43 DefinedAtom::ContentType leftType = left->contentType();
44 DefinedAtom::ContentType rightType = right->contentType();
45 if (leftType != rightType)
46 return leftType < rightType;
47
48 // TO DO: Sort atoms in customs sections together.
49
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000050 DEBUG(llvm::dbgs() << "Sorting by sectionPos\n");
51
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000052 // Sort by section position preference.
53 DefinedAtom::SectionPosition leftPos = left->sectionPosition();
54 DefinedAtom::SectionPosition rightPos = right->sectionPosition();
55 bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
56 bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
57 if (leftSpecialPos || rightSpecialPos) {
58 if (leftPos != rightPos)
59 return leftPos < rightPos;
60 }
61
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000062 DEBUG(llvm::dbgs() << "Sorting by override\n");
63
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000064 AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
65 AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
66 AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
67 if (lPos != end) {
68 if (rPos != end) {
69 // both left and right are overridden, so compare overridden ordinals
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000070 if (lPos->second != rPos->second)
71 return lPos->second < rPos->second;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000072 } else {
73 // left is overridden and right is not, so left < right
74 return true;
75 }
76 } else {
77 if (rPos != end) {
78 // right is overridden and left is not, so right < left
79 return false;
80 } else {
81 // neither are overridden,
82 // fall into default sorting below
83 }
84 }
85
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000086 DEBUG(llvm::dbgs() << "Sorting by .o order\n");
87
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000088 // Sort by .o order.
89 const File *leftFile = &left->file();
90 const File *rightFile = &right->file();
91 if (leftFile != rightFile)
92 return leftFile->ordinal() < rightFile->ordinal();
93
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +000094 DEBUG(llvm::dbgs() << "Sorting by ordinal\n");
95
Shankar Easwaran34ab70f2013-02-07 20:16:12 +000096 // Sort by atom order with .o file.
97 uint64_t leftOrdinal = left->ordinal();
98 uint64_t rightOrdinal = right->ordinal();
99 if (leftOrdinal != rightOrdinal)
100 return leftOrdinal < rightOrdinal;
101
Michael J. Spencer7f09a3d2013-02-26 01:35:30 +0000102 DEBUG(llvm::dbgs() << "Unordered\n");
103
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000104 return false;
105}
106
107/// This pass builds the followon tables described by two DenseMaps
108/// followOnRoots and followonNexts.
109/// The followOnRoots map contains a mapping of a DefinedAtom to its root
110/// The followOnNexts map contains a mapping of what DefinedAtom follows the
111/// current Atom
112/// The algorithm follows a very simple approach
113/// a) If the atom is first seen, then make that as the root atom
114/// b) The targetAtom which this Atom contains, has the root thats set to the
115/// root of the current atom
116/// c) If the targetAtom is part of a different tree and the root of the
117/// targetAtom is itself, Chain all the atoms that are contained in the tree
118/// to the current Tree
119/// d) If the targetAtom is part of a different chain and the root of the
120/// targetAtom until the targetAtom has all atoms of size 0, then chain the
121/// targetAtoms and its tree to the current chain
122void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
123 for (auto ai : range) {
124 for (const Reference *r : *ai) {
125 if (r->kind() == lld::Reference::kindLayoutAfter) {
126 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
127 _followOnNexts[ai] = targetAtom;
128 // If we find a followon for the first time, lets make that
129 // atom as the root atom
130 if (_followOnRoots.count(ai) == 0) {
131 _followOnRoots[ai] = ai;
132 }
133 // If the targetAtom is not a root of any chain, lets make
134 // the root of the targetAtom to the root of the current chain
135 auto iter = _followOnRoots.find(targetAtom);
136 if (iter == _followOnRoots.end()) {
Michael J. Spencer52fdb8b2013-03-09 01:41:27 +0000137 auto tmp = _followOnRoots[ai];
138 _followOnRoots[targetAtom] = tmp;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000139 } else {
140 // The followon is part of another chain
141 if (iter->second == targetAtom) {
142 const DefinedAtom *a = targetAtom;
143 while (true) {
144 _followOnRoots[a] = _followOnRoots[ai];
145 // Set all the follow on's for the targetAtom to be
146 // the current root
147 AtomToAtomT::iterator targetFollowOnAtomsIter =
148 _followOnNexts.find(a);
149
150 if (targetFollowOnAtomsIter != _followOnNexts.end())
151 a = targetFollowOnAtomsIter->second;
152 else
153 break;
154 } // while true
155 } else { // the atom could be part of chain already
156 // Get to the root of the chain
157 const DefinedAtom *a = _followOnRoots[targetAtom];
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000158 const DefinedAtom *targetPrevAtom = nullptr;
159
160 // If the size of the atom is 0, and the target
161 // is already part of a chain, lets bring the current
162 // atom into the chain
163 size_t currentAtomSize = (*ai).size();
164
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000165 // Lets add to the chain only if the atoms that
166 // appear before the targetAtom in the chain
167 // are of size 0
168 bool foundNonZeroSizeAtom = false;
169 while (true) {
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000170 targetPrevAtom = a;
171
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000172 // Set all the follow on's for the targetAtom to be
173 // the current root
174 AtomToAtomT::iterator targetFollowOnAtomsIter =
175 _followOnNexts.find(a);
176
177 if (targetFollowOnAtomsIter != _followOnNexts.end())
178 a = targetFollowOnAtomsIter->second;
179 else
180 break;
181
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000182 if ((a->size() != 0) && (currentAtomSize != 0)) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000183 foundNonZeroSizeAtom = true;
184 break;
185 }
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000186
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000187 if (a == targetAtom)
188 break;
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000189
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000190 } // while true
191 if (foundNonZeroSizeAtom) {
192 // TODO: print warning that an impossible layout
193 // is being desired by the user
194 // Continue to the next atom
195 break;
196 }
197
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000198 // If the atom is a zero sized atom, then make the target
199 // follow the zero sized atom, as the zero sized atom may be
200 // a weak symbol
201 if ((currentAtomSize == 0) && (targetPrevAtom)) {
202 _followOnNexts[targetPrevAtom] = ai;
203 _followOnRoots[ai] = _followOnRoots[targetPrevAtom];
204 _followOnNexts[ai] = targetAtom;
205 } else {
206 _followOnNexts[ai] = _followOnRoots[targetAtom];
207 // Set the root of all atoms in the
208 a = _followOnRoots[targetAtom];
209 while (true) {
210 _followOnRoots[a] = _followOnRoots[ai];
211 // Set all the follow on's for the targetAtom to be
212 // the current root
213 AtomToAtomT::iterator targetFollowOnAtomsIter =
214 _followOnNexts.find(a);
215 if (targetFollowOnAtomsIter != _followOnNexts.end())
216 a = targetFollowOnAtomsIter->second;
217 else
218 break;
219 } // while true
220 } // end else (currentAtomSize != 0)
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000221 } // end else
222 } // else
223 } // kindLayoutAfter
224 } // Reference
225 } // range
226}
227
228/// This pass builds the followon tables using InGroup relationships
229/// The algorithm follows a very simple approach
230/// a) If the rootAtom is not part of any root, create a new root with the
231/// as the head
232/// b) If the current Atom root is not found, then make the current atoms root
233/// point to the rootAtom
234/// c) If the root of the current Atom is itself a root of some other tree
235/// make all the atoms in the chain point to the ingroup reference
236/// d) Check to see if the current atom is part of the chain from the rootAtom
237/// if not add the atom to the chain, so that the current atom is part of the
238/// the chain where the rootAtom is in
239void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
240 // This table would convert precededby references to follow on
241 // references so that we have only one table
242 for (auto ai : range) {
243 for (const Reference *r : *ai) {
244 if (r->kind() == lld::Reference::kindInGroup) {
245 const DefinedAtom *rootAtom = llvm::dyn_cast<DefinedAtom>(r->target());
246 // If the root atom is not part of any root
247 // create a new root
248 if (_followOnRoots.count(rootAtom) == 0) {
249 _followOnRoots[rootAtom] = rootAtom;
250 }
251 // If the current Atom has not been seen yet and there is no root
252 // that has been set, set the root of the atom to the targetAtom
253 // as the targetAtom points to the ingroup root
254 auto iter = _followOnRoots.find(ai);
255 if (iter == _followOnRoots.end()) {
256 _followOnRoots[ai] = rootAtom;
257 }
258 else if (iter->second == ai) {
259 if (iter->second != rootAtom) {
260 const DefinedAtom *a = iter->second;
261 // Change all the followon next references to the ingroup reference root
262 while (true) {
263 _followOnRoots[a] = rootAtom;
264 // Set all the follow on's for the targetAtom to be
265 // the current root
266 AtomToAtomT::iterator targetFollowOnAtomsIter =
267 _followOnNexts.find(a);
268 if (targetFollowOnAtomsIter != _followOnNexts.end())
269 a = targetFollowOnAtomsIter->second;
270 else
271 break;
272 } // while true
273 }
274 }
275 else {
276 // TODO : Flag an error that the root of the tree
277 // is different, Here is an example
278 // Say there are atoms
279 // chain 1 : a->b->c
280 // chain 2 : d->e->f
281 // and e,f have their ingroup reference as a
282 // this could happen only if the root of e,f that is d
283 // has root as 'a'
284 continue;
285 }
286
287 // Check if the current atom is part of the chain
288 bool isAtomInChain = false;
289 const DefinedAtom *lastAtom = rootAtom;
290 while (true) {
291 AtomToAtomT::iterator followOnAtomsIter =
292 _followOnNexts.find(lastAtom);
293 if (followOnAtomsIter != _followOnNexts.end()) {
294 lastAtom = followOnAtomsIter->second;
295 if (lastAtom == ai) {
296 isAtomInChain = true;
297 break;
298 }
299 }
300 else
301 break;
302 } // findAtomInChain
303
304 if (!isAtomInChain)
305 _followOnNexts[lastAtom] = ai;
306 }
307 }
308 }
309}
310
311/// This pass builds the followon tables using Preceded By relationships
312/// The algorithm follows a very simple approach
313/// a) If the targetAtom is not part of any root and the current atom is not
314/// part of any root, create a chain with the current atom as root and
315/// the targetAtom as following the current atom
316/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
317/// of any chain and the currentAtom has no followOn's
318/// c) If the targetAtom is part of a different tree and the root of the
319/// targetAtom is itself, and if the current atom is not part of any root
320/// chain all the atoms together
321/// d) If the current atom has no followon and the root of the targetAtom is
322/// not equal to the root of the current atom(the targetAtom is not in the
323/// same chain), chain all the atoms that are lead by the targetAtom into
324/// the current chain
325void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
326 // This table would convert precededby references to follow on
327 // references so that we have only one table
328 for (auto ai : range) {
329 for (const Reference *r : *ai) {
330 if (r->kind() == lld::Reference::kindLayoutBefore) {
331 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
332 // Is the targetAtom not chained
333 if (_followOnRoots.count(targetAtom) == 0) {
334 // Is the current atom not part of any root ?
335 if (_followOnRoots.count(ai) == 0) {
336 _followOnRoots[ai] = ai;
337 _followOnNexts[ai] = targetAtom;
338 _followOnRoots[targetAtom] = _followOnRoots[ai];
339 } else if (_followOnNexts.count(ai) == 0) {
340 // Chain the targetAtom to the current Atom
341 // if the currentAtom has no followon references
342 _followOnNexts[ai] = targetAtom;
343 _followOnRoots[targetAtom] = _followOnRoots[ai];
344 }
345 } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
346 // Is the targetAtom in chain with the targetAtom as the root ?
347 bool changeRoots = false;
348 if (_followOnRoots.count(ai) == 0) {
349 _followOnRoots[ai] = ai;
350 _followOnNexts[ai] = targetAtom;
351 _followOnRoots[targetAtom] = _followOnRoots[ai];
352 changeRoots = true;
353 } else if (_followOnNexts.count(ai) == 0) {
354 // Chain the targetAtom to the current Atom
355 // if the currentAtom has no followon references
356 if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
357 _followOnNexts[ai] = targetAtom;
358 _followOnRoots[targetAtom] = _followOnRoots[ai];
359 changeRoots = true;
360 }
361 }
362 // Change the roots of the targetAtom and its chain to
363 // the current atoms root
364 if (changeRoots) {
365 const DefinedAtom *a = _followOnRoots[targetAtom];
366 while (true) {
367 _followOnRoots[a] = _followOnRoots[ai];
368 // Set all the follow on's for the targetAtom to be
369 // the current root
370 AtomToAtomT::iterator targetFollowOnAtomsIter =
371 _followOnNexts.find(a);
372 if (targetFollowOnAtomsIter != _followOnNexts.end())
373 a = targetFollowOnAtomsIter->second;
374 else
375 break;
376 }
377 } // changeRoots
378 } // Is targetAtom root
379 } // kindLayoutBefore
380 } // Reference
381 } // atom iteration
382} // end function
383
384
385/// Build an ordinal override map by traversing the followon chain, and
386/// assigning ordinals to each atom, if the atoms have their ordinals
387/// already assigned skip the atom and move to the next. This is the
388/// main map thats used to sort the atoms while comparing two atoms together
389void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
390 uint64_t index = 0;
391 for (auto ai : range) {
392 const DefinedAtom *atom = ai;
Michael J. Spencer1ecf8902013-03-12 00:10:00 +0000393 if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
394 continue;
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000395 AtomToAtomT::iterator start = _followOnRoots.find(atom);
396 if (start != _followOnRoots.end()) {
397 for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
398 nextAtom = _followOnNexts[nextAtom]) {
399 AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
400 if (pos == _ordinalOverrideMap.end()) {
401 _ordinalOverrideMap[nextAtom] = index++;
402 }
403 }
404 } else {
405 _ordinalOverrideMap[atom] = index;
406 }
407 }
408}
409
410/// Perform the actual pass
411void LayoutPass::perform(MutableFile &mergedFile) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000412 MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
413
414 // Build follow on tables
415 buildFollowOnTable(atomRange);
416
417 // Build Ingroup reference table
418 buildInGroupTable(atomRange);
419
420 // Build preceded by tables
421 buildPrecededByTable(atomRange);
422
423 // Build override maps
424 buildOrdinalOverrideMap(atomRange);
425
426 // sort the atoms
427 std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
428}