]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/order.cpp
684cb795d17519a1ff95e23fcbebbfae92f607bc
[apple/ld64.git] / src / ld / passes / order.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <stdint.h>
27 #include <math.h>
28 #include <unistd.h>
29 #include <dlfcn.h>
30 #include <mach/machine.h>
31
32 #include <vector>
33 #include <map>
34 #include <set>
35 #include <unordered_map>
36
37 #include "ld.hpp"
38 #include "order.h"
39
40 namespace ld {
41 namespace passes {
42 namespace order {
43
44 //
45 // The purpose of this pass is to take the graph of all Atoms and produce an ordered
46 // sequence of atoms. The constraints are that: 1) all Atoms of the same Segment must
47 // be contiguous, 2) all Atoms of the same Section must be contigous, 3) Atoms specified
48 // in an order are sequenced as in the order file and before Atoms not specified,
49 // 4) Atoms in the same section from the same .o file should be contiguous and sequenced
50 // in the same order they were in the .o file, 5) Atoms in the same Section but which came
51 // from different .o files should be sequenced in the same order that the .o files
52 // were passed to the linker (i.e. command line order).
53 //
54 // The way this is implemented is that the linker passes a "base ordinal" to each File
55 // as it is constructed. Add each atom has an objectAddress() method. Then
56 // sorting is just sorting by section, then by file ordinal, then by object address.
57 //
58 // If an -order_file is specified, it gets more complicated. First, an override-ordinal map
59 // is created. It causes the sort routine to ignore the value returned by ordinal() and objectAddress()
60 // and use the override value instead. Next some Atoms must be laid out consecutively
61 // (e.g. hand written assembly that does not end with return, but rather falls into
62 // the next label). This is modeled in via a kindNoneFollowOn fixup. The use of
63 // kindNoneFollowOn fixups produces "clusters" of atoms that must stay together.
64 // If an order_file tries to move one atom, it may need to move a whole cluster. The
65 // algorithm to do this models clusters using two maps. The "starts" maps maps any
66 // atom in a cluster to the first Atom in the cluster. The "nexts" maps an Atom in a
67 // cluster to the next Atom in the cluster. With this in place, while processing an
68 // order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
69 // given ordinal overrides.
70 //
71
72 class Layout
73 {
74 public:
75 Layout(const Options& opts, ld::Internal& state);
76 void doPass();
77 private:
78
79 class Comparer {
80 public:
81 Comparer(const Layout& l) : _layout(l) {}
82 bool operator()(const ld::Atom* left, const ld::Atom* right);
83 private:
84 const Layout& _layout;
85 };
86
87 typedef std::unordered_map<const char*, const ld::Atom*, CStringHash, CStringEquals> NameToAtom;
88
89 typedef std::map<const ld::Atom*, const ld::Atom*> AtomToAtom;
90
91 typedef std::map<const ld::Atom*, uint32_t> AtomToOrdinal;
92
93 const ld::Atom* findAtom(const Options::OrderedSymbol& orderedSymbol);
94 void buildNameTable();
95 void buildFollowOnTables();
96 void buildOrdinalOverrideMap();
97 const ld::Atom* follower(const ld::Atom* atom);
98 static bool matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName);
99 bool possibleToOrder(const ld::Internal::FinalSection*);
100
101 const Options& _options;
102 ld::Internal& _state;
103 AtomToAtom _followOnStarts;
104 AtomToAtom _followOnNexts;
105 NameToAtom _nameTable;
106 std::vector<const ld::Atom*> _nameCollisionAtoms;
107 AtomToOrdinal _ordinalOverrideMap;
108 Comparer _comparer;
109 bool _haveOrderFile;
110
111 static bool _s_log;
112 };
113
114 bool Layout::_s_log = false;
115
116 Layout::Layout(const Options& opts, ld::Internal& state)
117 : _options(opts), _state(state), _comparer(*this), _haveOrderFile(opts.orderedSymbolsCount() != 0)
118 {
119 }
120
121
122 bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
123 {
124 if ( left == right )
125 return false;
126
127 // magic section$start symbol always sorts to the start of its section
128 if ( left->contentType() == ld::Atom::typeSectionStart )
129 return true;
130 if ( right->contentType() == ld::Atom::typeSectionStart )
131 return false;
132
133 // if an -order_file is specified, then sorting is altered to sort those symbols first
134 if ( _layout._haveOrderFile ) {
135 AtomToOrdinal::const_iterator leftPos = _layout._ordinalOverrideMap.find(left);
136 AtomToOrdinal::const_iterator rightPos = _layout._ordinalOverrideMap.find(right);
137 AtomToOrdinal::const_iterator end = _layout._ordinalOverrideMap.end();
138 if ( leftPos != end ) {
139 if ( rightPos != end ) {
140 // both left and right are overridden, so compare overridden ordinals
141 return leftPos->second < rightPos->second;
142 }
143 else {
144 // left is overridden and right is not, so left < right
145 return true;
146 }
147 }
148 else {
149 if ( rightPos != end ) {
150 // right is overridden and left is not, so right < left
151 return false;
152 }
153 else {
154 // neither are overridden,
155 // fall into default sorting below
156 }
157 }
158 }
159
160 // magic section$end symbol always sorts to the end of its section
161 if ( left->contentType() == ld::Atom::typeSectionEnd )
162 return false;
163 if ( right->contentType() == ld::Atom::typeSectionEnd )
164 return true;
165
166 // aliases sort before their target
167 bool leftIsAlias = left->isAlias();
168 if ( leftIsAlias ) {
169 for (ld::Fixup::iterator fit=left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
170 if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
171 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
172 if ( fit->u.target == right )
173 return true; // left already before right
174 left = fit->u.target; // sort as if alias was its target
175 break;
176 }
177 }
178 }
179 bool rightIsAlias = right->isAlias();
180 if ( rightIsAlias ) {
181 for (ld::Fixup::iterator fit=right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
182 if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
183 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
184 if ( fit->u.target == left )
185 return false; // need to swap, alias is after target
186 right = fit->u.target; // continue with sort as if right was target
187 break;
188 }
189 }
190 }
191
192 // the __common section can have real or tentative definitions
193 // we want the real ones to sort before tentative ones
194 bool leftIsTent = (left->definition() == ld::Atom::definitionTentative);
195 bool rightIsTent = (right->definition() == ld::Atom::definitionTentative);
196 if ( leftIsTent != rightIsTent )
197 return rightIsTent;
198
199 #if 0
200 // initializers are auto sorted to start of section
201 if ( !fInitializerSet.empty() ) {
202 bool leftFirst = (fInitializerSet.count(left) != 0);
203 bool rightFirst = (fInitializerSet.count(right) != 0);
204 if ( leftFirst != rightFirst )
205 return leftFirst;
206 }
207
208 // terminators are auto sorted to end of section
209 if ( !fTerminatorSet.empty() ) {
210 bool leftLast = (fTerminatorSet.count(left) != 0);
211 bool rightLast = (fTerminatorSet.count(right) != 0);
212 if ( leftLast != rightLast )
213 return rightLast;
214 }
215 #endif
216
217 // sort by .o order
218 const ld::File* leftFile = left->file();
219 const ld::File* rightFile = right->file();
220 // <rdar://problem/10830126> properly sort if on file is NULL and the other is not
221 ld::File::Ordinal leftFileOrdinal = (leftFile != NULL) ? leftFile->ordinal() : ld::File::Ordinal::NullOrdinal();
222 ld::File::Ordinal rightFileOrdinal = (rightFile != NULL) ? rightFile->ordinal() : ld::File::Ordinal::NullOrdinal();
223 if ( leftFileOrdinal != rightFileOrdinal )
224 return leftFileOrdinal< rightFileOrdinal;
225
226 // tentative defintions have no address in .o file, they are traditionally laid out by name
227 if ( leftIsTent && rightIsTent )
228 return (strcmp(left->name(), right->name()) < 0);
229
230 // lastly sort by atom address
231 int64_t addrDiff = left->objectAddress() - right->objectAddress();
232 if ( addrDiff == 0 ) {
233 // have same address so one might be an alias, and aliases need to sort before target
234 if ( leftIsAlias != rightIsAlias )
235 return leftIsAlias;
236
237 // both at same address, sort by name
238 return (strcmp(left->name(), right->name()) < 0);
239 }
240 return (addrDiff < 0);
241 }
242
243 bool Layout::matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName)
244 {
245 if ( objectFileLeafName == NULL )
246 return true;
247 const char* atomFullPath = atom->file()->path();
248 const char* lastSlash = strrchr(atomFullPath, '/');
249 if ( lastSlash != NULL ) {
250 if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 )
251 return true;
252 }
253 else {
254 if ( strcmp(atomFullPath, objectFileLeafName) == 0 )
255 return true;
256 }
257 return false;
258 }
259
260
261 bool Layout::possibleToOrder(const ld::Internal::FinalSection* sect)
262 {
263 // atoms in only some sections can have order_file applied
264 switch ( sect->type() ) {
265 case ld::Section::typeUnclassified:
266 case ld::Section::typeCode:
267 case ld::Section::typeZeroFill:
268 return true;
269 case ld::Section::typeImportProxies:
270 return false;
271 default:
272 // if section has command line aliases, then we must apply ordering so aliases layout before targets
273 if ( _options.haveCmdLineAliases() ) {
274 for (std::vector<const ld::Atom*>::const_iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
275 const ld::Atom* atom = *ait;
276 if ( atom->isAlias() )
277 return true;
278 }
279 }
280 break;
281 }
282 return false;
283 }
284
285 void Layout::buildNameTable()
286 {
287 for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
288 ld::Internal::FinalSection* sect = *sit;
289 // some sections are not worth scanning for names
290 if ( ! possibleToOrder(sect) )
291 continue;
292 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
293 const ld::Atom* atom = *ait;
294 if ( atom->symbolTableInclusion() == ld::Atom::symbolTableIn ) {
295 const char* name = atom->name();
296 if ( name != NULL) {
297 // static function or data
298 NameToAtom::iterator pos = _nameTable.find(name);
299 if ( pos == _nameTable.end() )
300 _nameTable[name] = atom;
301 else {
302 const ld::Atom* existing = _nameTable[name];
303 if ( existing != NULL ) {
304 _nameCollisionAtoms.push_back(existing);
305 _nameTable[name] = NULL; // collision, denote with NULL
306 }
307 _nameCollisionAtoms.push_back(atom);
308 }
309 }
310 }
311 }
312 }
313 if ( _s_log ) {
314 fprintf(stderr, "buildNameTable() _nameTable:\n");
315 for(NameToAtom::iterator it=_nameTable.begin(); it != _nameTable.end(); ++it)
316 fprintf(stderr, " %p <- %s\n", it->second, it->first);
317 fprintf(stderr, "buildNameTable() _nameCollisionAtoms:\n");
318 for(std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); ++it)
319 fprintf(stderr, " %p, %s\n", *it, (*it)->name());
320 }
321 }
322
323
324 const ld::Atom* Layout::findAtom(const Options::OrderedSymbol& orderedSymbol)
325 {
326 // look for name in _nameTable
327 NameToAtom::iterator pos = _nameTable.find(orderedSymbol.symbolName);
328 if ( pos != _nameTable.end() ) {
329 if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) {
330 //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
331 return pos->second;
332 }
333 if ( pos->second == NULL ) {
334 // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
335 if ( ( orderedSymbol.objectFileName == NULL) && _options.printOrderFileStatistics() ) {
336 warning("%s specified in order_file but it exists in multiple .o files. "
337 "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName);
338 }
339 for (std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); it++) {
340 const ld::Atom* atom = *it;
341 if ( strcmp(atom->name(), orderedSymbol.symbolName) == 0 ) {
342 if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
343 return atom;
344 }
345 }
346 }
347 }
348 }
349
350 return NULL;
351 }
352
353 const ld::Atom* Layout::follower(const ld::Atom* atom)
354 {
355 for (const ld::Atom* a = _followOnStarts[atom]; a != NULL; a = _followOnNexts[a]) {
356 assert(a != NULL);
357 if ( _followOnNexts[a] == atom ) {
358 return a;
359 }
360 }
361 // no follower, first in chain
362 return NULL;
363 }
364
365 void Layout::buildFollowOnTables()
366 {
367 // if no -order_file, then skip building follow on table
368 if ( ! _haveOrderFile )
369 return;
370
371 // first make a pass to find all follow-on references and build start/next maps
372 // which are a way to represent clusters of atoms that must layout together
373 for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
374 ld::Internal::FinalSection* sect = *sit;
375 if ( !possibleToOrder(sect) )
376 continue;
377 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
378 const ld::Atom* atom = *ait;
379 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
380 if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
381 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
382 const ld::Atom* followOnAtom = fit->u.target;
383 if ( _s_log ) fprintf(stderr, "ref %p %s -> %p %s\n", atom, atom->name(), followOnAtom, followOnAtom->name());
384 assert(_followOnNexts.count(atom) == 0);
385 _followOnNexts[atom] = followOnAtom;
386 if ( _followOnStarts.count(atom) == 0 ) {
387 // first time atom has been seen, make it start of chain
388 _followOnStarts[atom] = atom;
389 if ( _s_log ) fprintf(stderr, " start %s -> %s\n", atom->name(), atom->name());
390 }
391 if ( _followOnStarts.count(followOnAtom) == 0 ) {
392 // first time followOnAtom has been seen, make atom start of chain
393 _followOnStarts[followOnAtom] = _followOnStarts[atom];
394 if ( _s_log ) fprintf(stderr, " start %s -> %s\n", followOnAtom->name(), _followOnStarts[atom]->name());
395 }
396 else {
397 if ( _followOnStarts[followOnAtom] == followOnAtom ) {
398 // followOnAtom atom already start of another chain, hook together
399 // and change all to use atom as start
400 const ld::Atom* a = followOnAtom;
401 while ( true ) {
402 assert(_followOnStarts[a] == followOnAtom);
403 _followOnStarts[a] = _followOnStarts[atom];
404 if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), _followOnStarts[atom]->name());
405 AtomToAtom::iterator pos = _followOnNexts.find(a);
406 if ( pos != _followOnNexts.end() )
407 a = pos->second;
408 else
409 break;
410 }
411 }
412 else {
413 // attempt to insert atom into existing followOn chain
414 const ld::Atom* curPrevToFollowOnAtom = this->follower(followOnAtom);
415 assert(curPrevToFollowOnAtom != NULL);
416 assert((atom->size() == 0) || (curPrevToFollowOnAtom->size() == 0));
417 if ( atom->size() == 0 ) {
418 // insert alias into existing chain right before followOnAtom
419 _followOnNexts[curPrevToFollowOnAtom] = atom;
420 _followOnNexts[atom] = followOnAtom;
421 _followOnStarts[atom] = _followOnStarts[followOnAtom];
422 }
423 else {
424 // insert real atom into existing chain right before alias of followOnAtom
425 const ld::Atom* curPrevPrevToFollowOn = this->follower(curPrevToFollowOnAtom);
426 if ( curPrevPrevToFollowOn == NULL ) {
427 // nothing previous, so make this a start of a new chain
428 _followOnNexts[atom] = curPrevToFollowOnAtom;
429 for (const ld::Atom* a = atom; a != NULL; a = _followOnNexts[a]) {
430 if ( _s_log ) fprintf(stderr, " adjust start for %s -> %s\n", a->name(), atom->name());
431 _followOnStarts[a] = atom;
432 }
433 }
434 else {
435 // is previous, insert into existing chain before previous
436 _followOnNexts[curPrevPrevToFollowOn] = atom;
437 _followOnNexts[atom] = curPrevToFollowOnAtom;
438 _followOnStarts[atom] = _followOnStarts[curPrevToFollowOnAtom];
439 }
440 }
441 }
442 }
443 }
444 }
445 }
446 }
447
448 if ( _s_log ) {
449 for(AtomToAtom::iterator it = _followOnStarts.begin(); it != _followOnStarts.end(); ++it)
450 fprintf(stderr, "start %s -> %s\n", it->first->name(), it->second->name());
451
452 for(AtomToAtom::iterator it = _followOnNexts.begin(); it != _followOnNexts.end(); ++it)
453 fprintf(stderr, "next %s -> %s\n", it->first->name(), (it->second != NULL) ? it->second->name() : "null");
454 }
455 }
456
457
458 class InSet
459 {
460 public:
461 InSet(const std::set<const ld::Atom*>& theSet) : _set(theSet) {}
462
463 bool operator()(const ld::Atom* atom) const {
464 return ( _set.count(atom) != 0 );
465 }
466 private:
467 const std::set<const ld::Atom*>& _set;
468 };
469
470
471 void Layout::buildOrdinalOverrideMap()
472 {
473 // if no -order_file, then skip building override map
474 if ( ! _haveOrderFile )
475 return;
476
477 // build fast name->atom table
478 this->buildNameTable();
479
480 // handle .o files that cannot have their atoms rearranged
481 // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
482 uint32_t index = 0;
483 uint32_t matchCount = 0;
484 std::set<const ld::Atom*> moveToData;
485 for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
486 const ld::Atom* atom = this->findAtom(*it);
487 if ( atom != NULL ) {
488 // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zero data
489 switch ( atom->section().type() ) {
490 case ld::Section::typeZeroFill:
491 case ld::Section::typeTentativeDefs:
492 if ( atom->size() <= 512 )
493 moveToData.insert(atom);
494 break;
495 default:
496 break;
497 }
498
499 AtomToAtom::iterator start = _followOnStarts.find(atom);
500 if ( start != _followOnStarts.end() ) {
501 // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
502 for(const ld::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = _followOnNexts[nextAtom]) {
503 AtomToOrdinal::iterator pos = _ordinalOverrideMap.find(nextAtom);
504 if ( pos == _ordinalOverrideMap.end() ) {
505 _ordinalOverrideMap[nextAtom] = index++;
506 if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->file()->path());
507 }
508 else {
509 if (_s_log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
510 atom->name(), index, _followOnStarts[atom]->name(), _ordinalOverrideMap[atom] );
511 }
512 }
513 }
514 else {
515 _ordinalOverrideMap[atom] = index;
516 if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->file()->path());
517 }
518 ++matchCount;
519 }
520 else {
521 if ( _options.printOrderFileStatistics() ) {
522 if ( it->objectFileName == NULL )
523 warning("can't find match for order_file entry: %s", it->symbolName);
524 else
525 warning("can't find match for order_file entry: %s/%s", it->objectFileName, it->symbolName);
526 }
527 }
528 ++index;
529 }
530 if ( _options.printOrderFileStatistics() && (_options.orderedSymbolsCount() != matchCount) ) {
531 warning("only %u out of %lu order_file symbols were applicable", matchCount, _options.orderedSymbolsCount() );
532 }
533
534 // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zeroed data
535 if ( ! moveToData.empty() ) {
536 // <rdar://problem/14919139> only move zero fill symbols to __data if there is a __data section
537 ld::Internal::FinalSection* dataSect = NULL;
538 for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
539 ld::Internal::FinalSection* sect = *sit;
540 if ( sect->type() == ld::Section::typeUnclassified ) {
541 if ( (strcmp(sect->sectionName(), "__data") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
542 dataSect = sect;
543 }
544 }
545
546 if ( dataSect != NULL ) {
547 // add atoms to __data
548 dataSect->atoms.insert(dataSect->atoms.end(), moveToData.begin(), moveToData.end());
549 // remove atoms from original sections
550 for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
551 ld::Internal::FinalSection* sect = *sit;
552 switch ( sect->type() ) {
553 case ld::Section::typeZeroFill:
554 case ld::Section::typeTentativeDefs:
555 sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), InSet(moveToData)), sect->atoms.end());
556 break;
557 default:
558 break;
559 }
560 }
561 }
562 }
563
564 }
565
566 void Layout::doPass()
567 {
568 // handle .o files that cannot have their atoms rearranged
569 this->buildFollowOnTables();
570
571 // assign new ordinal value to all ordered atoms
572 this->buildOrdinalOverrideMap();
573
574 // sort atoms in each section
575 for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
576 ld::Internal::FinalSection* sect = *sit;
577 //fprintf(stderr, "sorting section %s\n", sect->sectionName());
578 std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
579 }
580
581 //fprintf(stderr, "Sorted atoms:\n");
582 //for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
583 // ld::Internal::FinalSection* sect = *sit;
584 // for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
585 // const ld::Atom* atom = *ait;
586 // fprintf(stderr, "\t%p\t%s\t%s\n", atom, sect->sectionName(), atom->name());
587 // }
588 //}
589
590 }
591
592
593 void doPass(const Options& opts, ld::Internal& state)
594 {
595 Layout layout(opts, state);
596 layout.doPass();
597 }
598
599
600 } // namespace order_file
601 } // namespace passes
602 } // namespace ld