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