]>
Commit | Line | Data |
---|---|---|
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* | |
2 | * | |
3 | * Copyright (c) 2005-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 | // start temp HACK for cross builds | |
26 | extern "C" double log2 ( double ); | |
27 | //#define __MATH__ | |
28 | // end temp HACK for cross builds | |
29 | ||
30 | ||
31 | #include <stdlib.h> | |
32 | #include <sys/types.h> | |
33 | #include <sys/stat.h> | |
34 | #include <sys/mman.h> | |
35 | #include <sys/sysctl.h> | |
36 | #include <fcntl.h> | |
37 | #include <errno.h> | |
38 | #include <limits.h> | |
39 | #include <unistd.h> | |
40 | #include <execinfo.h> | |
41 | #include <mach/mach_time.h> | |
42 | #include <mach/vm_statistics.h> | |
43 | #include <mach/mach_init.h> | |
44 | #include <mach/mach_host.h> | |
45 | #include <dlfcn.h> | |
46 | #include <mach-o/dyld.h> | |
47 | #include <dlfcn.h> | |
48 | #include <AvailabilityMacros.h> | |
49 | ||
50 | #include <string> | |
51 | #include <map> | |
52 | #include <set> | |
53 | #include <string> | |
54 | #include <vector> | |
55 | #include <list> | |
56 | #include <algorithm> | |
57 | #include <unordered_map> | |
58 | #include <cxxabi.h> | |
59 | ||
60 | #include "Options.h" | |
61 | ||
62 | #include "MachOFileAbstraction.hpp" | |
63 | #include "Architectures.hpp" | |
64 | #include "ld.hpp" | |
65 | ||
66 | #include "InputFiles.h" | |
67 | #include "Resolver.h" | |
68 | #include "OutputFile.h" | |
69 | #include "Snapshot.h" | |
70 | ||
71 | #include "passes/stubs/make_stubs.h" | |
72 | #include "passes/dtrace_dof.h" | |
73 | #include "passes/got.h" | |
74 | #include "passes/tlvp.h" | |
75 | #include "passes/huge.h" | |
76 | #include "passes/compact_unwind.h" | |
77 | #include "passes/order.h" | |
78 | #include "passes/branch_island.h" | |
79 | #include "passes/branch_shim.h" | |
80 | #include "passes/objc.h" | |
81 | #include "passes/dylibs.h" | |
82 | #include "passes/bitcode_bundle.h" | |
83 | #include "passes/code_dedup.h" | |
84 | ||
85 | #include "parsers/archive_file.h" | |
86 | #include "parsers/macho_relocatable_file.h" | |
87 | #include "parsers/macho_dylib_file.h" | |
88 | #include "parsers/lto_file.h" | |
89 | #include "parsers/opaque_section_file.h" | |
90 | ||
91 | ||
92 | struct PerformanceStatistics { | |
93 | uint64_t startTool; | |
94 | uint64_t startInputFileProcessing; | |
95 | uint64_t startResolver; | |
96 | uint64_t startDylibs; | |
97 | uint64_t startPasses; | |
98 | uint64_t startOutput; | |
99 | uint64_t startDone; | |
100 | vm_statistics_data_t vmStart; | |
101 | vm_statistics_data_t vmEnd; | |
102 | }; | |
103 | ||
104 | ||
105 | class InternalState : public ld::Internal | |
106 | { | |
107 | public: | |
108 | InternalState(const Options& opts) : _options(opts), _atomsOrderedInSections(false) { } | |
109 | virtual ld::Internal::FinalSection* addAtom(const ld::Atom& atom); | |
110 | virtual ld::Internal::FinalSection* getFinalSection(const ld::Section&); | |
111 | ld::Internal::FinalSection* getFinalSection(const char* seg, const char* sect, ld::Section::Type type); | |
112 | ||
113 | uint64_t assignFileOffsets(); | |
114 | void setSectionSizesAndAlignments(); | |
115 | void sortSections(); | |
116 | void markAtomsOrdered() { _atomsOrderedInSections = true; } | |
117 | bool hasReferenceToWeakExternal(const ld::Atom& atom); | |
118 | ||
119 | virtual ~InternalState() {} | |
120 | private: | |
121 | ||
122 | class FinalSection : public ld::Internal::FinalSection | |
123 | { | |
124 | public: | |
125 | FinalSection(const ld::Section& sect, uint32_t sectionsSeen, const Options&); | |
126 | static int sectionComparer(const void* l, const void* r); | |
127 | static const ld::Section& outputSection(const ld::Section& sect, bool mergeZeroFill); | |
128 | static const ld::Section& objectOutputSection(const ld::Section& sect, const Options&); | |
129 | private: | |
130 | friend class InternalState; | |
131 | static uint32_t sectionOrder(const ld::Section& sect, uint32_t sectionsSeen, const Options& options); | |
132 | static uint32_t segmentOrder(const ld::Section& sect, const Options& options); | |
133 | uint32_t _segmentOrder; | |
134 | uint32_t _sectionOrder; | |
135 | ||
136 | static std::vector<const char*> _s_segmentsSeen; | |
137 | static ld::Section _s_DATA_data; | |
138 | static ld::Section _s_DATA_const; | |
139 | static ld::Section _s_TEXT_text; | |
140 | static ld::Section _s_TEXT_const; | |
141 | static ld::Section _s_DATA_nl_symbol_ptr; | |
142 | static ld::Section _s_DATA_common; | |
143 | static ld::Section _s_DATA_zerofill; | |
144 | static ld::Section _s_DATA_DIRTY_data; | |
145 | static ld::Section _s_DATA_CONST_const; | |
146 | }; | |
147 | ||
148 | bool hasZeroForFileOffset(const ld::Section* sect); | |
149 | uint64_t pageAlign(uint64_t addr); | |
150 | uint64_t pageAlign(uint64_t addr, uint64_t pageSize); | |
151 | ||
152 | struct SectionHash { | |
153 | size_t operator()(const ld::Section*) const; | |
154 | }; | |
155 | struct SectionEquals { | |
156 | bool operator()(const ld::Section* left, const ld::Section* right) const; | |
157 | }; | |
158 | typedef std::unordered_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut; | |
159 | ||
160 | ||
161 | SectionInToOut _sectionInToFinalMap; | |
162 | const Options& _options; | |
163 | bool _atomsOrderedInSections; | |
164 | }; | |
165 | ||
166 | ld::Section InternalState::FinalSection::_s_DATA_data( "__DATA", "__data", ld::Section::typeUnclassified); | |
167 | ld::Section InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified); | |
168 | ld::Section InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text", ld::Section::typeCode); | |
169 | ld::Section InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified); | |
170 | ld::Section InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer); | |
171 | ld::Section InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill); | |
172 | ld::Section InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill); | |
173 | ld::Section InternalState::FinalSection::_s_DATA_DIRTY_data( "__DATA_DIRTY", "__data", ld::Section::typeUnclassified); | |
174 | ld::Section InternalState::FinalSection::_s_DATA_CONST_const( "__DATA_CONST", "__const", ld::Section::typeUnclassified); | |
175 | ||
176 | std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen; | |
177 | ||
178 | ||
179 | size_t InternalState::SectionHash::operator()(const ld::Section* sect) const | |
180 | { | |
181 | size_t hash = 0; | |
182 | ld::CStringHash temp; | |
183 | hash += temp.operator()(sect->segmentName()); | |
184 | hash += temp.operator()(sect->sectionName()); | |
185 | return hash; | |
186 | } | |
187 | ||
188 | bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const | |
189 | { | |
190 | return (*left == *right); | |
191 | } | |
192 | ||
193 | ||
194 | InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, const Options& opts) | |
195 | : ld::Internal::FinalSection(sect), | |
196 | _segmentOrder(segmentOrder(sect, opts)), | |
197 | _sectionOrder(sectionOrder(sect, sectionsSeen, opts)) | |
198 | { | |
199 | //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n", | |
200 | // this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder); | |
201 | } | |
202 | ||
203 | const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect, bool mergeZeroFill) | |
204 | { | |
205 | // merge sections in final linked image | |
206 | switch ( sect.type() ) { | |
207 | case ld::Section::typeLiteral4: | |
208 | case ld::Section::typeLiteral8: | |
209 | case ld::Section::typeLiteral16: | |
210 | if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) | |
211 | return _s_TEXT_const; | |
212 | break; | |
213 | case ld::Section::typeUnclassified: | |
214 | if ( strcmp(sect.segmentName(), "__DATA") == 0 ) { | |
215 | if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 ) | |
216 | return _s_DATA_data; | |
217 | if ( strcmp(sect.sectionName(), "__const_coal") == 0 ) | |
218 | return _s_DATA_const; | |
219 | } | |
220 | else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) { | |
221 | if ( strcmp(sect.sectionName(), "__const_coal") == 0 ) | |
222 | return _s_TEXT_const; | |
223 | } | |
224 | else if ( strcmp(sect.segmentName(), "__DATA_DIRTY") == 0 ) { | |
225 | if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 ) | |
226 | return _s_DATA_DIRTY_data; | |
227 | } | |
228 | else if ( strcmp(sect.segmentName(), "__DATA_CONST") == 0 ) { | |
229 | if ( strcmp(sect.sectionName(), "__const_coal") == 0 ) | |
230 | return _s_DATA_CONST_const; | |
231 | } | |
232 | break; | |
233 | case ld::Section::typeZeroFill: | |
234 | if ( mergeZeroFill ) | |
235 | return _s_DATA_zerofill; | |
236 | break; | |
237 | case ld::Section::typeCode: | |
238 | if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) { | |
239 | if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 ) | |
240 | return _s_TEXT_text; | |
241 | else if ( strcmp(sect.sectionName(), "__StaticInit") == 0 ) | |
242 | return _s_TEXT_text; | |
243 | } | |
244 | break; | |
245 | case ld::Section::typeNonLazyPointer: | |
246 | if ( strcmp(sect.segmentName(), "__DATA") == 0 ) { | |
247 | if ( strcmp(sect.sectionName(), "__nl_symbol_ptr") == 0 ) | |
248 | return _s_DATA_nl_symbol_ptr; | |
249 | } | |
250 | else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) { | |
251 | if ( strcmp(sect.sectionName(), "__pointers") == 0 ) | |
252 | return _s_DATA_nl_symbol_ptr; | |
253 | } | |
254 | break; | |
255 | case ld::Section::typeTentativeDefs: | |
256 | if ( (strcmp(sect.segmentName(), "__DATA") == 0) && (strcmp(sect.sectionName(), "__comm/tent") == 0) ) { | |
257 | if ( mergeZeroFill ) | |
258 | return _s_DATA_zerofill; | |
259 | else | |
260 | return _s_DATA_common; | |
261 | } | |
262 | break; | |
263 | // FIX ME: more | |
264 | default: | |
265 | break; | |
266 | } | |
267 | return sect; | |
268 | } | |
269 | ||
270 | const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, const Options& options) | |
271 | { | |
272 | // in -r mode the only section that ever changes is __tenative -> __common with -d option | |
273 | if ( (sect.type() == ld::Section::typeTentativeDefs) && options.makeTentativeDefinitionsReal()) | |
274 | return _s_DATA_common; | |
275 | return sect; | |
276 | } | |
277 | ||
278 | uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, const Options& options) | |
279 | { | |
280 | if ( options.outputKind() == Options::kPreload ) { | |
281 | if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) | |
282 | return 0; | |
283 | const std::vector<const char*>& order = options.segmentOrder(); | |
284 | for (size_t i=0; i != order.size(); ++i) { | |
285 | if ( strcmp(sect.segmentName(), order[i]) == 0 ) | |
286 | return i+1; | |
287 | } | |
288 | if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) | |
289 | return order.size()+1; | |
290 | if ( strcmp(sect.segmentName(), "__DATA") == 0 ) | |
291 | return order.size()+2; | |
292 | } | |
293 | else { | |
294 | if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 ) | |
295 | return 0; | |
296 | if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) | |
297 | return 1; | |
298 | // in -r mode, want __DATA last so zerofill sections are at end | |
299 | if ( strcmp(sect.segmentName(), "__DATA") == 0 ) | |
300 | return (options.outputKind() == Options::kObjectFile) ? 5 : 2; | |
301 | if ( strcmp(sect.segmentName(), "__OBJC") == 0 ) | |
302 | return 3; | |
303 | if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) | |
304 | return 4; | |
305 | } | |
306 | // layout non-standard segments in order seen (+100 to shift beyond standard segments) | |
307 | for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) { | |
308 | if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 ) | |
309 | return i+100; | |
310 | } | |
311 | _s_segmentsSeen.push_back(sect.segmentName()); | |
312 | return _s_segmentsSeen.size()-1+100; | |
313 | } | |
314 | ||
315 | uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen, const Options& options) | |
316 | { | |
317 | if ( sect.type() == ld::Section::typeFirstSection ) | |
318 | return 0; | |
319 | if ( sect.type() == ld::Section::typeMachHeader ) | |
320 | return 1; | |
321 | if ( sect.type() == ld::Section::typeLastSection ) | |
322 | return INT_MAX; | |
323 | const std::vector<const char*>* sectionList = options.sectionOrder(sect.segmentName()); | |
324 | if ( ((options.outputKind() == Options::kPreload) || (options.outputKind() == Options::kDyld)) && (sectionList != NULL) ) { | |
325 | uint32_t count = 10; | |
326 | for (std::vector<const char*>::const_iterator it=sectionList->begin(); it != sectionList->end(); ++it, ++count) { | |
327 | if ( strcmp(*it, sect.sectionName()) == 0 ) | |
328 | return count; | |
329 | } | |
330 | } | |
331 | if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) { | |
332 | switch ( sect.type() ) { | |
333 | case ld::Section::typeCode: | |
334 | // <rdar://problem/8346444> make __text always be first "code" section | |
335 | if ( strcmp(sect.sectionName(), "__text") == 0 ) | |
336 | return 10; | |
337 | else | |
338 | return 11; | |
339 | case ld::Section::typeStub: | |
340 | return 12; | |
341 | case ld::Section::typeStubHelper: | |
342 | return 13; | |
343 | case ld::Section::typeLSDA: | |
344 | return INT_MAX-3; | |
345 | case ld::Section::typeUnwindInfo: | |
346 | return INT_MAX-2; | |
347 | case ld::Section::typeCFI: | |
348 | return INT_MAX-1; | |
349 | case ld::Section::typeStubClose: | |
350 | return INT_MAX; | |
351 | default: | |
352 | return sectionsSeen+20; | |
353 | } | |
354 | } | |
355 | else if ( strncmp(sect.segmentName(), "__DATA", 6) == 0 ) { | |
356 | switch ( sect.type() ) { | |
357 | case ld::Section::typeLazyPointerClose: | |
358 | return 8; | |
359 | case ld::Section::typeDyldInfo: | |
360 | return 9; | |
361 | case ld::Section::typeNonLazyPointer: | |
362 | return 10; | |
363 | case ld::Section::typeLazyPointer: | |
364 | return 11; | |
365 | case ld::Section::typeInitializerPointers: | |
366 | return 12; | |
367 | case ld::Section::typeTerminatorPointers: | |
368 | return 13; | |
369 | case ld::Section::typeTLVInitialValues: | |
370 | return INT_MAX-4; // need TLV zero-fill to follow TLV init values | |
371 | case ld::Section::typeTLVZeroFill: | |
372 | return INT_MAX-3; | |
373 | case ld::Section::typeZeroFill: | |
374 | // make sure __huge is always last zerofill section | |
375 | if ( strcmp(sect.sectionName(), "__huge") == 0 ) | |
376 | return INT_MAX-1; | |
377 | else | |
378 | return INT_MAX-2; | |
379 | default: | |
380 | // <rdar://problem/14348664> __DATA,__const section should be near __mod_init_func not __data | |
381 | if ( strcmp(sect.sectionName(), "__const") == 0 ) | |
382 | return 14; | |
383 | // <rdar://problem/17125893> Linker should put __cfstring near __const | |
384 | if ( strcmp(sect.sectionName(), "__cfstring") == 0 ) | |
385 | return 15; | |
386 | // <rdar://problem/7435296> Reorder sections to reduce page faults in object files | |
387 | else if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 ) | |
388 | return 20; | |
389 | else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 ) | |
390 | return 21; | |
391 | else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 ) | |
392 | return 22; | |
393 | else if ( strcmp(sect.sectionName(), "__objc_nlcatlist") == 0 ) | |
394 | return 23; | |
395 | else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 ) | |
396 | return 24; | |
397 | else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 ) | |
398 | return 25; | |
399 | else if ( strcmp(sect.sectionName(), "__objc_const") == 0 ) | |
400 | return 26; | |
401 | else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 ) | |
402 | return 27; | |
403 | else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 ) | |
404 | return 28; | |
405 | else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 ) | |
406 | return 29; | |
407 | else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 ) | |
408 | return 30; | |
409 | else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 ) | |
410 | return 31; | |
411 | else if ( strcmp(sect.sectionName(), "__objc_ivar") == 0 ) | |
412 | return 32; | |
413 | else if ( strcmp(sect.sectionName(), "__objc_data") == 0 ) | |
414 | return 33; | |
415 | else | |
416 | return sectionsSeen+40; | |
417 | } | |
418 | } | |
419 | // make sure zerofill in any other section is at end of segment | |
420 | if ( sect.type() == ld::Section::typeZeroFill ) | |
421 | return INT_MAX-1; | |
422 | return sectionsSeen+20; | |
423 | } | |
424 | ||
425 | #ifndef NDEBUG | |
426 | static void validateFixups(const ld::Atom& atom) | |
427 | { | |
428 | //fprintf(stderr, "validateFixups %s\n", atom.name()); | |
429 | bool lastWasClusterEnd = true; | |
430 | ld::Fixup::Cluster lastClusterSize = ld::Fixup::k1of1; | |
431 | uint32_t curClusterOffsetInAtom = 0; | |
432 | for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) { | |
433 | //fprintf(stderr, " fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize); | |
434 | assert((fit->offsetInAtom <= atom.size()) || (fit->offsetInAtom == 0)); | |
435 | if ( fit->firstInCluster() ) { | |
436 | assert(lastWasClusterEnd); | |
437 | curClusterOffsetInAtom = fit->offsetInAtom; | |
438 | lastWasClusterEnd = (fit->clusterSize == ld::Fixup::k1of1); | |
439 | } | |
440 | else { | |
441 | assert(!lastWasClusterEnd); | |
442 | assert(fit->offsetInAtom == curClusterOffsetInAtom); | |
443 | switch ((ld::Fixup::Cluster)fit->clusterSize) { | |
444 | case ld::Fixup::k1of1: | |
445 | case ld::Fixup::k1of2: | |
446 | case ld::Fixup::k1of3: | |
447 | case ld::Fixup::k1of4: | |
448 | case ld::Fixup::k1of5: | |
449 | lastWasClusterEnd = false; | |
450 | break; | |
451 | case ld::Fixup::k2of2: | |
452 | assert(lastClusterSize = ld::Fixup::k1of2); | |
453 | lastWasClusterEnd = true; | |
454 | break; | |
455 | case ld::Fixup::k2of3: | |
456 | assert(lastClusterSize = ld::Fixup::k1of3); | |
457 | lastWasClusterEnd = false; | |
458 | break; | |
459 | case ld::Fixup::k2of4: | |
460 | assert(lastClusterSize = ld::Fixup::k1of4); | |
461 | lastWasClusterEnd = false; | |
462 | break; | |
463 | case ld::Fixup::k2of5: | |
464 | assert(lastClusterSize = ld::Fixup::k1of5); | |
465 | lastWasClusterEnd = false; | |
466 | break; | |
467 | case ld::Fixup::k3of3: | |
468 | assert(lastClusterSize = ld::Fixup::k2of3); | |
469 | lastWasClusterEnd = true; | |
470 | break; | |
471 | case ld::Fixup::k3of4: | |
472 | assert(lastClusterSize = ld::Fixup::k2of4); | |
473 | lastWasClusterEnd = false; | |
474 | break; | |
475 | case ld::Fixup::k3of5: | |
476 | assert(lastClusterSize = ld::Fixup::k2of5); | |
477 | lastWasClusterEnd = false; | |
478 | break; | |
479 | case ld::Fixup::k4of4: | |
480 | assert(lastClusterSize = ld::Fixup::k3of4); | |
481 | lastWasClusterEnd = true; | |
482 | break; | |
483 | case ld::Fixup::k4of5: | |
484 | assert(lastClusterSize = ld::Fixup::k3of5); | |
485 | lastWasClusterEnd = false; | |
486 | break; | |
487 | case ld::Fixup::k5of5: | |
488 | assert(lastClusterSize = ld::Fixup::k4of5); | |
489 | lastWasClusterEnd = true; | |
490 | break; | |
491 | } | |
492 | } | |
493 | lastClusterSize = fit->clusterSize; | |
494 | if ( fit->binding == ld::Fixup::bindingDirectlyBound ) { | |
495 | assert(fit->u.target != NULL); | |
496 | } | |
497 | } | |
498 | switch (lastClusterSize) { | |
499 | case ld::Fixup::k1of1: | |
500 | case ld::Fixup::k2of2: | |
501 | case ld::Fixup::k3of3: | |
502 | case ld::Fixup::k4of4: | |
503 | case ld::Fixup::k5of5: | |
504 | break; | |
505 | default: | |
506 | assert(0 && "last fixup was not end of cluster"); | |
507 | break; | |
508 | } | |
509 | } | |
510 | #endif | |
511 | ||
512 | bool InternalState::hasReferenceToWeakExternal(const ld::Atom& atom) | |
513 | { | |
514 | // if __DATA,__const atom has pointer to weak external symbol, don't move to __DATA_CONST | |
515 | const ld::Atom* target = NULL; | |
516 | for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) { | |
517 | if ( fit->firstInCluster() ) { | |
518 | target = NULL; | |
519 | } | |
520 | switch ( fit->binding ) { | |
521 | case ld::Fixup::bindingNone: | |
522 | case ld::Fixup::bindingByNameUnbound: | |
523 | break; | |
524 | case ld::Fixup::bindingByContentBound: | |
525 | case ld::Fixup::bindingDirectlyBound: | |
526 | target = fit->u.target; | |
527 | break; | |
528 | case ld::Fixup::bindingsIndirectlyBound: | |
529 | target = indirectBindingTable[fit->u.bindingIndex]; | |
530 | break; | |
531 | } | |
532 | if ( (target != NULL) && (target->definition() == ld::Atom::definitionRegular) | |
533 | && (target->combine() == ld::Atom::combineByName) && (target->scope() == ld::Atom::scopeGlobal) ) { | |
534 | return true; | |
535 | } | |
536 | } | |
537 | return false; | |
538 | } | |
539 | ||
540 | ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom) | |
541 | { | |
542 | ld::Internal::FinalSection* fs = NULL; | |
543 | const char* sectName = atom.section().sectionName(); | |
544 | ld::Section::Type sectType = atom.section().type(); | |
545 | const ld::File* f = atom.file(); | |
546 | const char* path = (f != NULL) ? f->path() : NULL; | |
547 | if ( atom.section().type() == ld::Section::typeTentativeDefs ) { | |
548 | // tentative defintions don't have a real section name yet | |
549 | sectType = ld::Section::typeZeroFill; | |
550 | if ( _options.mergeZeroFill() ) | |
551 | sectName = FinalSection::_s_DATA_zerofill.sectionName(); | |
552 | else | |
553 | sectName = FinalSection::_s_DATA_common.sectionName(); | |
554 | } | |
555 | // Support for -move_to_r._segment | |
556 | if ( atom.symbolTableInclusion() == ld::Atom::symbolTableIn ) { | |
557 | const char* dstSeg; | |
558 | //fprintf(stderr, "%s\n", atom.name()); | |
559 | bool wildCardMatch; | |
560 | if ( _options.moveRwSymbol(atom.name(), path, dstSeg, wildCardMatch) ) { | |
561 | if ( (sectType != ld::Section::typeZeroFill) | |
562 | && (sectType != ld::Section::typeUnclassified) | |
563 | && (sectType != ld::Section::typeTentativeDefs) | |
564 | && (sectType != ld::Section::typeDyldInfo) ) { | |
565 | if ( !wildCardMatch ) | |
566 | warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not data (is %d)", atom.name(), path, dstSeg, sectType); | |
567 | } | |
568 | else { | |
569 | if ( _options.traceSymbolLayout() ) | |
570 | printf("symbol '%s', -move_to_rw_segment mapped it to %s/%s\n", atom.name(), dstSeg, sectName); | |
571 | fs = this->getFinalSection(dstSeg, sectName, sectType); | |
572 | } | |
573 | } | |
574 | if ( (fs == NULL) && _options.moveRoSymbol(atom.name(), path, dstSeg, wildCardMatch) ) { | |
575 | if ( (sectType != ld::Section::typeCode) | |
576 | && (sectType != ld::Section::typeUnclassified) ) { | |
577 | if ( !wildCardMatch ) | |
578 | warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not code (is %d)", atom.name(), path, dstSeg, sectType); | |
579 | } | |
580 | else { | |
581 | if ( _options.traceSymbolLayout() ) | |
582 | printf("symbol '%s', -move_to_ro_segment mapped it to %s/%s\n", atom.name(), dstSeg, sectName); | |
583 | fs = this->getFinalSection(dstSeg, sectName, ld::Section::typeCode); | |
584 | } | |
585 | } | |
586 | } | |
587 | // support for -rename_section and -rename_segment | |
588 | if ( fs == NULL ) { | |
589 | const std::vector<Options::SectionRename>& sectRenames = _options.sectionRenames(); | |
590 | const std::vector<Options::SegmentRename>& segRenames = _options.segmentRenames(); | |
591 | for ( std::vector<Options::SectionRename>::const_iterator it=sectRenames.begin(); it != sectRenames.end(); ++it) { | |
592 | if ( (strcmp(sectName, it->fromSection) == 0) && (strcmp(atom.section().segmentName(), it->fromSegment) == 0) ) { | |
593 | if ( _options.useDataConstSegment() && (strcmp(sectName, "__const") == 0) | |
594 | && (strcmp(atom.section().segmentName(), "__DATA") == 0) && hasReferenceToWeakExternal(atom) ) { | |
595 | // if __DATA,__const atom has pointer to weak external symbol, don't move to __DATA_CONST | |
596 | fs = this->getFinalSection("__DATA", "__const_weak", sectType); | |
597 | if ( _options.traceSymbolLayout() ) | |
598 | printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/_const_weak\n", atom.name()); | |
599 | } | |
600 | else if ( _options.useDataConstSegment() && (sectType == ld::Section::typeNonLazyPointer) && hasReferenceToWeakExternal(atom) ) { | |
601 | // if __DATA,__nl_symbol_ptr atom has pointer to weak external symbol, don't move to __DATA_CONST | |
602 | fs = this->getFinalSection("__DATA", "__got_weak", sectType); | |
603 | if ( _options.traceSymbolLayout() ) | |
604 | printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/__got_weak\n", atom.name()); | |
605 | } | |
606 | else { | |
607 | fs = this->getFinalSection(it->toSegment, it->toSection, sectType); | |
608 | if ( _options.traceSymbolLayout() ) | |
609 | printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName()); | |
610 | } | |
611 | } | |
612 | } | |
613 | if ( fs == NULL ) { | |
614 | for ( std::vector<Options::SegmentRename>::const_iterator it=segRenames.begin(); it != segRenames.end(); ++it) { | |
615 | if ( strcmp(atom.section().segmentName(), it->fromSegment) == 0 ) { | |
616 | if ( _options.traceSymbolLayout() ) | |
617 | printf("symbol '%s', -rename_segment mapped it to %s/%s\n", atom.name(), it->toSegment, sectName); | |
618 | fs = this->getFinalSection(it->toSegment, sectName, sectType); | |
619 | } | |
620 | } | |
621 | } | |
622 | } | |
623 | ||
624 | // if no override, use default location | |
625 | if ( fs == NULL ) { | |
626 | fs = this->getFinalSection(atom.section()); | |
627 | if ( _options.traceSymbolLayout() && (atom.symbolTableInclusion() == ld::Atom::symbolTableIn) ) | |
628 | printf("symbol '%s', use default mapping to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName()); | |
629 | } | |
630 | ||
631 | //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs); | |
632 | #ifndef NDEBUG | |
633 | validateFixups(atom); | |
634 | #endif | |
635 | if ( _atomsOrderedInSections ) { | |
636 | // make sure this atom is placed before any trailing section$end$ atom | |
637 | if ( (fs->atoms.size() > 1) && (fs->atoms.back()->contentType() == ld::Atom::typeSectionEnd) ) { | |
638 | // last atom in section$end$ atom, insert before it | |
639 | const ld::Atom* endAtom = fs->atoms.back(); | |
640 | fs->atoms.pop_back(); | |
641 | fs->atoms.push_back(&atom); | |
642 | fs->atoms.push_back(endAtom); | |
643 | } | |
644 | else { | |
645 | // not end atom, just append new atom | |
646 | fs->atoms.push_back(&atom); | |
647 | } | |
648 | } | |
649 | else { | |
650 | // normal case | |
651 | fs->atoms.push_back(&atom); | |
652 | } | |
653 | this->atomToSection[&atom] = fs; | |
654 | return fs; | |
655 | } | |
656 | ||
657 | ||
658 | ||
659 | ld::Internal::FinalSection* InternalState::getFinalSection(const char* seg, const char* sect, ld::Section::Type type) | |
660 | { | |
661 | for (std::vector<ld::Internal::FinalSection*>::iterator it=sections.begin(); it != sections.end(); ++it) { | |
662 | if ( (strcmp((*it)->segmentName(),seg) == 0) && (strcmp((*it)->sectionName(),sect) == 0) ) | |
663 | return *it; | |
664 | } | |
665 | return this->getFinalSection(*new ld::Section(seg, sect, type, false)); | |
666 | } | |
667 | ||
668 | ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection) | |
669 | { | |
670 | const ld::Section* baseForFinalSection = &inputSection; | |
671 | ||
672 | // see if input section already has a FinalSection | |
673 | SectionInToOut::iterator pos = _sectionInToFinalMap.find(&inputSection); | |
674 | if ( pos != _sectionInToFinalMap.end() ) { | |
675 | return pos->second; | |
676 | } | |
677 | ||
678 | // otherwise, create a new final section | |
679 | switch ( _options.outputKind() ) { | |
680 | case Options::kStaticExecutable: | |
681 | case Options::kDynamicExecutable: | |
682 | case Options::kDynamicLibrary: | |
683 | case Options::kDynamicBundle: | |
684 | case Options::kDyld: | |
685 | case Options::kKextBundle: | |
686 | case Options::kPreload: | |
687 | { | |
688 | // coalesce some sections | |
689 | const ld::Section& outSect = FinalSection::outputSection(inputSection, _options.mergeZeroFill()); | |
690 | pos = _sectionInToFinalMap.find(&outSect); | |
691 | if ( pos != _sectionInToFinalMap.end() ) { | |
692 | _sectionInToFinalMap[&inputSection] = pos->second; | |
693 | //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second); | |
694 | return pos->second; | |
695 | } | |
696 | else if ( outSect != inputSection ) { | |
697 | // new output section created, but not in map | |
698 | baseForFinalSection = &outSect; | |
699 | } | |
700 | } | |
701 | break; | |
702 | case Options::kObjectFile: | |
703 | baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options); | |
704 | pos = _sectionInToFinalMap.find(baseForFinalSection); | |
705 | if ( pos != _sectionInToFinalMap.end() ) { | |
706 | _sectionInToFinalMap[&inputSection] = pos->second; | |
707 | //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second); | |
708 | return pos->second; | |
709 | } | |
710 | break; | |
711 | } | |
712 | ||
713 | InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection, | |
714 | _sectionInToFinalMap.size(), _options); | |
715 | _sectionInToFinalMap[baseForFinalSection] = result; | |
716 | //fprintf(stderr, "_sectionInToFinalMap[%p(%s)] = %p\n", baseForFinalSection, baseForFinalSection->sectionName(), result); | |
717 | sections.push_back(result); | |
718 | return result; | |
719 | } | |
720 | ||
721 | ||
722 | int InternalState::FinalSection::sectionComparer(const void* l, const void* r) | |
723 | { | |
724 | const FinalSection* left = *(FinalSection**)l; | |
725 | const FinalSection* right = *(FinalSection**)r; | |
726 | if ( left->_segmentOrder != right->_segmentOrder ) | |
727 | return (left->_segmentOrder - right->_segmentOrder); | |
728 | return (left->_sectionOrder - right->_sectionOrder); | |
729 | } | |
730 | ||
731 | void InternalState::sortSections() | |
732 | { | |
733 | //fprintf(stderr, "UNSORTED final sections:\n"); | |
734 | //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
735 | // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName()); | |
736 | //} | |
737 | qsort(§ions[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer); | |
738 | //fprintf(stderr, "SORTED final sections:\n"); | |
739 | //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
740 | // fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName()); | |
741 | //} | |
742 | assert((sections[0]->type() == ld::Section::typeMachHeader) | |
743 | || ((sections[0]->type() == ld::Section::typeFirstSection) && (sections[1]->type() == ld::Section::typeMachHeader)) | |
744 | || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeMachHeader)) | |
745 | || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeFirstSection) && (sections[2]->type() == ld::Section::typeMachHeader)) ); | |
746 | ||
747 | } | |
748 | ||
749 | ||
750 | bool InternalState::hasZeroForFileOffset(const ld::Section* sect) | |
751 | { | |
752 | switch ( sect->type() ) { | |
753 | case ld::Section::typeZeroFill: | |
754 | case ld::Section::typeTLVZeroFill: | |
755 | return _options.optimizeZeroFill(); | |
756 | case ld::Section::typePageZero: | |
757 | case ld::Section::typeStack: | |
758 | case ld::Section::typeTentativeDefs: | |
759 | return true; | |
760 | default: | |
761 | break; | |
762 | } | |
763 | return false; | |
764 | } | |
765 | ||
766 | uint64_t InternalState::pageAlign(uint64_t addr) | |
767 | { | |
768 | const uint64_t alignment = _options.segmentAlignment(); | |
769 | return ((addr+alignment-1) & (-alignment)); | |
770 | } | |
771 | ||
772 | uint64_t InternalState::pageAlign(uint64_t addr, uint64_t pageSize) | |
773 | { | |
774 | return ((addr+pageSize-1) & (-pageSize)); | |
775 | } | |
776 | ||
777 | void InternalState::setSectionSizesAndAlignments() | |
778 | { | |
779 | for (std::vector<ld::Internal::FinalSection*>::iterator sit = sections.begin(); sit != sections.end(); ++sit) { | |
780 | ld::Internal::FinalSection* sect = *sit; | |
781 | if ( sect->type() == ld::Section::typeAbsoluteSymbols ) { | |
782 | // absolute symbols need their finalAddress() to their value | |
783 | for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { | |
784 | const ld::Atom* atom = *ait; | |
785 | (const_cast<ld::Atom*>(atom))->setSectionOffset(atom->objectAddress()); | |
786 | } | |
787 | } | |
788 | else { | |
789 | uint16_t maxAlignment = 0; | |
790 | uint64_t offset = 0; | |
791 | for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { | |
792 | const ld::Atom* atom = *ait; | |
793 | bool pagePerAtom = false; | |
794 | uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2; | |
795 | uint32_t atomModulus = atom->alignment().modulus; | |
796 | if ( _options.pageAlignDataAtoms() && ( strncmp(atom->section().segmentName(), "__DATA", 6) == 0) ) { | |
797 | // most objc sections cannot be padded | |
798 | bool contiguousObjCSection = ( strncmp(atom->section().sectionName(), "__objc_", 7) == 0 ); | |
799 | if ( strcmp(atom->section().sectionName(), "__objc_const") == 0 ) | |
800 | contiguousObjCSection = false; | |
801 | if ( strcmp(atom->section().sectionName(), "__objc_data") == 0 ) | |
802 | contiguousObjCSection = false; | |
803 | switch ( atom->section().type() ) { | |
804 | case ld::Section::typeUnclassified: | |
805 | case ld::Section::typeTentativeDefs: | |
806 | case ld::Section::typeZeroFill: | |
807 | if ( contiguousObjCSection ) | |
808 | break; | |
809 | pagePerAtom = true; | |
810 | if ( atomAlignmentPowerOf2 < 12 ) { | |
811 | atomAlignmentPowerOf2 = 12; | |
812 | atomModulus = 0; | |
813 | } | |
814 | break; | |
815 | default: | |
816 | break; | |
817 | } | |
818 | } | |
819 | if ( atomAlignmentPowerOf2 > maxAlignment ) | |
820 | maxAlignment = atomAlignmentPowerOf2; | |
821 | // calculate section offset for this atom | |
822 | uint64_t alignment = 1 << atomAlignmentPowerOf2; | |
823 | uint64_t currentModulus = (offset % alignment); | |
824 | uint64_t requiredModulus = atomModulus; | |
825 | if ( currentModulus != requiredModulus ) { | |
826 | if ( requiredModulus > currentModulus ) | |
827 | offset += requiredModulus-currentModulus; | |
828 | else | |
829 | offset += requiredModulus+alignment-currentModulus; | |
830 | } | |
831 | // LINKEDIT atoms are laid out later | |
832 | if ( sect->type() != ld::Section::typeLinkEdit ) { | |
833 | (const_cast<ld::Atom*>(atom))->setSectionOffset(offset); | |
834 | offset += atom->size(); | |
835 | if ( pagePerAtom ) { | |
836 | offset = (offset + 4095) & (-4096); // round up to end of page | |
837 | } | |
838 | } | |
839 | if ( (atom->scope() == ld::Atom::scopeGlobal) | |
840 | && (atom->definition() == ld::Atom::definitionRegular) | |
841 | && (atom->combine() == ld::Atom::combineByName) | |
842 | && ((atom->symbolTableInclusion() == ld::Atom::symbolTableIn) | |
843 | || (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) ) { | |
844 | this->hasWeakExternalSymbols = true; | |
845 | if ( _options.warnWeakExports() ) | |
846 | warning("weak external symbol: %s", atom->name()); | |
847 | } | |
848 | } | |
849 | sect->size = offset; | |
850 | // section alignment is that of a contained atom with the greatest alignment | |
851 | sect->alignment = maxAlignment; | |
852 | // unless -sectalign command line option overrides | |
853 | if ( _options.hasCustomSectionAlignment(sect->segmentName(), sect->sectionName()) ) | |
854 | sect->alignment = _options.customSectionAlignment(sect->segmentName(), sect->sectionName()); | |
855 | // each atom in __eh_frame has zero alignment to assure they pack together, | |
856 | // but compilers usually make the CFIs pointer sized, so we want whole section | |
857 | // to start on pointer sized boundary. | |
858 | if ( sect->type() == ld::Section::typeCFI ) | |
859 | sect->alignment = 3; | |
860 | if ( sect->type() == ld::Section::typeTLVDefs ) | |
861 | this->hasThreadLocalVariableDefinitions = true; | |
862 | } | |
863 | } | |
864 | } | |
865 | ||
866 | uint64_t InternalState::assignFileOffsets() | |
867 | { | |
868 | const bool log = false; | |
869 | const bool hiddenSectionsOccupyAddressSpace = ((_options.outputKind() != Options::kObjectFile) | |
870 | && (_options.outputKind() != Options::kPreload)); | |
871 | const bool segmentsArePageAligned = (_options.outputKind() != Options::kObjectFile); | |
872 | ||
873 | uint64_t address = 0; | |
874 | const char* lastSegName = ""; | |
875 | uint64_t floatingAddressStart = _options.baseAddress(); | |
876 | bool haveFixedSegments = false; | |
877 | ||
878 | // mark all sections as not having an address yet | |
879 | for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
880 | ld::Internal::FinalSection* sect = *it; | |
881 | sect->alignmentPaddingBytes = 0; | |
882 | sect->address = ULLONG_MAX; | |
883 | } | |
884 | ||
885 | // first pass, assign addresses to sections in segments with fixed start addresses | |
886 | if ( log ) fprintf(stderr, "Fixed address segments:\n"); | |
887 | for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
888 | ld::Internal::FinalSection* sect = *it; | |
889 | if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) | |
890 | continue; | |
891 | haveFixedSegments = true; | |
892 | if ( segmentsArePageAligned ) { | |
893 | if ( strcmp(lastSegName, sect->segmentName()) != 0 ) { | |
894 | address = _options.customSegmentAddress(sect->segmentName()); | |
895 | lastSegName = sect->segmentName(); | |
896 | } | |
897 | } | |
898 | // adjust section address based on alignment | |
899 | uint64_t unalignedAddress = address; | |
900 | uint64_t alignment = (1 << sect->alignment); | |
901 | address = ( (unalignedAddress+alignment-1) & (-alignment) ); | |
902 | ||
903 | // update section info | |
904 | sect->address = address; | |
905 | sect->alignmentPaddingBytes = (address - unalignedAddress); | |
906 | ||
907 | // sanity check size | |
908 | if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) | |
909 | && (_options.outputKind() != Options::kStaticExecutable) ) | |
910 | throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", | |
911 | sect->sectionName(), address, sect->size); | |
912 | ||
913 | if ( log ) fprintf(stderr, " address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n", | |
914 | sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName()); | |
915 | // update running totals | |
916 | if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace ) | |
917 | address += sect->size; | |
918 | ||
919 | // if TEXT segment address is fixed, then flow other segments after it | |
920 | if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) { | |
921 | floatingAddressStart = address; | |
922 | } | |
923 | } | |
924 | ||
925 | // second pass, assign section addresses to sections in segments that are ordered after a segment with a fixed address | |
926 | if ( haveFixedSegments && !_options.segmentOrder().empty() ) { | |
927 | if ( log ) fprintf(stderr, "After Fixed address segments:\n"); | |
928 | lastSegName = ""; | |
929 | ld::Internal::FinalSection* lastSect = NULL; | |
930 | for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
931 | ld::Internal::FinalSection* sect = *it; | |
932 | if ( (sect->address == ULLONG_MAX) && _options.segmentOrderAfterFixedAddressSegment(sect->segmentName()) ) { | |
933 | address = lastSect->address + lastSect->size; | |
934 | if ( (strcmp(lastSegName, sect->segmentName()) != 0) && segmentsArePageAligned ) { | |
935 | // round up size of last segment | |
936 | address = pageAlign(address, _options.segPageSize(lastSegName)); | |
937 | } | |
938 | // adjust section address based on alignment | |
939 | uint64_t unalignedAddress = address; | |
940 | uint64_t alignment = (1 << sect->alignment); | |
941 | address = ( (unalignedAddress+alignment-1) & (-alignment) ); | |
942 | sect->alignmentPaddingBytes = (address - unalignedAddress); | |
943 | sect->address = address; | |
944 | if ( log ) fprintf(stderr, " address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n", | |
945 | sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName()); | |
946 | // update running totals | |
947 | if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace ) | |
948 | address += sect->size; | |
949 | } | |
950 | lastSegName = sect->segmentName(); | |
951 | lastSect = sect; | |
952 | } | |
953 | } | |
954 | ||
955 | // last pass, assign addresses to remaining sections | |
956 | address = floatingAddressStart; | |
957 | lastSegName = ""; | |
958 | ld::Internal::FinalSection* overlappingFixedSection = NULL; | |
959 | ld::Internal::FinalSection* overlappingFlowSection = NULL; | |
960 | ld::Internal::FinalSection* prevSect = NULL; | |
961 | if ( log ) fprintf(stderr, "Regular layout segments:\n"); | |
962 | for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
963 | ld::Internal::FinalSection* sect = *it; | |
964 | if ( sect->address != ULLONG_MAX ) | |
965 | continue; | |
966 | if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) { | |
967 | sect->alignmentPaddingBytes = 0; | |
968 | continue; | |
969 | } | |
970 | if ( segmentsArePageAligned ) { | |
971 | if ( strcmp(lastSegName, sect->segmentName()) != 0 ) { | |
972 | // round up size of last segment if needed | |
973 | if ( *lastSegName != '\0' ) { | |
974 | address = pageAlign(address, _options.segPageSize(lastSegName)); | |
975 | } | |
976 | // set segment address based on end of last segment | |
977 | address = pageAlign(address); | |
978 | lastSegName = sect->segmentName(); | |
979 | } | |
980 | } | |
981 | ||
982 | // adjust section address based on alignment | |
983 | uint64_t unalignedAddress = address; | |
984 | uint64_t alignment = (1 << sect->alignment); | |
985 | address = ( (unalignedAddress+alignment-1) & (-alignment) ); | |
986 | ||
987 | // update section info | |
988 | sect->address = address; | |
989 | sect->alignmentPaddingBytes = (address - unalignedAddress); | |
990 | ||
991 | // <rdar://problem/21994854> if first section is more aligned than segment, move segment start up to match | |
992 | if ( (prevSect != NULL) && (prevSect->type() == ld::Section::typeFirstSection) && (strcmp(prevSect->segmentName(), sect->segmentName()) == 0) ) { | |
993 | assert(prevSect->size == 0); | |
994 | if ( prevSect->address != sect->address ) { | |
995 | prevSect->alignmentPaddingBytes += (sect->address - prevSect->address); | |
996 | prevSect->address = sect->address; | |
997 | } | |
998 | } | |
999 | ||
1000 | // sanity check size | |
1001 | if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) | |
1002 | && (_options.outputKind() != Options::kStaticExecutable) ) | |
1003 | throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", | |
1004 | sect->sectionName(), address, sect->size); | |
1005 | ||
1006 | // sanity check it does not overlap a fixed address segment | |
1007 | for (std::vector<ld::Internal::FinalSection*>::iterator sit = sections.begin(); sit != sections.end(); ++sit) { | |
1008 | ld::Internal::FinalSection* otherSect = *sit; | |
1009 | if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) ) | |
1010 | continue; | |
1011 | if ( otherSect->size == 0 ) | |
1012 | continue; | |
1013 | if ( sect->size == 0 ) | |
1014 | continue; | |
1015 | if ( sect->address > otherSect->address ) { | |
1016 | if ( (otherSect->address+otherSect->size) > sect->address ) { | |
1017 | overlappingFixedSection = otherSect; | |
1018 | overlappingFlowSection = sect; | |
1019 | } | |
1020 | } | |
1021 | else { | |
1022 | if ( (sect->address+sect->size) > otherSect->address ) { | |
1023 | overlappingFixedSection = otherSect; | |
1024 | overlappingFlowSection = sect; | |
1025 | } | |
1026 | } | |
1027 | } | |
1028 | ||
1029 | if ( log ) fprintf(stderr, " address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n", | |
1030 | sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, | |
1031 | sect->segmentName(), sect->sectionName()); | |
1032 | // update running totals | |
1033 | if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace ) | |
1034 | address += sect->size; | |
1035 | prevSect = sect; | |
1036 | } | |
1037 | if ( overlappingFixedSection != NULL ) { | |
1038 | fprintf(stderr, "Section layout:\n"); | |
1039 | for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
1040 | ld::Internal::FinalSection* sect = *it; | |
1041 | //if ( sect->isSectionHidden() ) | |
1042 | // continue; | |
1043 | fprintf(stderr, " address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n", | |
1044 | sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes, | |
1045 | sect->segmentName(), sect->sectionName()); | |
1046 | ||
1047 | } | |
1048 | throwf("Section (%s/%s) overlaps fixed address section (%s/%s)", | |
1049 | overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(), | |
1050 | overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName()); | |
1051 | } | |
1052 | ||
1053 | ||
1054 | // third pass, assign section file offsets | |
1055 | uint64_t fileOffset = 0; | |
1056 | lastSegName = ""; | |
1057 | if ( log ) fprintf(stderr, "All segments with file offsets:\n"); | |
1058 | for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) { | |
1059 | ld::Internal::FinalSection* sect = *it; | |
1060 | if ( hasZeroForFileOffset(sect) ) { | |
1061 | // fileoff of zerofill sections is moot, but historically it is set to zero | |
1062 | sect->fileOffset = 0; | |
1063 | ||
1064 | // <rdar://problem/10445047> align file offset with address layout | |
1065 | fileOffset += sect->alignmentPaddingBytes; | |
1066 | } | |
1067 | else { | |
1068 | // page align file offset at start of each segment | |
1069 | if ( segmentsArePageAligned && (*lastSegName != '\0') && (strcmp(lastSegName, sect->segmentName()) != 0) ) { | |
1070 | fileOffset = pageAlign(fileOffset, _options.segPageSize(lastSegName)); | |
1071 | } | |
1072 | lastSegName = sect->segmentName(); | |
1073 | ||
1074 | // align file offset with address layout | |
1075 | fileOffset += sect->alignmentPaddingBytes; | |
1076 | ||
1077 | // update section info | |
1078 | sect->fileOffset = fileOffset; | |
1079 | ||
1080 | // update running total | |
1081 | fileOffset += sect->size; | |
1082 | } | |
1083 | ||
1084 | if ( log ) fprintf(stderr, " fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n", | |
1085 | sect->fileOffset, sect->address, sect->isSectionHidden(), sect->size, sect->alignment, | |
1086 | sect->segmentName(), sect->sectionName()); | |
1087 | } | |
1088 | ||
1089 | #if 0 | |
1090 | // for encrypted iPhoneOS apps | |
1091 | if ( _options.makeEncryptable() ) { | |
1092 | // remember end of __TEXT for later use by load command | |
1093 | for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) { | |
1094 | ld::Internal::FinalSection* sect = *it; | |
1095 | if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) { | |
1096 | _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size); | |
1097 | } | |
1098 | } | |
1099 | } | |
1100 | #endif | |
1101 | ||
1102 | // return total file size | |
1103 | return fileOffset; | |
1104 | } | |
1105 | ||
1106 | static char* commatize(uint64_t in, char* out) | |
1107 | { | |
1108 | char* result = out; | |
1109 | char rawNum[30]; | |
1110 | sprintf(rawNum, "%llu", in); | |
1111 | const int rawNumLen = strlen(rawNum); | |
1112 | for(int i=0; i < rawNumLen-1; ++i) { | |
1113 | *out++ = rawNum[i]; | |
1114 | if ( ((rawNumLen-i) % 3) == 1 ) | |
1115 | *out++ = ','; | |
1116 | } | |
1117 | *out++ = rawNum[rawNumLen-1]; | |
1118 | *out = '\0'; | |
1119 | return result; | |
1120 | } | |
1121 | ||
1122 | static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime) | |
1123 | { | |
1124 | static uint64_t sUnitsPerSecond = 0; | |
1125 | if ( sUnitsPerSecond == 0 ) { | |
1126 | struct mach_timebase_info timeBaseInfo; | |
1127 | if ( mach_timebase_info(&timeBaseInfo) != KERN_SUCCESS ) | |
1128 | return; | |
1129 | sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer; | |
1130 | } | |
1131 | if ( partTime < sUnitsPerSecond ) { | |
1132 | uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond; | |
1133 | uint32_t milliSeconds = milliSecondsTimeTen/10; | |
1134 | uint32_t percentTimesTen = (partTime*1000)/totalTime; | |
1135 | uint32_t percent = percentTimesTen/10; | |
1136 | fprintf(stderr, "%24s: % 4d.%d milliseconds (% 4d.%d%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10); | |
1137 | } | |
1138 | else { | |
1139 | uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond; | |
1140 | uint32_t seconds = secondsTimeTen/10; | |
1141 | uint32_t percentTimesTen = (partTime*1000)/totalTime; | |
1142 | uint32_t percent = percentTimesTen/10; | |
1143 | fprintf(stderr, "%24s: % 4d.%d seconds (% 4d.%d%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10); | |
1144 | } | |
1145 | } | |
1146 | ||
1147 | ||
1148 | static void getVMInfo(vm_statistics_data_t& info) | |
1149 | { | |
1150 | mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t); | |
1151 | kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO, | |
1152 | (host_info_t)&info, &count); | |
1153 | if (error != KERN_SUCCESS) { | |
1154 | bzero(&info, sizeof(vm_statistics_data_t)); | |
1155 | } | |
1156 | } | |
1157 | ||
1158 | ||
1159 | ||
1160 | static const char* sOverridePathlibLTO = NULL; | |
1161 | ||
1162 | // | |
1163 | // This is magic glue that overrides the default behaviour | |
1164 | // of lazydylib1.o which is used to lazily load libLTO.dylib. | |
1165 | // | |
1166 | extern "C" const char* dyld_lazy_dylib_path_fix(const char* path); | |
1167 | const char* dyld_lazy_dylib_path_fix(const char* path) | |
1168 | { | |
1169 | if ( sOverridePathlibLTO != NULL ) | |
1170 | return sOverridePathlibLTO; | |
1171 | else | |
1172 | return path; | |
1173 | } | |
1174 | ||
1175 | ||
1176 | ||
1177 | int main(int argc, const char* argv[]) | |
1178 | { | |
1179 | const char* archName = NULL; | |
1180 | bool showArch = false; | |
1181 | bool archInferred = false; | |
1182 | try { | |
1183 | PerformanceStatistics statistics; | |
1184 | statistics.startTool = mach_absolute_time(); | |
1185 | ||
1186 | // create object to track command line arguments | |
1187 | Options options(argc, argv); | |
1188 | InternalState state(options); | |
1189 | ||
1190 | // allow libLTO to be overridden by command line -lto_library | |
1191 | sOverridePathlibLTO = options.overridePathlibLTO(); | |
1192 | ||
1193 | // gather vm stats | |
1194 | if ( options.printStatistics() ) | |
1195 | getVMInfo(statistics.vmStart); | |
1196 | ||
1197 | // update strings for error messages | |
1198 | showArch = options.printArchPrefix(); | |
1199 | archName = options.architectureName(); | |
1200 | archInferred = (options.architecture() == 0); | |
1201 | ||
1202 | // open and parse input files | |
1203 | statistics.startInputFileProcessing = mach_absolute_time(); | |
1204 | ld::tool::InputFiles inputFiles(options, &archName); | |
1205 | ||
1206 | // load and resolve all references | |
1207 | statistics.startResolver = mach_absolute_time(); | |
1208 | ld::tool::Resolver resolver(options, inputFiles, state); | |
1209 | resolver.resolve(); | |
1210 | ||
1211 | // add dylibs used | |
1212 | statistics.startDylibs = mach_absolute_time(); | |
1213 | inputFiles.dylibs(state); | |
1214 | ||
1215 | // do initial section sorting so passes have rough idea of the layout | |
1216 | state.sortSections(); | |
1217 | ||
1218 | // run passes | |
1219 | statistics.startPasses = mach_absolute_time(); | |
1220 | ld::passes::objc::doPass(options, state); | |
1221 | ld::passes::stubs::doPass(options, state); | |
1222 | ld::passes::huge::doPass(options, state); | |
1223 | ld::passes::got::doPass(options, state); | |
1224 | ld::passes::tlvp::doPass(options, state); | |
1225 | ld::passes::dylibs::doPass(options, state); // must be after stubs and GOT passes | |
1226 | ld::passes::order::doPass(options, state); | |
1227 | state.markAtomsOrdered(); | |
1228 | ld::passes::dedup::doPass(options, state); | |
1229 | ld::passes::branch_shim::doPass(options, state); // must be after stubs | |
1230 | ld::passes::branch_island::doPass(options, state); // must be after stubs and order pass | |
1231 | ld::passes::dtrace::doPass(options, state); | |
1232 | ld::passes::compact_unwind::doPass(options, state); // must be after order pass | |
1233 | ld::passes::bitcode_bundle::doPass(options, state); // must be after dylib | |
1234 | ||
1235 | // sort final sections | |
1236 | state.sortSections(); | |
1237 | ||
1238 | // write output file | |
1239 | statistics.startOutput = mach_absolute_time(); | |
1240 | ld::tool::OutputFile out(options); | |
1241 | out.write(state); | |
1242 | statistics.startDone = mach_absolute_time(); | |
1243 | ||
1244 | // print statistics | |
1245 | //mach_o::relocatable::printCounts(); | |
1246 | if ( options.printStatistics() ) { | |
1247 | getVMInfo(statistics.vmEnd); | |
1248 | uint64_t totalTime = statistics.startDone - statistics.startTool; | |
1249 | printTime("ld total time", totalTime, totalTime); | |
1250 | printTime(" option parsing time", statistics.startInputFileProcessing - statistics.startTool, totalTime); | |
1251 | printTime(" object file processing", statistics.startResolver - statistics.startInputFileProcessing,totalTime); | |
1252 | printTime(" resolve symbols", statistics.startDylibs - statistics.startResolver, totalTime); | |
1253 | printTime(" build atom list", statistics.startPasses - statistics.startDylibs, totalTime); | |
1254 | printTime(" passess", statistics.startOutput - statistics.startPasses, totalTime); | |
1255 | printTime(" write output", statistics.startDone - statistics.startOutput, totalTime); | |
1256 | fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", | |
1257 | statistics.vmEnd.pageins-statistics.vmStart.pageins, | |
1258 | statistics.vmEnd.pageouts-statistics.vmStart.pageouts, | |
1259 | statistics.vmEnd.faults-statistics.vmStart.faults); | |
1260 | char temp[40]; | |
1261 | fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", inputFiles._totalObjectLoaded, commatize(inputFiles._totalObjectSize, temp)); | |
1262 | fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded, commatize(inputFiles._totalArchiveSize, temp)); | |
1263 | fprintf(stderr, "processed %3u dylib files\n", inputFiles._totalDylibsLoaded); | |
1264 | fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(out.fileSize(), temp)); | |
1265 | } | |
1266 | // <rdar://problem/6780050> Would like linker warning to be build error. | |
1267 | if ( options.errorBecauseOfWarnings() ) { | |
1268 | fprintf(stderr, "ld: fatal warning(s) induced error (-fatal_warnings)\n"); | |
1269 | return 1; | |
1270 | } | |
1271 | } | |
1272 | catch (const char* msg) { | |
1273 | if ( archInferred ) | |
1274 | fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName); | |
1275 | else if ( showArch ) | |
1276 | fprintf(stderr, "ld: %s for architecture %s\n", msg, archName); | |
1277 | else | |
1278 | fprintf(stderr, "ld: %s\n", msg); | |
1279 | return 1; | |
1280 | } | |
1281 | ||
1282 | return 0; | |
1283 | } | |
1284 | ||
1285 | ||
1286 | #ifndef NDEBUG | |
1287 | // implement assert() function to print out a backtrace before aborting | |
1288 | void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr) | |
1289 | { | |
1290 | Snapshot *snapshot = Snapshot::globalSnapshot; | |
1291 | ||
1292 | snapshot->setSnapshotMode(Snapshot::SNAPSHOT_DEBUG); | |
1293 | snapshot->createSnapshot(); | |
1294 | snapshot->recordAssertionMessage("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line); | |
1295 | ||
1296 | void* callStack[128]; | |
1297 | int depth = ::backtrace(callStack, 128); | |
1298 | char* buffer = (char*)malloc(1024); | |
1299 | for(int i=0; i < depth-1; ++i) { | |
1300 | Dl_info info; | |
1301 | dladdr(callStack[i], &info); | |
1302 | const char* symboName = info.dli_sname; | |
1303 | if ( (symboName != NULL) && (strncmp(symboName, "_Z", 2) == 0) ) { | |
1304 | size_t bufLen = 1024; | |
1305 | int result; | |
1306 | char* unmangled = abi::__cxa_demangle(symboName, buffer, &bufLen, &result); | |
1307 | if ( unmangled != NULL ) | |
1308 | symboName = unmangled; | |
1309 | } | |
1310 | long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr; | |
1311 | fprintf(stderr, "%d %p %s + %ld\n", i, callStack[i], symboName, offset); | |
1312 | snapshot->recordAssertionMessage("%d %p %s + %ld\n", i, callStack[i], symboName, offset); | |
1313 | } | |
1314 | fprintf(stderr, "A linker snapshot was created at:\n\t%s\n", snapshot->rootDir()); | |
1315 | fprintf(stderr, "ld: Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line); | |
1316 | exit(1); | |
1317 | } | |
1318 | #endif | |
1319 | ||
1320 |