]>
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 | ||
63 | File(const char* pth, time_t modTime, uint32_t ord) | |
64 | : _path(pth), _modTime(modTime), _ordinal(ord) { } | |
65 | virtual ~File() {} | |
66 | const char* path() const { return _path; } | |
67 | time_t modificationTime() const{ return _modTime; } | |
68 | uint32_t ordinal() const { return _ordinal; } | |
69 | virtual bool forEachAtom(AtomHandler&) const = 0; | |
70 | virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const = 0; | |
71 | virtual ObjcConstraint objCConstraint() const { return objcConstraintNone; } | |
72 | virtual uint32_t cpuSubType() const { return 0; } | |
73 | virtual uint32_t subFileCount() const { return 1; } | |
74 | private: | |
75 | const char* _path; | |
76 | time_t _modTime; | |
77 | uint32_t _ordinal; | |
78 | }; | |
79 | ||
80 | ||
81 | // | |
82 | // minumum OS versions | |
83 | // | |
84 | enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, | |
85 | mac10_6=0x000A0600, mac10_7=0x000A0700 }; | |
afe874b1 A |
86 | enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100, |
87 | iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000 }; | |
a645023d A |
88 | |
89 | namespace relocatable { | |
90 | // | |
91 | // ld::relocatable::File | |
92 | // | |
93 | // Abstract base class for object files the linker processes. | |
94 | // | |
95 | // objcReplacementClasses() is reflects if the file was compiled for fix-and-continue | |
96 | // | |
97 | // debugInfo() returns if the object file contains debugger information (stabs or dwarf). | |
98 | // | |
99 | // stabs() lazily creates a vector of Stab objects for each atom | |
100 | // | |
101 | // canScatterAtoms() true for all compiler generated code. Hand written assembly can opt-in | |
102 | // via .subsections_via_symbols directive. When true it means the linker can break up section | |
103 | // content at symbol boundaries and do optimizations like coalescing, dead code stripping, or | |
104 | // apply order files. | |
105 | // | |
106 | // optimize() used by libLTO to lazily generate code from llvm bit-code files | |
107 | // | |
108 | class File : public ld::File | |
109 | { | |
110 | public: | |
111 | enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 }; | |
112 | struct Stab { | |
113 | const class Atom* atom; | |
114 | uint8_t type; | |
115 | uint8_t other; | |
116 | uint16_t desc; | |
117 | uint32_t value; | |
118 | const char* string; | |
119 | }; | |
120 | ||
121 | File(const char* pth, time_t modTime, uint32_t ord) | |
122 | : ld::File(pth, modTime, ord) { } | |
123 | virtual ~File() {} | |
124 | virtual bool objcReplacementClasses() const = 0; | |
125 | virtual DebugInfoKind debugInfo() const = 0; | |
126 | virtual const char* debugInfoPath() const { return path(); } | |
127 | virtual time_t debugInfoModificationTime() const { return modificationTime(); } | |
128 | virtual const std::vector<Stab>* stabs() const = 0; | |
129 | virtual bool canScatterAtoms() const = 0; | |
130 | virtual bool hasLongBranchStubs() { return false; } | |
131 | }; | |
132 | } // namespace relocatable | |
133 | ||
134 | ||
135 | namespace dylib { | |
136 | ||
137 | // | |
138 | // ld::dylib::File | |
139 | // | |
140 | // Abstract base class for dynamic shared libraries read by the linker processes. | |
141 | // | |
142 | class File : public ld::File | |
143 | { | |
144 | public: | |
145 | class DylibHandler | |
146 | { | |
147 | public: | |
148 | virtual ~DylibHandler() {} | |
149 | virtual File* findDylib(const char* installPath, const char* fromPath) = 0; | |
150 | }; | |
151 | ||
152 | File(const char* pth, time_t modTime, uint32_t ord) | |
153 | : ld::File(pth, modTime, ord), _dylibInstallPath(NULL), | |
154 | _dylibTimeStamp(0), _dylibCurrentVersion(0), _dylibCompatibilityVersion(0), | |
155 | _explicitlyLinked(false), _implicitlyLinked(false), | |
afe874b1 A |
156 | _lazyLoadedDylib(false), _forcedWeakLinked(false), _reExported(false), |
157 | _upward(false), _dead(false) { } | |
a645023d A |
158 | const char* installPath() const { return _dylibInstallPath; } |
159 | uint32_t timestamp() const { return _dylibTimeStamp; } | |
160 | uint32_t currentVersion() const { return _dylibCurrentVersion; } | |
161 | uint32_t compatibilityVersion() const{ return _dylibCompatibilityVersion; } | |
162 | void setExplicitlyLinked() { _explicitlyLinked = true; } | |
163 | bool explicitlyLinked() const { return _explicitlyLinked; } | |
164 | void setImplicitlyLinked() { _implicitlyLinked = true; } | |
165 | bool implicitlyLinked() const { return _implicitlyLinked; } | |
166 | // attributes of how dylib will be used when linked | |
167 | void setWillBeLazyLoadedDylb() { _lazyLoadedDylib = true; } | |
168 | bool willBeLazyLoadedDylib() const { return _lazyLoadedDylib; } | |
afe874b1 A |
169 | void setForcedWeakLinked() { _forcedWeakLinked = true; } |
170 | bool forcedWeakLinked() const { return _forcedWeakLinked; } | |
171 | ||
a645023d A |
172 | void setWillBeReExported() { _reExported = true; } |
173 | bool willBeReExported() const { return _reExported; } | |
174 | void setWillBeUpwardDylib() { _upward = true; } | |
175 | bool willBeUpwardDylib() const { return _upward; } | |
a645023d A |
176 | void setWillBeRemoved(bool value) { _dead = value; } |
177 | bool willRemoved() const { return _dead; } | |
178 | ||
179 | virtual void processIndirectLibraries(DylibHandler* handler, bool addImplicitDylibs) = 0; | |
180 | virtual bool providedExportAtom() const = 0; | |
181 | virtual const char* parentUmbrella() const = 0; | |
182 | virtual const std::vector<const char*>* allowableClients() const = 0; | |
183 | virtual bool hasWeakExternals() const = 0; | |
184 | virtual bool deadStrippable() const = 0; | |
185 | virtual bool hasWeakDefinition(const char* name) const = 0; | |
186 | virtual bool hasPublicInstallName() const = 0; | |
afe874b1 | 187 | virtual bool allSymbolsAreWeakImported() const = 0; |
a645023d A |
188 | protected: |
189 | const char* _dylibInstallPath; | |
190 | uint32_t _dylibTimeStamp; | |
191 | uint32_t _dylibCurrentVersion; | |
192 | uint32_t _dylibCompatibilityVersion; | |
193 | bool _explicitlyLinked; | |
194 | bool _implicitlyLinked; | |
195 | bool _lazyLoadedDylib; | |
afe874b1 | 196 | bool _forcedWeakLinked; |
a645023d A |
197 | bool _reExported; |
198 | bool _upward; | |
a645023d A |
199 | bool _dead; |
200 | }; | |
201 | } // namespace dylib | |
202 | ||
203 | ||
afe874b1 A |
204 | namespace archive { |
205 | // | |
206 | // ld::archive::File | |
207 | // | |
208 | // Abstract base class for static libraries read by the linker processes. | |
209 | // | |
210 | class File : public ld::File | |
211 | { | |
212 | public: | |
213 | File(const char* pth, time_t modTime, uint32_t ord) | |
214 | : ld::File(pth, modTime, ord) { } | |
215 | virtual ~File() {} | |
216 | virtual bool justInTimeDataOnlyforEachAtom(const char* name, AtomHandler&) const = 0; | |
217 | }; | |
218 | } // namespace archive | |
219 | ||
a645023d A |
220 | |
221 | // | |
222 | // ld::Section | |
223 | // | |
224 | class Section | |
225 | { | |
226 | public: | |
227 | enum Type { typeUnclassified, typeCode, typePageZero, typeImportProxies, typeLinkEdit, typeMachHeader, typeStack, | |
228 | typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, | |
229 | typeCString, typeNonStdCString, typeCStringPointer, typeUTF16Strings, typeCFString, typeObjC1Classes, | |
230 | typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList, | |
231 | typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo, | |
232 | typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers, | |
233 | typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, | |
234 | typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers, | |
afe874b1 | 235 | typeFirstSection, typeLastSection, typeDebug }; |
a645023d A |
236 | |
237 | ||
238 | Section(const char* sgName, const char* sctName, | |
239 | Type t, bool hidden=false) | |
240 | : _segmentName(sgName), _sectionName(sctName), | |
241 | _type(t), _hidden(hidden) {} | |
242 | Section(const Section& sect) | |
243 | : _segmentName(sect.segmentName()), _sectionName(sect.sectionName()), | |
244 | _type(sect.type()), _hidden(sect.isSectionHidden()) {} | |
245 | ||
246 | bool operator==(const Section& rhs) const { return ( (_hidden==rhs._hidden) && | |
247 | (strcmp(_segmentName, rhs._segmentName)==0) && | |
248 | (strcmp(_sectionName, rhs._sectionName)==0) ); } | |
249 | bool operator!=(const Section& rhs) const { return ! (*this == rhs); } | |
250 | const char* segmentName() const { return _segmentName; } | |
251 | const char* sectionName() const { return _sectionName; } | |
252 | Type type() const { return _type; } | |
253 | bool isSectionHidden() const { return _hidden; } | |
254 | ||
255 | private: | |
256 | const char* _segmentName; | |
257 | const char* _sectionName; | |
258 | Type _type; | |
259 | bool _hidden; | |
260 | }; | |
261 | ||
262 | ||
263 | ||
264 | // | |
265 | // ld::Fixup | |
266 | // | |
267 | // A Fixup describes how part of an Atom's content must be fixed up. For instance, | |
268 | // an instruction may contain a displacement to another Atom that must be | |
269 | // fixed up by the linker. | |
270 | // | |
271 | // A Fixup my reference another Atom. There are two kinds of references: direct and by-name. | |
272 | // With a direct reference, the target is bound by the File that created it. | |
273 | // For instance a reference to a static would produce a direct reference. | |
274 | // A by-name reference requires the linker to find the target Atom with the | |
275 | // required name in order to be bound. | |
276 | // | |
277 | // For a link to succeed all Fixup must be bound. | |
278 | // | |
279 | // A Reference also has a fix-up-offset. This is the offset into the content of the | |
280 | // Atom holding the reference where the fix-up (relocation) will be applied. | |
281 | // | |
282 | // | |
283 | struct Fixup | |
284 | { | |
285 | enum TargetBinding { bindingNone, bindingByNameUnbound, bindingDirectlyBound, bindingByContentBound, bindingsIndirectlyBound }; | |
286 | enum Cluster { k1of1, k1of2, k2of2, k1of3, k2of3, k3of3, k1of4, k2of4, k3of4, k4of4, k1of5, k2of5, k3of5, k4of5, k5of5 }; | |
287 | enum Kind { kindNone, kindNoneFollowOn, | |
288 | // grouping | |
289 | kindNoneGroupSubordinate, | |
290 | kindNoneGroupSubordinateFDE, kindNoneGroupSubordinateLSDA, kindNoneGroupSubordinatePersonality, | |
291 | // value calculations | |
292 | kindSetTargetAddress, | |
293 | kindSubtractTargetAddress, | |
294 | kindAddAddend, | |
295 | kindSubtractAddend, | |
296 | kindSetTargetImageOffset, | |
297 | kindSetTargetSectionOffset, | |
298 | kindSetTargetTLVTemplateOffset, | |
299 | // pointer store kinds (of current calculated value) | |
300 | kindStore8, | |
301 | kindStoreLittleEndian16, | |
302 | kindStoreLittleEndianLow24of32, | |
303 | kindStoreLittleEndian32, | |
304 | kindStoreLittleEndian64, | |
305 | kindStoreBigEndian16, | |
306 | kindStoreBigEndianLow24of32, | |
307 | kindStoreBigEndian32, | |
308 | kindStoreBigEndian64, | |
309 | // Intel specific store kinds | |
310 | kindStoreX86BranchPCRel8, kindStoreX86BranchPCRel32, | |
311 | kindStoreX86PCRel8, kindStoreX86PCRel16, | |
312 | kindStoreX86PCRel32, kindStoreX86PCRel32_1, kindStoreX86PCRel32_2, kindStoreX86PCRel32_4, | |
313 | kindStoreX86PCRel32GOTLoad, kindStoreX86PCRel32GOTLoadNowLEA, kindStoreX86PCRel32GOT, | |
314 | kindStoreX86PCRel32TLVLoad, kindStoreX86PCRel32TLVLoadNowLEA, | |
315 | kindStoreX86Abs32TLVLoad, kindStoreX86Abs32TLVLoadNowLEA, | |
316 | // ARM specific store kinds | |
317 | kindStoreARMBranch24, kindStoreThumbBranch22, | |
318 | kindStoreARMLoad12, | |
319 | kindStoreARMLow16, kindStoreARMHigh16, | |
320 | kindStoreThumbLow16, kindStoreThumbHigh16, | |
a645023d A |
321 | // dtrace probes |
322 | kindDtraceExtra, | |
323 | kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear, | |
324 | kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear, | |
325 | kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear, | |
a645023d A |
326 | // lazy binding |
327 | kindLazyTarget, kindSetLazyOffset, | |
328 | // pointer store combinations | |
329 | kindStoreTargetAddressLittleEndian32, // kindSetTargetAddress + kindStoreLittleEndian32 | |
330 | kindStoreTargetAddressLittleEndian64, // kindSetTargetAddress + kindStoreLittleEndian64 | |
331 | kindStoreTargetAddressBigEndian32, // kindSetTargetAddress + kindStoreBigEndian32 | |
332 | kindStoreTargetAddressBigEndian64, // kindSetTargetAddress + kindStoreBigEndian364 | |
333 | kindSetTargetTLVTemplateOffsetLittleEndian32, // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian32 | |
334 | kindSetTargetTLVTemplateOffsetLittleEndian64, // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian64 | |
335 | // Intel value calculation and store combinations | |
336 | kindStoreTargetAddressX86PCRel32, // kindSetTargetAddress + kindStoreX86PCRel32 | |
337 | kindStoreTargetAddressX86BranchPCRel32, // kindSetTargetAddress + kindStoreX86BranchPCRel32 | |
338 | kindStoreTargetAddressX86PCRel32GOTLoad,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoad | |
339 | kindStoreTargetAddressX86PCRel32GOTLoadNowLEA,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoadNowLEA | |
340 | kindStoreTargetAddressX86PCRel32TLVLoad, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoad | |
341 | kindStoreTargetAddressX86PCRel32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoadNowLEA | |
342 | kindStoreTargetAddressX86Abs32TLVLoad, // kindSetTargetAddress + kindStoreX86Abs32TLVLoad | |
343 | kindStoreTargetAddressX86Abs32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86Abs32TLVLoadNowLEA | |
344 | // ARM value calculation and store combinations | |
345 | kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24 | |
346 | kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22 | |
347 | kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12 | |
a645023d A |
348 | }; |
349 | ||
350 | union { | |
351 | const Atom* target; | |
352 | const char* name; | |
353 | uint64_t addend; | |
354 | uint32_t bindingIndex; | |
355 | } u; | |
356 | uint32_t offsetInAtom; | |
357 | Kind kind : 8; | |
358 | Cluster clusterSize : 4; | |
359 | bool weakImport : 1; | |
360 | TargetBinding binding : 3; | |
361 | bool contentAddendOnly : 1; | |
362 | bool contentDetlaToAddendOnly : 1; | |
363 | ||
364 | typedef Fixup* iterator; | |
365 | ||
366 | Fixup() : | |
367 | offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false), | |
368 | binding(bindingNone), | |
369 | contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; } | |
370 | ||
371 | Fixup(Kind k, Atom* targetAtom) : | |
372 | offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false), | |
373 | binding(Fixup::bindingDirectlyBound), | |
374 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
375 | { assert(targetAtom != NULL); u.target = targetAtom; } | |
376 | ||
377 | Fixup(uint32_t off, Cluster c, Kind k) : | |
378 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), | |
379 | binding(Fixup::bindingNone), | |
380 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
381 | { u.addend = 0; } | |
382 | ||
383 | Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) : | |
384 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm), | |
385 | binding(Fixup::bindingByNameUnbound), | |
386 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
387 | { assert(name != NULL); u.name = name; } | |
388 | ||
389 | Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) : | |
390 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b), | |
391 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
392 | { assert(name != NULL); u.name = name; } | |
393 | ||
394 | Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) : | |
395 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), | |
396 | binding(Fixup::bindingDirectlyBound), | |
397 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
398 | { assert(targetAtom != NULL); u.target = targetAtom; } | |
399 | ||
400 | Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) : | |
401 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b), | |
402 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
403 | { assert(targetAtom != NULL); u.target = targetAtom; } | |
404 | ||
405 | Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) : | |
406 | offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), | |
407 | binding(Fixup::bindingNone), | |
408 | contentAddendOnly(false), contentDetlaToAddendOnly(false) | |
409 | { u.addend = addend; } | |
410 | ||
411 | bool firstInCluster() const { | |
412 | switch (clusterSize) { | |
413 | case k1of1: | |
414 | case k1of2: | |
415 | case k1of3: | |
416 | case k1of4: | |
417 | case k1of5: | |
418 | return true; | |
419 | default: | |
420 | break; | |
421 | } | |
422 | return false; | |
423 | } | |
424 | ||
425 | bool lastInCluster() const { | |
426 | switch (clusterSize) { | |
427 | case k1of1: | |
428 | case k2of2: | |
429 | case k3of3: | |
430 | case k4of4: | |
431 | case k5of5: | |
432 | return true; | |
433 | default: | |
434 | break; | |
435 | } | |
436 | return false; | |
437 | } | |
438 | ||
439 | }; | |
440 | ||
441 | // | |
442 | // ld::Atom | |
443 | // | |
444 | // An atom is the fundamental unit of linking. A C function or global variable is an atom. | |
445 | // An atom has content and attributes. The content of a function atom is the instructions | |
446 | // that implement the function. The content of a global variable atom is its initial bits. | |
447 | // | |
448 | // Name: | |
449 | // The name of an atom is the label name generated by the compiler. A C compiler names foo() | |
450 | // as _foo. A C++ compiler names foo() as __Z3foov. | |
451 | // The name refers to the first byte of the content. An atom cannot have multiple entry points. | |
452 | // Such code is modeled as multiple atoms, each having a "follow on" reference to the next. | |
453 | // A "follow on" reference is a contraint to the linker to the atoms must be laid out contiguously. | |
454 | // | |
455 | // Scope: | |
456 | // An atom is in one of three scopes: translation-unit, linkage-unit, or global. These correspond | |
457 | // to the C visibility of static, hidden, default. | |
458 | // | |
459 | // DefinitionKind: | |
460 | // An atom is one of five defintion kinds: | |
461 | // regular Most atoms. | |
462 | // weak C++ compiler makes some functions weak if there might be multiple copies | |
463 | // that the linker needs to coalesce. | |
464 | // tentative A straggler from ancient C when the extern did not exist. "int foo;" is ambiguous. | |
465 | // It could be a prototype or it could be a definition. | |
466 | // external This is a "proxy" atom produced by a dylib reader. It has no content. It exists | |
467 | // so that the graph of Atoms can be complete. | |
468 | // external-weak Same as external, but the definition in the dylib is weak. | |
469 | // | |
470 | // SymbolTableInclusion: | |
471 | // An atom may or may not be in the symbol table in an object file. | |
472 | // in Most atoms for functions or global data | |
473 | // not-in Anonymous atoms such literal c-strings, or other compiler generated data | |
474 | // not-in-final Atom whose name should not be in the symbol table of final linkd image (e.g. 'l' labels .eh labels) | |
475 | // in-never-strip Atom whose name the strip tool should never remove (e.g. REFERENCED_DYNAMICALLY in mach-o) | |
476 | // | |
477 | // ContentType: | |
478 | // Some atoms require specially processing by the linker based on their content. For instance, zero-fill data | |
479 | // atom are group together at the end of the DATA segment to reduce disk size. | |
480 | // | |
481 | // ObjectAddress: | |
482 | // For reproducability, the linker lays out atoms in the order they occurred in the source (object) files. | |
483 | // The objectAddress() method returns the address of an atom in the object file so that the linker | |
484 | // can arrange the atoms. | |
485 | // | |
486 | // | |
487 | class Atom | |
488 | { | |
489 | public: | |
490 | enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal }; | |
491 | enum Definition { definitionRegular, definitionTentative, definitionAbsolute, definitionProxy }; | |
492 | enum Combine { combineNever, combineByName, combineByNameAndContent, combineByNameAndReferences }; | |
493 | enum ContentType { typeUnclassified, typeZeroFill, typeCString, typeCFI, typeLSDA, typeSectionStart, | |
494 | typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer, | |
495 | typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers, | |
496 | typeLTOtemporary, typeResolver, | |
497 | typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers }; | |
498 | ||
499 | enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn, | |
500 | symbolTableInAndNeverStrip, symbolTableInAsAbsolute, | |
501 | symbolTableInWithRandomAutoStripLabel }; | |
afe874b1 A |
502 | enum WeakImportState { weakImportUnset, weakImportTrue, weakImportFalse }; |
503 | ||
a645023d A |
504 | struct Alignment { |
505 | Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {} | |
506 | uint8_t trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); } | |
507 | uint16_t powerOf2; | |
508 | uint16_t modulus; | |
509 | }; | |
510 | struct LineInfo { | |
511 | const char* fileName; | |
512 | uint32_t atomOffset; | |
513 | uint32_t lineNumber; | |
514 | ||
515 | typedef LineInfo* iterator; | |
516 | }; | |
517 | struct UnwindInfo { | |
518 | uint32_t startOffset; | |
519 | uint32_t unwindInfo; | |
520 | ||
521 | typedef UnwindInfo* iterator; | |
522 | }; | |
523 | ||
524 | Atom(const Section& sect, Definition d, Combine c, Scope s, ContentType ct, | |
525 | SymbolTableInclusion i, bool dds, bool thumb, bool al, Alignment a) : | |
526 | _section(§), _address(0), _alignmentModulus(a.modulus), | |
527 | _alignmentPowerOf2(a.powerOf2), _definition(d), _combine(c), | |
528 | _dontDeadStrip(dds), _thumb(thumb), _alias(al), _autoHide(false), | |
529 | _contentType(ct), _symbolTableInclusion(i), | |
530 | _scope(s), _mode(modeSectionOffset), | |
531 | _overridesADylibsWeakDef(false), _coalescedAway(false), | |
afe874b1 | 532 | _live(false), _machoSection(0), _weakImportState(weakImportUnset) |
a645023d A |
533 | { |
534 | #ifndef NDEBUG | |
535 | switch ( _combine ) { | |
536 | case combineByNameAndContent: | |
537 | case combineByNameAndReferences: | |
538 | assert(_symbolTableInclusion == symbolTableNotIn); | |
539 | assert(_scope != scopeGlobal); | |
540 | break; | |
541 | case combineByName: | |
542 | case combineNever: | |
543 | break; | |
544 | }; | |
545 | #endif | |
546 | } | |
547 | virtual ~Atom() {} | |
548 | ||
549 | const Section& section() const { return *_section; } | |
550 | Definition definition() const { return _definition; } | |
551 | Combine combine() const { return _combine; } | |
552 | Scope scope() const { return _scope; } | |
553 | ContentType contentType() const { return _contentType; } | |
554 | SymbolTableInclusion symbolTableInclusion() const{ return _symbolTableInclusion; } | |
555 | bool dontDeadStrip() const { return _dontDeadStrip; } | |
556 | bool isThumb() const { return _thumb; } | |
557 | bool isAlias() const { return _alias; } | |
558 | Alignment alignment() const { return Alignment(_alignmentPowerOf2, _alignmentModulus); } | |
559 | bool overridesDylibsWeakDef() const { return _overridesADylibsWeakDef; } | |
560 | bool coalescedAway() const { return _coalescedAway; } | |
afe874b1 A |
561 | bool weakImported() const { return _weakImportState == weakImportTrue; } |
562 | WeakImportState weakImportState() const { return _weakImportState; } | |
a645023d A |
563 | bool autoHide() const { return _autoHide; } |
564 | bool live() const { return _live; } | |
565 | uint8_t machoSection() const { assert(_machoSection != 0); return _machoSection; } | |
566 | ||
567 | void setScope(Scope s) { _scope = s; } | |
568 | void setSymbolTableInclusion(SymbolTableInclusion i) | |
569 | { _symbolTableInclusion = i; } | |
570 | void setCombine(Combine c) { _combine = c; } | |
571 | void setOverridesDylibsWeakDef() { _overridesADylibsWeakDef = true; } | |
572 | void setCoalescedAway() { _coalescedAway = true; } | |
afe874b1 | 573 | void setWeakImportState(bool w) { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); } |
a645023d A |
574 | void setAutoHide() { _autoHide = true; } |
575 | void setLive() { _live = true; } | |
576 | void setLive(bool value) { _live = value; } | |
577 | void setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; } | |
578 | void setSectionOffset(uint64_t o){ assert(_mode == modeSectionOffset); _address = o; _mode = modeSectionOffset; } | |
579 | void setSectionStartAddress(uint64_t a) { assert(_mode == modeSectionOffset); _address += a; _mode = modeFinalAddress; } | |
580 | uint64_t sectionOffset() const { assert(_mode == modeSectionOffset); return _address; } | |
581 | uint64_t finalAddress() const { assert(_mode == modeFinalAddress); return _address; } | |
582 | ||
583 | virtual const File* file() const = 0; | |
584 | virtual bool translationUnitSource(const char** dir, const char** name) const = 0; | |
585 | virtual const char* name() const = 0; | |
586 | virtual uint64_t objectAddress() const = 0; | |
587 | virtual uint64_t size() const = 0; | |
588 | virtual void copyRawContent(uint8_t buffer[]) const = 0; | |
589 | virtual const uint8_t* rawContentPointer() const { return NULL; } | |
590 | virtual unsigned long contentHash(const class IndirectBindingTable&) const { return 0; } | |
591 | virtual bool canCoalesceWith(const Atom& rhs, const class IndirectBindingTable&) const { return false; } | |
592 | virtual Fixup::iterator fixupsBegin() const { return NULL; } | |
593 | virtual Fixup::iterator fixupsEnd() const { return NULL; } | |
594 | virtual UnwindInfo::iterator beginUnwind() const { return NULL; } | |
595 | virtual UnwindInfo::iterator endUnwind() const { return NULL; } | |
596 | virtual LineInfo::iterator beginLineInfo() const { return NULL; } | |
597 | virtual LineInfo::iterator endLineInfo() const { return NULL; } | |
598 | ||
599 | protected: | |
600 | enum AddressMode { modeSectionOffset, modeFinalAddress }; | |
601 | ||
602 | void setAttributesFromAtom(const Atom& a) { | |
603 | _section = a._section; | |
604 | _alignmentModulus = a._alignmentModulus; | |
605 | _alignmentPowerOf2 = a._alignmentPowerOf2; | |
606 | _definition = a._definition; | |
607 | _combine = a._combine; | |
608 | _dontDeadStrip = a._dontDeadStrip; | |
609 | _thumb = a._thumb; | |
610 | _alias = a._alias; | |
611 | _autoHide = a._autoHide; | |
612 | _contentType = a._contentType; | |
613 | _symbolTableInclusion = a._symbolTableInclusion; | |
614 | _scope = a._scope; | |
615 | _mode = a._mode; | |
616 | _overridesADylibsWeakDef = a._overridesADylibsWeakDef; | |
617 | _coalescedAway = a._coalescedAway; | |
afe874b1 | 618 | _weakImportState = a._weakImportState; |
a645023d A |
619 | } |
620 | ||
621 | const Section * _section; | |
622 | uint64_t _address; | |
623 | uint16_t _alignmentModulus; | |
624 | uint8_t _alignmentPowerOf2; | |
625 | Definition _definition : 2; | |
626 | Combine _combine : 2; | |
627 | bool _dontDeadStrip : 1; | |
628 | bool _thumb : 1; | |
629 | bool _alias : 1; | |
630 | int _autoHide : 1; | |
631 | ContentType _contentType : 5; | |
632 | SymbolTableInclusion _symbolTableInclusion : 3; | |
633 | Scope _scope : 2; | |
634 | AddressMode _mode: 2; | |
635 | bool _overridesADylibsWeakDef : 1; | |
636 | bool _coalescedAway : 1; | |
a645023d A |
637 | bool _live : 1; |
638 | unsigned _machoSection : 8; | |
afe874b1 | 639 | WeakImportState _weakImportState : 2; |
a645023d A |
640 | }; |
641 | ||
642 | ||
643 | class IndirectBindingTable | |
644 | { | |
645 | public: | |
646 | virtual const char* indirectName(uint32_t bindingIndex) const = 0; | |
647 | virtual const ld::Atom* indirectAtom(uint32_t bindingIndex) const = 0; | |
648 | }; | |
649 | ||
650 | ||
651 | class Internal | |
652 | { | |
653 | public: | |
654 | class FinalSection : public ld::Section { | |
655 | public: | |
656 | FinalSection(const Section& sect) : Section(sect), address(0), | |
657 | fileOffset(0), size(0), alignment(0), | |
658 | indirectSymTabStartIndex(0), indirectSymTabElementSize(0), | |
659 | relocStart(0), relocCount(0), | |
660 | hasLocalRelocs(false), hasExternalRelocs(false) {} | |
661 | std::vector<const Atom*> atoms; | |
662 | uint64_t address; | |
663 | uint64_t fileOffset; | |
664 | uint64_t size; | |
665 | uint32_t alignmentPaddingBytes; | |
666 | uint8_t alignment; | |
667 | uint32_t indirectSymTabStartIndex; | |
668 | uint32_t indirectSymTabElementSize; | |
669 | uint32_t relocStart; | |
670 | uint32_t relocCount; | |
671 | bool hasLocalRelocs; | |
672 | bool hasExternalRelocs; | |
673 | }; | |
674 | ||
675 | virtual ld::Internal::FinalSection* addAtom(const Atom&) = 0; | |
676 | virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0; | |
677 | virtual ~Internal() {} | |
678 | Internal() : bundleLoader(NULL), | |
679 | entryPoint(NULL), classicBindingHelper(NULL), | |
680 | lazyBindingHelper(NULL), compressedFastBinderProxy(NULL), | |
681 | objcObjectConstraint(ld::File::objcConstraintNone), | |
682 | objcDylibConstraint(ld::File::objcConstraintNone), | |
683 | cpuSubType(0), | |
684 | allObjectFilesScatterable(true), hasObjcReplacementClasses(false), | |
685 | someObjectFileHasDwarf(false), usingHugeSections(false) { } | |
686 | ||
687 | std::vector<FinalSection*> sections; | |
688 | std::vector<ld::dylib::File*> dylibs; | |
689 | std::vector<ld::relocatable::File::Stab> stabs; | |
690 | std::vector<const ld::Atom*> indirectBindingTable; | |
691 | const ld::dylib::File* bundleLoader; | |
692 | const Atom* entryPoint; | |
693 | const Atom* classicBindingHelper; | |
694 | const Atom* lazyBindingHelper; | |
695 | const Atom* compressedFastBinderProxy; | |
696 | ld::File::ObjcConstraint objcObjectConstraint; | |
697 | ld::File::ObjcConstraint objcDylibConstraint; | |
698 | uint32_t cpuSubType; | |
699 | bool allObjectFilesScatterable; | |
700 | bool hasObjcReplacementClasses; | |
701 | bool someObjectFileHasDwarf; | |
702 | bool usingHugeSections; | |
703 | }; | |
704 | ||
705 | ||
706 | ||
707 | ||
708 | ||
709 | ||
710 | ||
711 | ||
712 | ||
713 | ||
714 | ||
715 | ||
716 | } // namespace ld | |
717 | ||
718 | #endif // __LD_HPP__ |