blob: 81a5915227b212cc788970aef83931b01077f346 [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()) {
137 _followOnRoots[targetAtom] = _followOnRoots[ai];
138 } else {
139 // The followon is part of another chain
140 if (iter->second == targetAtom) {
141 const DefinedAtom *a = targetAtom;
142 while (true) {
143 _followOnRoots[a] = _followOnRoots[ai];
144 // Set all the follow on's for the targetAtom to be
145 // the current root
146 AtomToAtomT::iterator targetFollowOnAtomsIter =
147 _followOnNexts.find(a);
148
149 if (targetFollowOnAtomsIter != _followOnNexts.end())
150 a = targetFollowOnAtomsIter->second;
151 else
152 break;
153 } // while true
154 } else { // the atom could be part of chain already
155 // Get to the root of the chain
156 const DefinedAtom *a = _followOnRoots[targetAtom];
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000157 const DefinedAtom *targetPrevAtom = nullptr;
158
159 // If the size of the atom is 0, and the target
160 // is already part of a chain, lets bring the current
161 // atom into the chain
162 size_t currentAtomSize = (*ai).size();
163
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000164 // Lets add to the chain only if the atoms that
165 // appear before the targetAtom in the chain
166 // are of size 0
167 bool foundNonZeroSizeAtom = false;
168 while (true) {
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000169 targetPrevAtom = a;
170
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000171 // Set all the follow on's for the targetAtom to be
172 // the current root
173 AtomToAtomT::iterator targetFollowOnAtomsIter =
174 _followOnNexts.find(a);
175
176 if (targetFollowOnAtomsIter != _followOnNexts.end())
177 a = targetFollowOnAtomsIter->second;
178 else
179 break;
180
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000181 if ((a->size() != 0) && (currentAtomSize != 0)) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000182 foundNonZeroSizeAtom = true;
183 break;
184 }
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000185
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000186 if (a == targetAtom)
187 break;
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000188
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000189 } // while true
190 if (foundNonZeroSizeAtom) {
191 // TODO: print warning that an impossible layout
192 // is being desired by the user
193 // Continue to the next atom
194 break;
195 }
196
Shankar Easwaranc44bc342013-03-06 21:59:27 +0000197 // If the atom is a zero sized atom, then make the target
198 // follow the zero sized atom, as the zero sized atom may be
199 // a weak symbol
200 if ((currentAtomSize == 0) && (targetPrevAtom)) {
201 _followOnNexts[targetPrevAtom] = ai;
202 _followOnRoots[ai] = _followOnRoots[targetPrevAtom];
203 _followOnNexts[ai] = targetAtom;
204 } else {
205 _followOnNexts[ai] = _followOnRoots[targetAtom];
206 // Set the root of all atoms in the
207 a = _followOnRoots[targetAtom];
208 while (true) {
209 _followOnRoots[a] = _followOnRoots[ai];
210 // Set all the follow on's for the targetAtom to be
211 // the current root
212 AtomToAtomT::iterator targetFollowOnAtomsIter =
213 _followOnNexts.find(a);
214 if (targetFollowOnAtomsIter != _followOnNexts.end())
215 a = targetFollowOnAtomsIter->second;
216 else
217 break;
218 } // while true
219 } // end else (currentAtomSize != 0)
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000220 } // end else
221 } // else
222 } // kindLayoutAfter
223 } // Reference
224 } // range
225}
226
227/// This pass builds the followon tables using InGroup relationships
228/// The algorithm follows a very simple approach
229/// a) If the rootAtom is not part of any root, create a new root with the
230/// as the head
231/// b) If the current Atom root is not found, then make the current atoms root
232/// point to the rootAtom
233/// c) If the root of the current Atom is itself a root of some other tree
234/// make all the atoms in the chain point to the ingroup reference
235/// d) Check to see if the current atom is part of the chain from the rootAtom
236/// if not add the atom to the chain, so that the current atom is part of the
237/// the chain where the rootAtom is in
238void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
239 // This table would convert precededby references to follow on
240 // references so that we have only one table
241 for (auto ai : range) {
242 for (const Reference *r : *ai) {
243 if (r->kind() == lld::Reference::kindInGroup) {
244 const DefinedAtom *rootAtom = llvm::dyn_cast<DefinedAtom>(r->target());
245 // If the root atom is not part of any root
246 // create a new root
247 if (_followOnRoots.count(rootAtom) == 0) {
248 _followOnRoots[rootAtom] = rootAtom;
249 }
250 // If the current Atom has not been seen yet and there is no root
251 // that has been set, set the root of the atom to the targetAtom
252 // as the targetAtom points to the ingroup root
253 auto iter = _followOnRoots.find(ai);
254 if (iter == _followOnRoots.end()) {
255 _followOnRoots[ai] = rootAtom;
256 }
257 else if (iter->second == ai) {
258 if (iter->second != rootAtom) {
259 const DefinedAtom *a = iter->second;
260 // Change all the followon next references to the ingroup reference root
261 while (true) {
262 _followOnRoots[a] = rootAtom;
263 // Set all the follow on's for the targetAtom to be
264 // the current root
265 AtomToAtomT::iterator targetFollowOnAtomsIter =
266 _followOnNexts.find(a);
267 if (targetFollowOnAtomsIter != _followOnNexts.end())
268 a = targetFollowOnAtomsIter->second;
269 else
270 break;
271 } // while true
272 }
273 }
274 else {
275 // TODO : Flag an error that the root of the tree
276 // is different, Here is an example
277 // Say there are atoms
278 // chain 1 : a->b->c
279 // chain 2 : d->e->f
280 // and e,f have their ingroup reference as a
281 // this could happen only if the root of e,f that is d
282 // has root as 'a'
283 continue;
284 }
285
286 // Check if the current atom is part of the chain
287 bool isAtomInChain = false;
288 const DefinedAtom *lastAtom = rootAtom;
289 while (true) {
290 AtomToAtomT::iterator followOnAtomsIter =
291 _followOnNexts.find(lastAtom);
292 if (followOnAtomsIter != _followOnNexts.end()) {
293 lastAtom = followOnAtomsIter->second;
294 if (lastAtom == ai) {
295 isAtomInChain = true;
296 break;
297 }
298 }
299 else
300 break;
301 } // findAtomInChain
302
303 if (!isAtomInChain)
304 _followOnNexts[lastAtom] = ai;
305 }
306 }
307 }
308}
309
310/// This pass builds the followon tables using Preceded By relationships
311/// The algorithm follows a very simple approach
312/// a) If the targetAtom is not part of any root and the current atom is not
313/// part of any root, create a chain with the current atom as root and
314/// the targetAtom as following the current atom
315/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
316/// of any chain and the currentAtom has no followOn's
317/// c) If the targetAtom is part of a different tree and the root of the
318/// targetAtom is itself, and if the current atom is not part of any root
319/// chain all the atoms together
320/// d) If the current atom has no followon and the root of the targetAtom is
321/// not equal to the root of the current atom(the targetAtom is not in the
322/// same chain), chain all the atoms that are lead by the targetAtom into
323/// the current chain
324void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
325 // This table would convert precededby references to follow on
326 // references so that we have only one table
327 for (auto ai : range) {
328 for (const Reference *r : *ai) {
329 if (r->kind() == lld::Reference::kindLayoutBefore) {
330 const DefinedAtom *targetAtom = llvm::dyn_cast<DefinedAtom>(r->target());
331 // Is the targetAtom not chained
332 if (_followOnRoots.count(targetAtom) == 0) {
333 // Is the current atom not part of any root ?
334 if (_followOnRoots.count(ai) == 0) {
335 _followOnRoots[ai] = ai;
336 _followOnNexts[ai] = targetAtom;
337 _followOnRoots[targetAtom] = _followOnRoots[ai];
338 } else if (_followOnNexts.count(ai) == 0) {
339 // Chain the targetAtom to the current Atom
340 // if the currentAtom has no followon references
341 _followOnNexts[ai] = targetAtom;
342 _followOnRoots[targetAtom] = _followOnRoots[ai];
343 }
344 } else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
345 // Is the targetAtom in chain with the targetAtom as the root ?
346 bool changeRoots = false;
347 if (_followOnRoots.count(ai) == 0) {
348 _followOnRoots[ai] = ai;
349 _followOnNexts[ai] = targetAtom;
350 _followOnRoots[targetAtom] = _followOnRoots[ai];
351 changeRoots = true;
352 } else if (_followOnNexts.count(ai) == 0) {
353 // Chain the targetAtom to the current Atom
354 // if the currentAtom has no followon references
355 if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
356 _followOnNexts[ai] = targetAtom;
357 _followOnRoots[targetAtom] = _followOnRoots[ai];
358 changeRoots = true;
359 }
360 }
361 // Change the roots of the targetAtom and its chain to
362 // the current atoms root
363 if (changeRoots) {
364 const DefinedAtom *a = _followOnRoots[targetAtom];
365 while (true) {
366 _followOnRoots[a] = _followOnRoots[ai];
367 // Set all the follow on's for the targetAtom to be
368 // the current root
369 AtomToAtomT::iterator targetFollowOnAtomsIter =
370 _followOnNexts.find(a);
371 if (targetFollowOnAtomsIter != _followOnNexts.end())
372 a = targetFollowOnAtomsIter->second;
373 else
374 break;
375 }
376 } // changeRoots
377 } // Is targetAtom root
378 } // kindLayoutBefore
379 } // Reference
380 } // atom iteration
381} // end function
382
383
384/// Build an ordinal override map by traversing the followon chain, and
385/// assigning ordinals to each atom, if the atoms have their ordinals
386/// already assigned skip the atom and move to the next. This is the
387/// main map thats used to sort the atoms while comparing two atoms together
388void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
389 uint64_t index = 0;
390 for (auto ai : range) {
391 const DefinedAtom *atom = ai;
392 AtomToAtomT::iterator start = _followOnRoots.find(atom);
393 if (start != _followOnRoots.end()) {
394 for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
395 nextAtom = _followOnNexts[nextAtom]) {
396 AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
397 if (pos == _ordinalOverrideMap.end()) {
398 _ordinalOverrideMap[nextAtom] = index++;
399 }
400 }
401 } else {
402 _ordinalOverrideMap[atom] = index;
403 }
404 }
405}
406
407/// Perform the actual pass
408void LayoutPass::perform(MutableFile &mergedFile) {
Shankar Easwaran34ab70f2013-02-07 20:16:12 +0000409 MutableFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
410
411 // Build follow on tables
412 buildFollowOnTable(atomRange);
413
414 // Build Ingroup reference table
415 buildInGroupTable(atomRange);
416
417 // Build preceded by tables
418 buildPrecededByTable(atomRange);
419
420 // Build override maps
421 buildOrdinalOverrideMap(atomRange);
422
423 // sort the atoms
424 std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
425}