]>
Commit | Line | Data |
---|---|---|
a645023d A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2005-2010 Apple Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * This file contains Original Code and/or Modifications of Original Code | |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | ||
26 | #ifndef __LD_HPP__ | |
27 | #define __LD_HPP__ | |
28 | ||
29 | #include <stdint.h> | |
30 | #include <math.h> | |
31 | #include <unistd.h> | |
32 | #include <assert.h> | |
33 | ||
34 | #include <vector> | |
35 | #include <set> | |
36 | ||
37 | ||
38 | namespace ld { | |
39 | ||
40 | // | |
41 | // ld::File | |
42 | // | |
43 | // Abstract base class for all object or library files the linker processes. | |
44 | // | |
45 | // forEachAtom() iterates over the Atoms in the order they occur in the file. | |
46 | // | |
47 | // justInTimeforEachAtom(name) iterates over lazily created Atoms. For instance if | |
48 | // File is a static library, justInTimeforEachAtom() will iterate over the base set | |
49 | // of Atoms from the archive member implementing 'name'. | |
50 | // | |
51 | class File | |
52 | { | |
53 | public: | |
54 | enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC }; | |
55 | ||
56 | class AtomHandler { | |
57 | public: | |
58 | virtual ~AtomHandler() {} | |
59 | virtual void doAtom(const class Atom&) = 0; | |
60 | virtual void doFile(const class File&) = 0; | |
61 | }; | |
62 | ||
ebf6f434 A |
63 | // |
64 | // ld::File::Ordinal | |
65 | // | |
66 | // Codifies the rules of ordering input files for symbol precedence. These are: | |
67 | // - Input files listed on the command line are ordered according to their index in the argument list. | |
68 | // - Input files listed in a file list are ordered first at the index of the file list argument, then | |
69 | // by index in the file list | |
70 | // - Input files extracted from archives are ordered using the ordinal of the archive itself plus the | |
71 | // index of the object file within the archive | |
72 | // - Indirect dylibs are ordered after all input files derived from the command line, in the order that | |
73 | // they are discovered. | |
74 | // - The LTO object file is last. | |
75 | // | |
76 | class Ordinal | |
77 | { | |
78 | private: | |
79 | // The actual numeric ordinal. Lower values have higher precedence and a zero value is invalid. | |
80 | // The 64 bit ordinal is broken into 4 16 bit chunks. The high 16 bits are a "partition" that | |
81 | // is used to distinguish major ordinal groups: command line, indirect dylib, LTO. | |
82 | // The remaining chunks are used according to the partition (see below). | |
83 | uint64_t _ordinal; | |
84 | ||
85 | Ordinal (uint64_t ordinal) : _ordinal(ordinal) {} | |
86 | ||
87 | enum { ArgListPartition=0, IndirectDylibPartition=1, LTOPartition = 2, InvalidParition=0xffff }; | |
88 | Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) { | |
89 | _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0); | |
90 | } | |
91 | ||
92 | const uint16_t partition() const { return (_ordinal>>48)&0xffff; } | |
93 | const uint16_t majorIndex() const { return (_ordinal>>32)&0xffff; } | |
94 | const uint16_t minorIndex() const { return (_ordinal>>16)&0xffff; } | |
95 | const uint16_t counter() const { return (_ordinal>>00)&0xffff; } | |
96 | ||
97 | const Ordinal nextMajorIndex() const { assert(majorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<32)); } | |
98 | const Ordinal nextMinorIndex() const { assert(minorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<16)); } | |
99 | const Ordinal nextCounter() const { assert(counter() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<0)); } | |
100 | ||
101 | public: | |
102 | Ordinal() : _ordinal(0) {}; | |
103 | ||
104 | static const Ordinal NullOrdinal() { return Ordinal((uint64_t)0); } | |
105 | ||
106 | const bool validOrdinal() const { return _ordinal != 0; } | |
107 | ||
108 | bool operator ==(const Ordinal& rhs) const { return _ordinal == rhs._ordinal; } | |
109 | bool operator !=(const Ordinal& rhs) const { return _ordinal != rhs._ordinal; } | |
110 | bool operator < (const Ordinal& rhs) const { return _ordinal < rhs._ordinal; } | |
111 | bool operator > (const Ordinal& rhs) const { return _ordinal > rhs._ordinal; } | |
112 | ||
113 | // For ordinals derived from the command line args the partition is ArgListPartition | |
114 | // The majorIndex is the arg index that pulls in the file, file list, or archive. | |
115 | // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list. | |
116 | // The counter is used for .a files and the value is the index of the object in the archive. | |
117 | // Thus, an object pulled in from a .a that was listed in a file list could use all three fields. | |
118 | static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(ArgListPartition, argIndex, 0, 0); }; | |
119 | const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); } | |
120 | const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(ArgListPartition, majorIndex(), minorIndex(), index); } | |
121 | ||
122 | // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries. | |
123 | static const ld::File::Ordinal indirectDylibBase() { return Ordinal(IndirectDylibPartition, 0, 0, 0); } | |
124 | const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); } | |
125 | ||
126 | // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed. | |
127 | static const ld::File::Ordinal LTOOrdinal() { return Ordinal(LTOPartition, 0, 0, 0); } | |
128 | }; | |
129 | ||
130 | typedef enum { Reloc, Dylib, Archive, Other } Type; | |
131 | ||
132 | File(const char* pth, time_t modTime, Ordinal ord, Type type) | |
133 | : _path(pth), _modTime(modTime), _ordinal(ord), _type(type) { } | |
a645023d A |
134 | virtual ~File() {} |
135 | const char* path() const { return _path; } | |
136 | time_t modificationTime() const{ return _modTime; } | |
ebf6f434 | 137 | Ordinal ordinal() const { return _ordinal; } |
a645023d A |
138 | virtual bool forEachAtom(AtomHandler&) const = 0; |
139 | virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const = 0; | |
140 | virtual ObjcConstraint objCConstraint() const { return objcConstraintNone; } | |
141 | virtual uint32_t cpuSubType() const { return 0; } | |
142 | virtual uint32_t subFileCount() const { return 1; } | |
ebf6f434 A |
143 | bool fileExists() const { return _modTime != 0; } |
144 | Type type() const { return _type; } | |
a645023d A |
145 | private: |
146 | const char* _path; | |
147 | time_t _modTime; | |
ebf6f434 A |
148 | const Ordinal _ordinal; |
149 | const Type _type; | |
a645023d A |
150 | }; |
151 | ||
152 | ||
153 | // | |
154 | // minumum OS versions | |
155 | // | |
156 | enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, | |
ebf6f434 A |
157 | mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800, |
158 | mac10_Future=0x10000000 }; | |
afe874b1 | 159 | enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100, |
ebf6f434 | 160 | iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000, |
b1f7435d | 161 | iOS_6_0=0x00060000, iOS_Future=0x10000000}; |
a645023d A |
162 | |
163 | namespace relocatable { | |
164 | // | |
165 | // ld::relocatable::File | |
166 | // | |
167 | // Abstract base class for object files the linker processes. | |
168 | // | |
a645023d A |
169 | // debugInfo() returns if the object file contains debugger information (stabs or dwarf). |
170 | // | |
171 | // stabs() lazily creates a vector of Stab objects for each atom | |
172 | // | |
173 | // canScatterAtoms() true for all compiler generated code. Hand written assembly can opt-in | |
174 | // via .subsections_via_symbols directive. When true it means the linker can break up section | |
175 | // content at symbol boundaries and do optimizations like coalescing, dead code stripping, or | |
176 | // apply order files. | |
177 | // | |
178 | // optimize() used by libLTO to lazily generate code from llvm bit-code files | |
179 | // | |
180 | class File : public ld::File | |
181 | { | |
182 | public: | |
183 | enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 }; | |
184 | struct Stab { | |
185 | const class Atom* atom; | |
186 | uint8_t type; | |
187 | uint8_t other; | |
188 | uint16_t desc; | |
189 | uint32_t value; | |
190 | const char* string; | |
191 | }; | |
192 | ||
ebf6f434 A |
193 | File(const char* pth, time_t modTime, Ordinal ord) |
194 | : ld::File(pth, modTime, ord, Reloc) { } | |
a645023d | 195 | virtual ~File() {} |
a645023d A |
196 | virtual DebugInfoKind debugInfo() const = 0; |
197 | virtual const char* debugInfoPath() const { return path(); } | |
198 | virtual time_t debugInfoModificationTime() const { return modificationTime(); } | |
199 | virtual const std::vector<Stab>* stabs() const = 0; | |
200 | virtual bool canScatterAtoms() const = 0; | |
201 | virtual bool hasLongBranchStubs() { return false; } | |
202 | }; | |
203 | } // namespace relocatable | |
204 | ||
205 | ||
206 | namespace dylib { | |
207 | ||
208 | // | |
209 | // ld::dylib::File | |
210 | // | |
211 | // Abstract base class for dynamic shared libraries read by the linker processes. | |
212 | // | |
213 | class File : public ld::File | |
214 | { | |
215 | public: | |
216 | class DylibHandler | |
217 | { | |
218 | public: | |
219 | virtual ~DylibHandler() {} | |
220 | virtual File* findDylib(const char* installPath, const char* fromPath) = 0; | |
221 | }; | |
222 | ||
ebf6f434 A |
223 | File(const char* pth, time_t modTime, Ordinal ord) |
224 | : ld::File(pth, modTime, ord, Dylib), _dylibInstallPath(NULL), | |
a645023d A |
225 | _dylibTimeStamp(0), _dylibCurrentVersion(0), _dylibCompatibilityVersion(0), |
226 | _explicitlyLinked(false), _implicitlyLinked(false), | |
afe874b1 A |
227 | _lazyLoadedDylib(false), _forcedWeakLinked(false), _reExported(false), |
228 | _upward(false), _dead(false) { } | |
a645023d A |
229 | const char* installPath() const { return _dylibInstallPath; } |
230 | uint32_t timestamp() const { return _dylibTimeStamp; } | |
231 | uint32_t currentVersion() const { return _dylibCurrentVersion; } | |
232 | uint32_t compatibilityVersion() const{ return _dylibCompatibilityVersion; } | |
233 | void setExplicitlyLinked() { _explicitlyLinked = true; } | |
234 | bool explicitlyLinked() const { return _explicitlyLinked; } | |
235 | void setImplicitlyLinked() { _implicitlyLinked = true; } | |
236 | bool implicitlyLinked() const { return _implicitlyLinked; } | |
ebf6f434 | 237 | |
a645023d A |
238 | // attributes of how dylib will be used when linked |
239 | void setWillBeLazyLoadedDylb() { _lazyLoadedDylib = true; } | |
240 | bool willBeLazyLoadedDylib() const { return _lazyLoadedDylib; } | |
afe874b1 A |
241 | void setForcedWeakLinked() { _forcedWeakLinked = true; } |
242 | bool forcedWeakLinked() const { return _forcedWeakLinked; } | |
243 | ||
a645023d A |
244 | void setWillBeReExported() { _reExported = true; } |
245 | bool willBeReExported() const { return _reExported; } | |
246 | void setWillBeUpwardDylib() { _upward = true; } | |
247 | bool willBeUpwardDylib() const { return _upward; } | |
a645023d A |
248 | void setWillBeRemoved(bool value) { _dead = value; } |
249 | bool willRemoved() const { return _dead; } | |
250 | ||
251 | virtual void processIndirectLibraries(DylibHandler* handler, bool addImplicitDylibs) = 0; | |
252 | virtual bool providedExportAtom() const = 0; | |
253 | virtual const char* parentUmbrella() const = 0; | |
254 | virtual const std::vector<const char*>* allowableClients() const = 0; | |
255 | virtual bool hasWeakExternals() const = 0; | |
256 | virtual bool deadStrippable() const = 0; | |
257 | virtual bool hasWeakDefinition(const char* name) const = 0; | |
258 | virtual bool hasPublicInstallName() const = 0; | |
afe874b1 | 259 | virtual bool allSymbolsAreWeakImported() const = 0; |
ebf6f434 | 260 | virtual const void* codeSignatureDR() const = 0; |
a645023d A |
261 | protected: |
262 | const char* _dylibInstallPath; | |
263 | uint32_t _dylibTimeStamp; | |
264 | uint32_t _dylibCurrentVersion; | |
265 | uint32_t _dylibCompatibilityVersion; | |
266 | bool _explicitlyLinked; | |
267 | bool _implicitlyLinked; | |
268 | bool _lazyLoadedDylib; | |
afe874b1 | 269 | bool _forcedWeakLinked; |
a645023d A |
270 | bool _reExported; |
271 | bool _upward; | |
a645023d A |
272 | bool _dead; |
273 | }; | |
274 | } // namespace dylib | |
275 | ||
276 | ||
afe874b1 A |
277 | namespace archive { |
278 | // | |
279 | // ld::archive::File | |
280 | // | |
281 | // Abstract base class for static libraries read by the linker processes. | |
282 | // | |
283 | class File : public ld::File | |
284 | { | |
285 | public: | |
ebf6f434 A |
286 | File(const char* pth, time_t modTime, Ordinal ord) |
287 | : ld::File(pth, modTime, ord, Archive) { } | |
afe874b1 A |
288 | virtual ~File() {} |
289 | virtual bool justInTimeDataOnlyforEachAtom(const char* name, AtomHandler&) const = 0; | |
290 | }; | |
291 | } // namespace archive | |
292 | ||
a645023d A |
293 | |
294 | // | |
295 | // ld::Section | |
296 | // | |
297 | class Section | |
298 | { | |
299 | public: | |
300 | enum Type { typeUnclassified, typeCode, typePageZero, typeImportProxies, typeLinkEdit, typeMachHeader, typeStack, | |
301 | typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, | |
302 | typeCString, typeNonStdCString, typeCStringPointer, typeUTF16Strings, typeCFString, typeObjC1Classes, | |
303 | typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList, | |
304 | typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo, | |
305 | typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers, | |
306 | typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, | |
307 | typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers, | |
afe874b1 | 308 | typeFirstSection, typeLastSection, typeDebug }; |
a645023d A |
309 | |
310 | ||
311 | Section(const char* sgName, const char* sctName, | |
312 | Type t, bool hidden=false) | |
313 | : _segmentName(sgName), _sectionName(sctName), | |
314 | _type(t), _hidden(hidden) {} | |
315 | Section(const Section& sect) | |
316 | : _segmentName(sect.segmentName()), _sectionName(sect.sectionName()), | |
317 | _type(sect.type()), _hidden(sect.isSectionHidden()) {} | |
318 | ||
319 | bool operator==(const Section& rhs) const { return ( (_hidden==rhs._hidden) && | |
320 | (strcmp(_segmentName, rhs._segmentName)==0) && | |
321 | (strcmp(_sectionName, rhs._sectionName)==0) ); } | |
322 | bool operator!=(const Section& rhs) const { return ! (*this == rhs); } | |
323 | const char* segmentName() const { return _segmentName; } | |
324 | const char* sectionName() const { return _sectionName; } | |
325 | Type type() const { return _type; } | |
326 | bool isSectionHidden() const { return _hidden; } | |
327 | ||
328 | private: | |
329 | const char* _segmentName; | |
330 | const char* _sectionName; | |
331 | Type _type; | |
332 | bool _hidden; | |
333 | }; | |
334 | ||
335 | ||
336 | ||
337 | // | |
338 | // ld::Fixup | |
339 | // | |
340 | // A Fixup describes how part of an Atom's content must be fixed up. For instance, | |
341 | // an instruction may contain a displacement to another Atom that must be | |
342 | // fixed up by the linker. | |
343 | // | |
344 | // A Fixup my reference another Atom. There are two kinds of references: direct and by-name. | |
345 | // With a direct reference, the target is bound by the File that created it. | |
346 | // For instance a reference to a static would produce a direct reference. | |
347 | // A by-name reference requires the linker to find the target Atom with the | |
348 | // required name in order to be bound. | |
349 | // | |
350 | // For a link to succeed all Fixup must be bound. | |
351 | // | |
352 | // A Reference also has a fix-up-offset. This is the offset into the content of the | |
353 | // Atom holding the reference where the fix-up (relocation) will be applied. | |
354 | // | |
355 | // | |
356 | struct Fixup | |
357 | { | |
358 | enum TargetBinding { bindingNone, bindingByNameUnbound, bindingDirectlyBound, bindingByContentBound, bindingsIndirectlyBound }; | |
359 | enum Cluster { k1of1, k1of2, k2of2, k1of3, k2of3, k3of3, k1of4, k2of4, k3of4, k4of4, k1of5, k2of5, k3of5, k4of5, k5of5 }; | |
360 | enum Kind { kindNone, kindNoneFollowOn, | |
361 | // grouping | |
362 | kindNoneGroupSubordinate, | |
363 | kindNoneGroupSubordinateFDE, kindNoneGroupSubordinateLSDA, kindNoneGroupSubordinatePersonality, | |
364 | // value calculations | |
365 | kindSetTargetAddress, | |
366 | kindSubtractTargetAddress, | |
367 | kindAddAddend, | |
368 | kindSubtractAddend, | |
369 | kindSetTargetImageOffset, | |
370 | kindSetTargetSectionOffset, | |
371 | kindSetTargetTLVTemplateOffset, | |
372 | // pointer store kinds (of current calculated value) | |
373 | kindStore8, | |
374 | kindStoreLittleEndian16, | |
375 | kindStoreLittleEndianLow24of32, | |
376 | kindStoreLittleEndian32, | |
377 | kindStoreLittleEndian64, | |
378 | kindStoreBigEndian16, | |
379 | kindStoreBigEndianLow24of32, | |
380 | kindStoreBigEndian32, | |
381 | kindStoreBigEndian64, | |
382 | // Intel specific store kinds | |
383 | kindStoreX86BranchPCRel8, kindStoreX86BranchPCRel32, | |
384 | kindStoreX86PCRel8, kindStoreX86PCRel16, | |
385 | kindStoreX86PCRel32, kindStoreX86PCRel32_1, kindStoreX86PCRel32_2, kindStoreX86PCRel32_4, | |
386 | kindStoreX86PCRel32GOTLoad, kindStoreX86PCRel32GOTLoadNowLEA, kindStoreX86PCRel32GOT, | |
387 | kindStoreX86PCRel32TLVLoad, kindStoreX86PCRel32TLVLoadNowLEA, | |
388 | kindStoreX86Abs32TLVLoad, kindStoreX86Abs32TLVLoadNowLEA, | |
389 | // ARM specific store kinds | |
390 | kindStoreARMBranch24, kindStoreThumbBranch22, | |
391 | kindStoreARMLoad12, | |
392 | kindStoreARMLow16, kindStoreARMHigh16, | |
393 | kindStoreThumbLow16, kindStoreThumbHigh16, | |
a645023d A |
394 | // dtrace probes |
395 | kindDtraceExtra, | |
396 | kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear, | |
397 | kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear, | |
398 | kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear, | |
a645023d A |
399 | // lazy binding |
400 | kindLazyTarget, kindSetLazyOffset, | |
ebf6f434 A |
401 | // data-in-code markers |
402 | kindDataInCodeStartData, kindDataInCodeStartJT8, kindDataInCodeStartJT16, | |
403 | kindDataInCodeStartJT32, kindDataInCodeStartJTA32, kindDataInCodeEnd, | |
a645023d A |
404 | // pointer store combinations |
405 | kindStoreTargetAddressLittleEndian32, // kindSetTargetAddress + kindStoreLittleEndian32 | |
406 | kindStoreTargetAddressLittleEndian64, // kindSetTargetAddress + kindStoreLittleEndian64 | |
407 | kindStoreTargetAddressBigEndian32, // kindSetTargetAddress + kindStoreBigEndian32 | |
408 | kindStoreTargetAddressBigEndian64, // kindSetTargetAddress + kindStoreBigEndian364 | |
409 | kindSetTargetTLVTemplateOffsetLittleEndian32, // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian32 | |
410 | kindSetTargetTLVTemplateOffsetLittleEndian64, // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian64 | |
411 | // Intel value calculation and store combinations | |
412 | kindStoreTargetAddressX86PCRel32, // kindSetTargetAddress + kindStoreX86PCRel32 | |
413 | kindStoreTargetAddressX86BranchPCRel32, // kindSetTargetAddress + kindStoreX86BranchPCRel32 | |
414 | kindStoreTargetAddressX86PCRel32GOTLoad,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoad | |
415 | kindStoreTargetAddressX86PCRel32GOTLoadNowLEA,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoadNowLEA | |
416 | kindStoreTargetAddressX86PCRel32TLVLoad, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoad | |
417 | kindStoreTargetAddressX86PCRel32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoadNowLEA | |
418 | kindStoreTargetAddressX86Abs32TLVLoad, // kindSetTargetAddress + kindStoreX86Abs32TLVLoad | |
419 | kindStoreTargetAddressX86Abs32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86Abs32TLVLoadNowLEA | |
420 | // ARM value calculation and store combinations | |
421 | kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24 | |
422 | kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22 | |
423 | kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12 | |
a645023d A |
424 | }; |
425 | ||
426 | union { | |
427 | const Atom* target; | |
428 | const char* name; | |
429 | uint64_t addend; | |
430 | uint32_t bindingIndex; | |
431 | } u; | |
432 | uint32_t offsetInAtom; | |
433 | Kind kind : 8; | |
434 | Cluster clusterSize : 4; | |
435 | bool weakImport : 1; | |
436 | TargetBinding binding : 3; | |
437 | bool contentAddendOnly : 1; | |
438 | bool contentDetlaToAddendOnly : 1; | |
439 | ||
440 | typedef Fixup* iterator; | |
441 | ||
442 | Fixup() : | |
443 | offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false), | |
444 | binding(bindingNone), | |
445 | contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; } | |
446 | ||
447 | Fixup(Kind k, Atom* targetAtom) : | |
448 | offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false), | |
449 | binding(Fixup::bindingDirectlyBound), | |
450 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
451 | { assert(targetAtom != NULL); u.target = targetAtom; } | |
452 | ||
453 | Fixup(uint32_t off, Cluster c, Kind k) : | |
454 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), | |
455 | binding(Fixup::bindingNone), | |
456 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
457 | { u.addend = 0; } | |
458 | ||
459 | Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) : | |
460 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm), | |
461 | binding(Fixup::bindingByNameUnbound), | |
462 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
463 | { assert(name != NULL); u.name = name; } | |
464 | ||
465 | Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) : | |
466 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b), | |
467 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
468 | { assert(name != NULL); u.name = name; } | |
469 | ||
470 | Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) : | |
471 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), | |
472 | binding(Fixup::bindingDirectlyBound), | |
473 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
474 | { assert(targetAtom != NULL); u.target = targetAtom; } | |
475 | ||
476 | Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) : | |
477 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b), | |
478 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
479 | { assert(targetAtom != NULL); u.target = targetAtom; } | |
480 | ||
481 | Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) : | |
482 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), | |
483 | binding(Fixup::bindingNone), | |
484 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
485 | { u.addend = addend; } | |
486 | ||
487 | bool firstInCluster() const { | |
488 | switch (clusterSize) { | |
489 | case k1of1: | |
490 | case k1of2: | |
491 | case k1of3: | |
492 | case k1of4: | |
493 | case k1of5: | |
494 | return true; | |
495 | default: | |
496 | break; | |
497 | } | |
498 | return false; | |
499 | } | |
500 | ||
501 | bool lastInCluster() const { | |
502 | switch (clusterSize) { | |
503 | case k1of1: | |
504 | case k2of2: | |
505 | case k3of3: | |
506 | case k4of4: | |
507 | case k5of5: | |
508 | return true; | |
509 | default: | |
510 | break; | |
511 | } | |
512 | return false; | |
513 | } | |
514 | ||
515 | }; | |
516 | ||
517 | // | |
518 | // ld::Atom | |
519 | // | |
520 | // An atom is the fundamental unit of linking. A C function or global variable is an atom. | |
521 | // An atom has content and attributes. The content of a function atom is the instructions | |
522 | // that implement the function. The content of a global variable atom is its initial bits. | |
523 | // | |
524 | // Name: | |
525 | // The name of an atom is the label name generated by the compiler. A C compiler names foo() | |
526 | // as _foo. A C++ compiler names foo() as __Z3foov. | |
527 | // The name refers to the first byte of the content. An atom cannot have multiple entry points. | |
528 | // Such code is modeled as multiple atoms, each having a "follow on" reference to the next. | |
529 | // A "follow on" reference is a contraint to the linker to the atoms must be laid out contiguously. | |
530 | // | |
531 | // Scope: | |
532 | // An atom is in one of three scopes: translation-unit, linkage-unit, or global. These correspond | |
533 | // to the C visibility of static, hidden, default. | |
534 | // | |
535 | // DefinitionKind: | |
536 | // An atom is one of five defintion kinds: | |
537 | // regular Most atoms. | |
538 | // weak C++ compiler makes some functions weak if there might be multiple copies | |
539 | // that the linker needs to coalesce. | |
540 | // tentative A straggler from ancient C when the extern did not exist. "int foo;" is ambiguous. | |
541 | // It could be a prototype or it could be a definition. | |
542 | // external This is a "proxy" atom produced by a dylib reader. It has no content. It exists | |
543 | // so that the graph of Atoms can be complete. | |
544 | // external-weak Same as external, but the definition in the dylib is weak. | |
545 | // | |
546 | // SymbolTableInclusion: | |
547 | // An atom may or may not be in the symbol table in an object file. | |
548 | // in Most atoms for functions or global data | |
549 | // not-in Anonymous atoms such literal c-strings, or other compiler generated data | |
550 | // not-in-final Atom whose name should not be in the symbol table of final linkd image (e.g. 'l' labels .eh labels) | |
551 | // in-never-strip Atom whose name the strip tool should never remove (e.g. REFERENCED_DYNAMICALLY in mach-o) | |
552 | // | |
553 | // ContentType: | |
554 | // Some atoms require specially processing by the linker based on their content. For instance, zero-fill data | |
555 | // atom are group together at the end of the DATA segment to reduce disk size. | |
556 | // | |
557 | // ObjectAddress: | |
558 | // For reproducability, the linker lays out atoms in the order they occurred in the source (object) files. | |
559 | // The objectAddress() method returns the address of an atom in the object file so that the linker | |
560 | // can arrange the atoms. | |
561 | // | |
562 | // | |
563 | class Atom | |
564 | { | |
565 | public: | |
566 | enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal }; | |
567 | enum Definition { definitionRegular, definitionTentative, definitionAbsolute, definitionProxy }; | |
568 | enum Combine { combineNever, combineByName, combineByNameAndContent, combineByNameAndReferences }; | |
569 | enum ContentType { typeUnclassified, typeZeroFill, typeCString, typeCFI, typeLSDA, typeSectionStart, | |
570 | typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer, | |
571 | typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers, | |
572 | typeLTOtemporary, typeResolver, | |
573 | typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers }; | |
574 | ||
575 | enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn, | |
576 | symbolTableInAndNeverStrip, symbolTableInAsAbsolute, | |
577 | symbolTableInWithRandomAutoStripLabel }; | |
afe874b1 A |
578 | enum WeakImportState { weakImportUnset, weakImportTrue, weakImportFalse }; |
579 | ||
a645023d A |
580 | struct Alignment { |
581 | Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {} | |
582 | uint8_t trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); } | |
583 | uint16_t powerOf2; | |
584 | uint16_t modulus; | |
585 | }; | |
586 | struct LineInfo { | |
587 | const char* fileName; | |
588 | uint32_t atomOffset; | |
589 | uint32_t lineNumber; | |
590 | ||
591 | typedef LineInfo* iterator; | |
592 | }; | |
593 | struct UnwindInfo { | |
594 | uint32_t startOffset; | |
595 | uint32_t unwindInfo; | |
596 | ||
597 | typedef UnwindInfo* iterator; | |
598 | }; | |
599 | ||
600 | Atom(const Section& sect, Definition d, Combine c, Scope s, ContentType ct, | |
601 | SymbolTableInclusion i, bool dds, bool thumb, bool al, Alignment a) : | |
602 | _section(§), _address(0), _alignmentModulus(a.modulus), | |
603 | _alignmentPowerOf2(a.powerOf2), _definition(d), _combine(c), | |
604 | _dontDeadStrip(dds), _thumb(thumb), _alias(al), _autoHide(false), | |
605 | _contentType(ct), _symbolTableInclusion(i), | |
606 | _scope(s), _mode(modeSectionOffset), | |
607 | _overridesADylibsWeakDef(false), _coalescedAway(false), | |
afe874b1 | 608 | _live(false), _machoSection(0), _weakImportState(weakImportUnset) |
a645023d A |
609 | { |
610 | #ifndef NDEBUG | |
611 | switch ( _combine ) { | |
612 | case combineByNameAndContent: | |
613 | case combineByNameAndReferences: | |
614 | assert(_symbolTableInclusion == symbolTableNotIn); | |
615 | assert(_scope != scopeGlobal); | |
616 | break; | |
617 | case combineByName: | |
618 | case combineNever: | |
619 | break; | |
620 | }; | |
621 | #endif | |
622 | } | |
623 | virtual ~Atom() {} | |
624 | ||
625 | const Section& section() const { return *_section; } | |
626 | Definition definition() const { return _definition; } | |
627 | Combine combine() const { return _combine; } | |
628 | Scope scope() const { return _scope; } | |
629 | ContentType contentType() const { return _contentType; } | |
630 | SymbolTableInclusion symbolTableInclusion() const{ return _symbolTableInclusion; } | |
631 | bool dontDeadStrip() const { return _dontDeadStrip; } | |
632 | bool isThumb() const { return _thumb; } | |
633 | bool isAlias() const { return _alias; } | |
634 | Alignment alignment() const { return Alignment(_alignmentPowerOf2, _alignmentModulus); } | |
635 | bool overridesDylibsWeakDef() const { return _overridesADylibsWeakDef; } | |
636 | bool coalescedAway() const { return _coalescedAway; } | |
afe874b1 A |
637 | bool weakImported() const { return _weakImportState == weakImportTrue; } |
638 | WeakImportState weakImportState() const { return _weakImportState; } | |
a645023d A |
639 | bool autoHide() const { return _autoHide; } |
640 | bool live() const { return _live; } | |
641 | uint8_t machoSection() const { assert(_machoSection != 0); return _machoSection; } | |
642 | ||
643 | void setScope(Scope s) { _scope = s; } | |
644 | void setSymbolTableInclusion(SymbolTableInclusion i) | |
645 | { _symbolTableInclusion = i; } | |
646 | void setCombine(Combine c) { _combine = c; } | |
647 | void setOverridesDylibsWeakDef() { _overridesADylibsWeakDef = true; } | |
648 | void setCoalescedAway() { _coalescedAway = true; } | |
afe874b1 | 649 | void setWeakImportState(bool w) { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); } |
a645023d A |
650 | void setAutoHide() { _autoHide = true; } |
651 | void setLive() { _live = true; } | |
652 | void setLive(bool value) { _live = value; } | |
653 | void setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; } | |
654 | void setSectionOffset(uint64_t o){ assert(_mode == modeSectionOffset); _address = o; _mode = modeSectionOffset; } | |
655 | void setSectionStartAddress(uint64_t a) { assert(_mode == modeSectionOffset); _address += a; _mode = modeFinalAddress; } | |
656 | uint64_t sectionOffset() const { assert(_mode == modeSectionOffset); return _address; } | |
657 | uint64_t finalAddress() const { assert(_mode == modeFinalAddress); return _address; } | |
ebf6f434 A |
658 | #ifndef NDEBUG |
659 | bool finalAddressMode() const { return (_mode == modeFinalAddress); } | |
660 | #endif | |
a645023d | 661 | virtual const File* file() const = 0; |
b1f7435d | 662 | virtual const char* translationUnitSource() const { return NULL; } |
a645023d A |
663 | virtual const char* name() const = 0; |
664 | virtual uint64_t objectAddress() const = 0; | |
665 | virtual uint64_t size() const = 0; | |
666 | virtual void copyRawContent(uint8_t buffer[]) const = 0; | |
667 | virtual const uint8_t* rawContentPointer() const { return NULL; } | |
668 | virtual unsigned long contentHash(const class IndirectBindingTable&) const { return 0; } | |
669 | virtual bool canCoalesceWith(const Atom& rhs, const class IndirectBindingTable&) const { return false; } | |
670 | virtual Fixup::iterator fixupsBegin() const { return NULL; } | |
671 | virtual Fixup::iterator fixupsEnd() const { return NULL; } | |
ebf6f434 A |
672 | bool hasFixupsOfKind(Fixup::Kind kind) const { |
673 | for (ld::Fixup::iterator fit = fixupsBegin(), end=fixupsEnd(); fit != end; ++fit) { | |
674 | if ( fit->kind == kind ) return true; | |
675 | } | |
676 | return false; | |
677 | } | |
678 | ||
a645023d A |
679 | virtual UnwindInfo::iterator beginUnwind() const { return NULL; } |
680 | virtual UnwindInfo::iterator endUnwind() const { return NULL; } | |
681 | virtual LineInfo::iterator beginLineInfo() const { return NULL; } | |
682 | virtual LineInfo::iterator endLineInfo() const { return NULL; } | |
683 | ||
684 | protected: | |
685 | enum AddressMode { modeSectionOffset, modeFinalAddress }; | |
686 | ||
687 | void setAttributesFromAtom(const Atom& a) { | |
688 | _section = a._section; | |
689 | _alignmentModulus = a._alignmentModulus; | |
690 | _alignmentPowerOf2 = a._alignmentPowerOf2; | |
691 | _definition = a._definition; | |
692 | _combine = a._combine; | |
693 | _dontDeadStrip = a._dontDeadStrip; | |
694 | _thumb = a._thumb; | |
695 | _alias = a._alias; | |
696 | _autoHide = a._autoHide; | |
697 | _contentType = a._contentType; | |
698 | _symbolTableInclusion = a._symbolTableInclusion; | |
699 | _scope = a._scope; | |
700 | _mode = a._mode; | |
701 | _overridesADylibsWeakDef = a._overridesADylibsWeakDef; | |
702 | _coalescedAway = a._coalescedAway; | |
afe874b1 | 703 | _weakImportState = a._weakImportState; |
a645023d A |
704 | } |
705 | ||
706 | const Section * _section; | |
707 | uint64_t _address; | |
708 | uint16_t _alignmentModulus; | |
709 | uint8_t _alignmentPowerOf2; | |
710 | Definition _definition : 2; | |
711 | Combine _combine : 2; | |
712 | bool _dontDeadStrip : 1; | |
713 | bool _thumb : 1; | |
714 | bool _alias : 1; | |
715 | int _autoHide : 1; | |
716 | ContentType _contentType : 5; | |
717 | SymbolTableInclusion _symbolTableInclusion : 3; | |
718 | Scope _scope : 2; | |
719 | AddressMode _mode: 2; | |
720 | bool _overridesADylibsWeakDef : 1; | |
721 | bool _coalescedAway : 1; | |
a645023d A |
722 | bool _live : 1; |
723 | unsigned _machoSection : 8; | |
afe874b1 | 724 | WeakImportState _weakImportState : 2; |
a645023d A |
725 | }; |
726 | ||
727 | ||
728 | class IndirectBindingTable | |
729 | { | |
730 | public: | |
731 | virtual const char* indirectName(uint32_t bindingIndex) const = 0; | |
732 | virtual const ld::Atom* indirectAtom(uint32_t bindingIndex) const = 0; | |
733 | }; | |
734 | ||
735 | ||
736 | class Internal | |
737 | { | |
738 | public: | |
739 | class FinalSection : public ld::Section { | |
740 | public: | |
741 | FinalSection(const Section& sect) : Section(sect), address(0), | |
742 | fileOffset(0), size(0), alignment(0), | |
743 | indirectSymTabStartIndex(0), indirectSymTabElementSize(0), | |
744 | relocStart(0), relocCount(0), | |
745 | hasLocalRelocs(false), hasExternalRelocs(false) {} | |
746 | std::vector<const Atom*> atoms; | |
747 | uint64_t address; | |
748 | uint64_t fileOffset; | |
749 | uint64_t size; | |
750 | uint32_t alignmentPaddingBytes; | |
751 | uint8_t alignment; | |
752 | uint32_t indirectSymTabStartIndex; | |
753 | uint32_t indirectSymTabElementSize; | |
754 | uint32_t relocStart; | |
755 | uint32_t relocCount; | |
756 | bool hasLocalRelocs; | |
757 | bool hasExternalRelocs; | |
758 | }; | |
759 | ||
760 | virtual ld::Internal::FinalSection* addAtom(const Atom&) = 0; | |
761 | virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0; | |
762 | virtual ~Internal() {} | |
763 | Internal() : bundleLoader(NULL), | |
764 | entryPoint(NULL), classicBindingHelper(NULL), | |
765 | lazyBindingHelper(NULL), compressedFastBinderProxy(NULL), | |
766 | objcObjectConstraint(ld::File::objcConstraintNone), | |
767 | objcDylibConstraint(ld::File::objcConstraintNone), | |
768 | cpuSubType(0), | |
ebf6f434 | 769 | allObjectFilesScatterable(true), |
a645023d A |
770 | someObjectFileHasDwarf(false), usingHugeSections(false) { } |
771 | ||
772 | std::vector<FinalSection*> sections; | |
773 | std::vector<ld::dylib::File*> dylibs; | |
774 | std::vector<ld::relocatable::File::Stab> stabs; | |
775 | std::vector<const ld::Atom*> indirectBindingTable; | |
776 | const ld::dylib::File* bundleLoader; | |
777 | const Atom* entryPoint; | |
778 | const Atom* classicBindingHelper; | |
779 | const Atom* lazyBindingHelper; | |
780 | const Atom* compressedFastBinderProxy; | |
781 | ld::File::ObjcConstraint objcObjectConstraint; | |
782 | ld::File::ObjcConstraint objcDylibConstraint; | |
783 | uint32_t cpuSubType; | |
784 | bool allObjectFilesScatterable; | |
a645023d A |
785 | bool someObjectFileHasDwarf; |
786 | bool usingHugeSections; | |
787 | }; | |
788 | ||
789 | ||
790 | ||
d425e388 A |
791 | |
792 | // utility classes for using std::unordered_map with c-strings | |
793 | struct CStringHash { | |
794 | size_t operator()(const char* __s) const { | |
795 | size_t __h = 0; | |
796 | for ( ; *__s; ++__s) | |
797 | __h = 5 * __h + *__s; | |
798 | return __h; | |
799 | }; | |
800 | }; | |
801 | struct CStringEquals | |
802 | { | |
803 | bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } | |
804 | }; | |
a645023d A |
805 | |
806 | ||
807 | ||
808 | ||
809 | ||
810 | ||
811 | ||
812 | ||
813 | ||
814 | } // namespace ld | |
815 | ||
816 | #endif // __LD_HPP__ |