]> git.saurik.com Git - apple/ld64.git/blob - src/ld/MachOWriterExecutable.hpp
ld64-96.5.tar.gz
[apple/ld64.git] / src / ld / MachOWriterExecutable.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2009 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 #ifndef __EXECUTABLE_MACH_O__
26 #define __EXECUTABLE_MACH_O__
27
28 #include <stdint.h>
29 #include <stddef.h>
30 #include <fcntl.h>
31 #include <sys/time.h>
32 #include <uuid/uuid.h>
33 #include <mach/i386/thread_status.h>
34 #include <mach/ppc/thread_status.h>
35 #include <CommonCrypto/CommonDigest.h>
36
37 #include <vector>
38 #include <algorithm>
39 #include <map>
40 #include <set>
41 #include <ext/hash_map>
42
43 #include "ObjectFile.h"
44 #include "ExecutableFile.h"
45 #include "Options.h"
46
47 #include "MachOFileAbstraction.hpp"
48 #include "MachOTrie.hpp"
49
50
51 //
52 //
53 // To implement architecture xxx, you must write template specializations for the following methods:
54 // MachHeaderAtom<xxx>::setHeaderInfo()
55 // ThreadsLoadCommandsAtom<xxx>::getSize()
56 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
57 // Writer<xxx>::addObjectRelocs()
58 // Writer<xxx>::fixUpReferenceRelocatable()
59 // Writer<xxx>::fixUpReferenceFinal()
60 // Writer<xxx>::stubableReference()
61 // Writer<xxx>::weakImportReferenceKind()
62 // Writer<xxx>::GOTReferenceKind()
63 //
64
65
66 namespace mach_o {
67 namespace executable {
68
69 // forward references
70 template <typename A> class WriterAtom;
71 template <typename A> class PageZeroAtom;
72 template <typename A> class CustomStackAtom;
73 template <typename A> class MachHeaderAtom;
74 template <typename A> class SegmentLoadCommandsAtom;
75 template <typename A> class EncryptionLoadCommandsAtom;
76 template <typename A> class SymbolTableLoadCommandsAtom;
77 template <typename A> class DyldInfoLoadCommandsAtom;
78 template <typename A> class ThreadsLoadCommandsAtom;
79 template <typename A> class DylibIDLoadCommandsAtom;
80 template <typename A> class RoutinesLoadCommandsAtom;
81 template <typename A> class DyldLoadCommandsAtom;
82 template <typename A> class UUIDLoadCommandAtom;
83 template <typename A> class LinkEditAtom;
84 template <typename A> class SectionRelocationsLinkEditAtom;
85 template <typename A> class CompressedRebaseInfoLinkEditAtom;
86 template <typename A> class CompressedBindingInfoLinkEditAtom;
87 template <typename A> class CompressedWeakBindingInfoLinkEditAtom;
88 template <typename A> class CompressedLazyBindingInfoLinkEditAtom;
89 template <typename A> class CompressedExportInfoLinkEditAtom;
90 template <typename A> class LocalRelocationsLinkEditAtom;
91 template <typename A> class ExternalRelocationsLinkEditAtom;
92 template <typename A> class SymbolTableLinkEditAtom;
93 template <typename A> class SegmentSplitInfoLoadCommandsAtom;
94 template <typename A> class SegmentSplitInfoContentAtom;
95 template <typename A> class IndirectTableLinkEditAtom;
96 template <typename A> class ModuleInfoLinkEditAtom;
97 template <typename A> class StringsLinkEditAtom;
98 template <typename A> class LoadCommandsPaddingAtom;
99 template <typename A> class UnwindInfoAtom;
100 template <typename A> class StubAtom;
101 template <typename A> class StubHelperAtom;
102 template <typename A> class ClassicStubHelperAtom;
103 template <typename A> class HybridStubHelperAtom;
104 template <typename A> class HybridStubHelperHelperAtom;
105 template <typename A> class FastStubHelperAtom;
106 template <typename A> class FastStubHelperHelperAtom;
107 template <typename A> class LazyPointerAtom;
108 template <typename A> class NonLazyPointerAtom;
109 template <typename A> class DylibLoadCommandsAtom;
110 template <typename A> class BranchIslandAtom;
111
112
113 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
114 class SectionInfo : public ObjectFile::Section {
115 public:
116 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0),
117 fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false),
118 fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false),
119 fAllSelfModifyingStubs(false), fAllStubHelpers(false),
120 fAllZeroFill(false), fVirtualSection(false),
121 fHasTextLocalRelocs(false), fHasTextExternalRelocs(false)
122 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
123 void setIndex(unsigned int index) { fIndex=index; }
124 std::vector<ObjectFile::Atom*> fAtoms;
125 char fSegmentName[20];
126 char fSectionName[20];
127 uint64_t fFileOffset;
128 uint64_t fSize;
129 uint32_t fRelocCount;
130 uint32_t fRelocOffset;
131 uint32_t fIndirectSymbolOffset;
132 uint8_t fAlignment;
133 bool fAllLazyPointers;
134 bool fAllLazyDylibPointers;
135 bool fAllNonLazyPointers;
136 bool fAllStubs;
137 bool fAllSelfModifyingStubs;
138 bool fAllStubHelpers;
139 bool fAllZeroFill;
140 bool fVirtualSection;
141 bool fHasTextLocalRelocs;
142 bool fHasTextExternalRelocs;
143 };
144
145 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
146 class SegmentInfo
147 {
148 public:
149 SegmentInfo(uint64_t pageSize) : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
150 fBaseAddress(0), fSize(0), fPageSize(pageSize), fFixedAddress(false),
151 fIndependentAddress(false), fHasLoadCommand(true) { fName[0] = '\0'; }
152 std::vector<class SectionInfo*> fSections;
153 char fName[20];
154 uint32_t fInitProtection;
155 uint32_t fMaxProtection;
156 uint64_t fFileOffset;
157 uint64_t fFileSize;
158 uint64_t fBaseAddress;
159 uint64_t fSize;
160 uint64_t fPageSize;
161 bool fFixedAddress;
162 bool fIndependentAddress;
163 bool fHasLoadCommand;
164 };
165
166
167 struct RebaseInfo {
168 RebaseInfo(uint8_t t, uint64_t addr) : fType(t), fAddress(addr) {}
169 uint8_t fType;
170 uint64_t fAddress;
171 // for sorting
172 int operator<(const RebaseInfo& rhs) const {
173 // sort by type, then address
174 if ( this->fType != rhs.fType )
175 return (this->fType < rhs.fType );
176 return (this->fAddress < rhs.fAddress );
177 }
178 };
179
180 struct BindingInfo {
181 BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t addend)
182 : fType(t), fFlags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), fLibraryOrdinal(ord),
183 fSymbolName(sym), fAddress(addr), fAddend(addend) {}
184 BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t addend)
185 : fType(t), fFlags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ), fLibraryOrdinal(0),
186 fSymbolName(sym), fAddress(addr), fAddend(addend) {}
187 uint8_t fType;
188 uint8_t fFlags;
189 int fLibraryOrdinal;
190 const char* fSymbolName;
191 uint64_t fAddress;
192 int64_t fAddend;
193
194 // for sorting
195 int operator<(const BindingInfo& rhs) const {
196 // sort by library, symbol, type, then address
197 if ( this->fLibraryOrdinal != rhs.fLibraryOrdinal )
198 return (this->fLibraryOrdinal < rhs.fLibraryOrdinal );
199 if ( this->fSymbolName != rhs.fSymbolName )
200 return ( strcmp(this->fSymbolName, rhs.fSymbolName) < 0 );
201 if ( this->fType != rhs.fType )
202 return (this->fType < rhs.fType );
203 return (this->fAddress < rhs.fAddress );
204 }
205 };
206
207
208 class ByteStream {
209 private:
210 std::vector<uint8_t> fData;
211 public:
212 std::vector<uint8_t>& bytes() { return fData; }
213 unsigned long size() const { return fData.size(); }
214 void reserve(unsigned long l) { fData.reserve(l); }
215 const uint8_t* start() const { return &fData[0]; }
216
217 void append_uleb128(uint64_t value) {
218 uint8_t byte;
219 do {
220 byte = value & 0x7F;
221 value &= ~0x7F;
222 if ( value != 0 )
223 byte |= 0x80;
224 fData.push_back(byte);
225 value = value >> 7;
226 } while( byte >= 0x80 );
227 }
228
229 void append_sleb128(int64_t value) {
230 bool isNeg = ( value < 0 );
231 uint8_t byte;
232 bool more;
233 do {
234 byte = value & 0x7F;
235 value = value >> 7;
236 if ( isNeg )
237 more = ( (value != -1) || ((byte & 0x40) == 0) );
238 else
239 more = ( (value != 0) || ((byte & 0x40) != 0) );
240 if ( more )
241 byte |= 0x80;
242 fData.push_back(byte);
243 }
244 while( more );
245 }
246
247 void append_string(const char* str) {
248 for (const char* s = str; *s != '\0'; ++s)
249 fData.push_back(*s);
250 fData.push_back('\0');
251 }
252
253 void append_byte(uint8_t byte) {
254 fData.push_back(byte);
255 }
256
257 static unsigned int uleb128_size(uint64_t value) {
258 uint32_t result = 0;
259 do {
260 value = value >> 7;
261 ++result;
262 } while ( value != 0 );
263 return result;
264 }
265
266 void pad_to_size(unsigned int alignment) {
267 while ( (fData.size() % alignment) != 0 )
268 fData.push_back(0);
269 }
270 };
271
272
273 template <typename A>
274 class Writer : public ExecutableFile::Writer
275 {
276 public:
277 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
278 virtual ~Writer();
279
280 virtual const char* getPath() { return fFilePath; }
281 virtual time_t getModificationTime() { return 0; }
282 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
283 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
284 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
285 virtual std::vector<Stab>* getStabs() { return NULL; }
286
287 virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint,
288 bool objcReplacementClasses);
289 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
290 virtual void addSynthesizedAtoms(const std::vector<class ObjectFile::Atom*>& existingAtoms,
291 class ObjectFile::Atom* dyldClassicHelperAtom,
292 class ObjectFile::Atom* dyldCompressedHelperAtom,
293 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
294 bool biggerThanTwoGigs,
295 uint32_t dylibSymbolCount,
296 std::vector<class ObjectFile::Atom*>& newAtoms);
297 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
298 std::vector<class ObjectFile::Reader::Stab>& stabs,
299 class ObjectFile::Atom* entryPointAtom,
300 bool createUUID, bool canScatter,
301 ObjectFile::Reader::CpuConstraint cpuConstraint,
302 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
303 bool hasExternalWeakDefinitions);
304
305 private:
306 typedef typename A::P P;
307 typedef typename A::P::uint_t pint_t;
308
309 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
310
311 void assignFileOffsets();
312 void synthesizeStubs(const std::vector<class ObjectFile::Atom*>& existingAtoms,
313 std::vector<class ObjectFile::Atom*>& newAtoms);
314 void synthesizeKextGOT(const std::vector<class ObjectFile::Atom*>& existingAtoms,
315 std::vector<class ObjectFile::Atom*>& newAtoms);
316 void createSplitSegContent();
317 void synthesizeUnwindInfoTable();
318 void insertDummyStubs();
319 void partitionIntoSections();
320 bool addBranchIslands();
321 bool createBranchIslands();
322 bool isBranchThatMightNeedIsland(uint8_t kind);
323 uint32_t textSizeWhenMightNeedBranchIslands();
324 uint32_t maxDistanceBetweenIslands();
325 void adjustLoadCommandsAndPadding();
326 void createDynamicLinkerCommand();
327 void createDylibCommands();
328 void buildLinkEdit();
329 const char* getArchString();
330 void writeMap();
331 uint64_t writeAtoms();
332 void writeNoOps(int fd, uint32_t from, uint32_t to);
333 void copyNoOps(uint8_t* from, uint8_t* to);
334 bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
335 void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
336 void collectExportedAndImportedAndLocalAtoms();
337 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
338 void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
339 void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
340 void buildSymbolTable();
341 bool stringsNeedLabelsInObjects();
342 const char* symbolTableName(const ObjectFile::Atom* atom);
343 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
344 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
345 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
346 void copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
347 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
348 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
349 bool targetRequiresWeakBinding(const ObjectFile::Atom& target);
350 int compressedOrdinalForImortedAtom(ObjectFile::Atom* target);
351 bool shouldExport(const ObjectFile::Atom& atom) const;
352 void buildFixups();
353 void adjustLinkEditSections();
354 void buildObjectFileFixups();
355 void buildExecutableFixups();
356 bool preboundLazyPointerType(uint8_t* type);
357 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
358 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
359 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
360 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
361 uint8_t buffer[], bool finalLinkedImage) const;
362 uint32_t symbolIndex(ObjectFile::Atom& atom);
363 bool makesExternalRelocatableReference(ObjectFile::Atom& target) const;
364 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
365 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
366 uint8_t getRelocPointerSize();
367 uint64_t maxAddress();
368 bool stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref);
369 bool GOTReferenceKind(uint8_t kind);
370 bool optimizableGOTReferenceKind(uint8_t kind);
371 bool weakImportReferenceKind(uint8_t kind);
372 unsigned int collectStabs();
373 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
374 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
375 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
376 void addStabs(uint32_t startIndex);
377 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
378 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
379 bool generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
380 bool generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
381 bool mightNeedPadSegment();
382 void scanForAbsoluteReferences();
383 bool needsModuleTable();
384 void optimizeDylibReferences();
385 bool indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const;
386
387 struct DirectLibrary {
388 class ObjectFile::Reader* fLibrary;
389 bool fWeak;
390 bool fReExport;
391 };
392
393 friend class WriterAtom<A>;
394 friend class PageZeroAtom<A>;
395 friend class CustomStackAtom<A>;
396 friend class MachHeaderAtom<A>;
397 friend class SegmentLoadCommandsAtom<A>;
398 friend class EncryptionLoadCommandsAtom<A>;
399 friend class SymbolTableLoadCommandsAtom<A>;
400 friend class DyldInfoLoadCommandsAtom<A>;
401 friend class ThreadsLoadCommandsAtom<A>;
402 friend class DylibIDLoadCommandsAtom<A>;
403 friend class RoutinesLoadCommandsAtom<A>;
404 friend class DyldLoadCommandsAtom<A>;
405 friend class UUIDLoadCommandAtom<A>;
406 friend class LinkEditAtom<A>;
407 friend class SectionRelocationsLinkEditAtom<A>;
408 friend class CompressedRebaseInfoLinkEditAtom<A>;
409 friend class CompressedBindingInfoLinkEditAtom<A>;
410 friend class CompressedWeakBindingInfoLinkEditAtom<A>;
411 friend class CompressedLazyBindingInfoLinkEditAtom<A>;
412 friend class CompressedExportInfoLinkEditAtom<A>;
413 friend class LocalRelocationsLinkEditAtom<A>;
414 friend class ExternalRelocationsLinkEditAtom<A>;
415 friend class SymbolTableLinkEditAtom<A>;
416 friend class SegmentSplitInfoLoadCommandsAtom<A>;
417 friend class SegmentSplitInfoContentAtom<A>;
418 friend class IndirectTableLinkEditAtom<A>;
419 friend class ModuleInfoLinkEditAtom<A>;
420 friend class StringsLinkEditAtom<A>;
421 friend class LoadCommandsPaddingAtom<A>;
422 friend class UnwindInfoAtom<A>;
423 friend class StubAtom<A>;
424 friend class StubHelperAtom<A>;
425 friend class ClassicStubHelperAtom<A>;
426 friend class HybridStubHelperAtom<A>;
427 friend class FastStubHelperAtom<A>;
428 friend class FastStubHelperHelperAtom<A>;
429 friend class HybridStubHelperHelperAtom<A>;
430 friend class LazyPointerAtom<A>;
431 friend class NonLazyPointerAtom<A>;
432 friend class DylibLoadCommandsAtom<A>;
433 friend class BranchIslandAtom<A>;
434
435 const char* fFilePath;
436 Options& fOptions;
437 std::vector<class ObjectFile::Atom*>* fAllAtoms;
438 std::vector<class ObjectFile::Reader::Stab>* fStabs;
439 std::set<const class ObjectFile::Atom*>* fRegularDefAtomsThatOverrideADylibsWeakDef;
440 class SectionInfo* fLoadCommandsSection;
441 class SegmentInfo* fLoadCommandsSegment;
442 class MachHeaderAtom<A>* fMachHeaderAtom;
443 class EncryptionLoadCommandsAtom<A>* fEncryptionLoadCommand;
444 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
445 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
446 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
447 class UnwindInfoAtom<A>* fUnwindInfoAtom;
448 class UUIDLoadCommandAtom<A>* fUUIDAtom;
449 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
450 std::vector<SegmentInfo*> fSegmentInfos;
451 class SegmentInfo* fPadSegmentInfo;
452 class ObjectFile::Atom* fEntryPoint;
453 class ObjectFile::Atom* fDyldClassicHelperAtom;
454 class ObjectFile::Atom* fDyldCompressedHelperAtom;
455 class ObjectFile::Atom* fDyldLazyDylibHelper;
456 std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*> fLibraryToLoadCommand;
457 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
458 std::map<class ObjectFile::Reader*, class ObjectFile::Reader*> fLibraryAliases;
459 std::set<class ObjectFile::Reader*> fForcedWeakImportReaders;
460 std::vector<class ObjectFile::Atom*> fExportedAtoms;
461 std::vector<class ObjectFile::Atom*> fImportedAtoms;
462 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
463 std::vector<macho_nlist<P> > fLocalExtraLabels;
464 std::vector<macho_nlist<P> > fGlobalExtraLabels;
465 std::map<ObjectFile::Atom*, uint32_t> fAtomToSymbolIndex;
466 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
467 class CompressedRebaseInfoLinkEditAtom<A>* fCompressedRebaseInfoAtom;
468 class CompressedBindingInfoLinkEditAtom<A>* fCompressedBindingInfoAtom;
469 class CompressedWeakBindingInfoLinkEditAtom<A>* fCompressedWeakBindingInfoAtom;
470 class CompressedLazyBindingInfoLinkEditAtom<A>* fCompressedLazyBindingInfoAtom;
471 class CompressedExportInfoLinkEditAtom<A>* fCompressedExportInfoAtom;
472 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
473 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
474 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
475 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
476 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
477 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
478 class StringsLinkEditAtom<A>* fStringsAtom;
479 class PageZeroAtom<A>* fPageZeroAtom;
480 class NonLazyPointerAtom<A>* fFastStubGOTAtom;
481 macho_nlist<P>* fSymbolTable;
482 std::vector<macho_relocation_info<P> > fSectionRelocs;
483 std::vector<macho_relocation_info<P> > fInternalRelocs;
484 std::vector<macho_relocation_info<P> > fExternalRelocs;
485 std::vector<RebaseInfo> fRebaseInfo;
486 std::vector<BindingInfo> fBindingInfo;
487 std::vector<BindingInfo> fWeakBindingInfo;
488 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
489 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
490 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
491 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
492 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
493 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyDylibPointers;
494 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
495 uint32_t fSymbolTableCount;
496 uint32_t fSymbolTableStabsCount;
497 uint32_t fSymbolTableStabsStartIndex;
498 uint32_t fSymbolTableLocalCount;
499 uint32_t fSymbolTableLocalStartIndex;
500 uint32_t fSymbolTableExportCount;
501 uint32_t fSymbolTableExportStartIndex;
502 uint32_t fSymbolTableImportCount;
503 uint32_t fSymbolTableImportStartIndex;
504 uint32_t fLargestAtomSize;
505 uint32_t fDylibSymbolCountUpperBound;
506 bool fEmitVirtualSections;
507 bool fHasWeakExports;
508 bool fReferencesWeakImports;
509 bool fCanScatter;
510 bool fWritableSegmentPastFirst4GB;
511 bool fNoReExportedDylibs;
512 bool fBiggerThanTwoGigs;
513 bool fSlideable;
514 bool fHasThumbBranches;
515 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
516 std::set<const ObjectFile::Reader*> fDylibReadersWithNonWeakImports;
517 std::set<const ObjectFile::Reader*> fDylibReadersWithWeakImports;
518 SegmentInfo* fFirstWritableSegment;
519 ObjectFile::Reader::CpuConstraint fCpuConstraint;
520 uint32_t fAnonNameIndex;
521 };
522
523
524 class Segment : public ObjectFile::Segment
525 {
526 public:
527 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
528 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
529 virtual const char* getName() const { return fName; }
530 virtual bool isContentReadable() const { return fReadable; }
531 virtual bool isContentWritable() const { return fWritable; }
532 virtual bool isContentExecutable() const { return fExecutable; }
533 virtual bool hasFixedAddress() const { return fFixedAddress; }
534
535 static Segment fgTextSegment;
536 static Segment fgPageZeroSegment;
537 static Segment fgLinkEditSegment;
538 static Segment fgStackSegment;
539 static Segment fgImportSegment;
540 static Segment fgROImportSegment;
541 static Segment fgDataSegment;
542 static Segment fgObjCSegment;
543 static Segment fgHeaderSegment;
544
545
546 private:
547 const char* fName;
548 const bool fReadable;
549 const bool fWritable;
550 const bool fExecutable;
551 const bool fFixedAddress;
552 };
553
554 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
555 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
556 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
557 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
558 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
559 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
560 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
561 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
562 Segment Segment::fgHeaderSegment("__HEADER", true, false, true, false);
563
564
565 template <typename A>
566 class WriterAtom : public ObjectFile::Atom
567 {
568 public:
569 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
570 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
571
572 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
573 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
574 virtual const char* getName() const { return NULL; }
575 virtual const char* getDisplayName() const { return this->getName(); }
576 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
577 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
578 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
579 virtual bool dontDeadStrip() const { return true; }
580 virtual bool isZeroFill() const { return false; }
581 virtual bool isThumb() const { return false; }
582 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
583 virtual bool mustRemainInSection() const { return true; }
584 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
585 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
586 virtual uint32_t getOrdinal() const { return 0; }
587 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
588 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
589 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
590 virtual void setScope(Scope) { }
591
592
593 protected:
594 virtual ~WriterAtom() {}
595 typedef typename A::P P;
596 typedef typename A::P::E E;
597
598 static Segment& headerSegment(Writer<A>& writer) { return (writer.fOptions.outputKind()==Options::kPreload)
599 ? Segment::fgHeaderSegment : Segment::fgTextSegment; }
600
601 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
602
603 Writer<A>& fWriter;
604 Segment& fSegment;
605 };
606
607 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
608
609
610 template <typename A>
611 class PageZeroAtom : public WriterAtom<A>
612 {
613 public:
614 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
615 fSize(fWriter.fOptions.zeroPageSize()) {}
616 virtual const char* getDisplayName() const { return "page zero content"; }
617 virtual bool isZeroFill() const { return true; }
618 virtual uint64_t getSize() const { return fSize; }
619 virtual const char* getSectionName() const { return "._zeropage"; }
620 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
621 void setSize(uint64_t size) { fSize = size; }
622 private:
623 using WriterAtom<A>::fWriter;
624 typedef typename A::P P;
625 uint64_t fSize;
626 };
627
628
629 template <typename A>
630 class DsoHandleAtom : public WriterAtom<A>
631 {
632 public:
633 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
634 virtual const char* getName() const { return "___dso_handle"; }
635 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
636 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
637 virtual uint64_t getSize() const { return 0; }
638 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
639 virtual const char* getSectionName() const { return "._mach_header"; }
640 virtual void copyRawContent(uint8_t buffer[]) const {}
641 };
642
643
644 template <typename A>
645 class MachHeaderAtom : public WriterAtom<A>
646 {
647 public:
648 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)) {}
649 virtual const char* getName() const;
650 virtual const char* getDisplayName() const;
651 virtual ObjectFile::Atom::Scope getScope() const;
652 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
653 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
654 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
655 virtual const char* getSectionName() const { return "._mach_header"; }
656 virtual uint32_t getOrdinal() const { return 1; }
657 virtual void copyRawContent(uint8_t buffer[]) const;
658 private:
659 using WriterAtom<A>::fWriter;
660 typedef typename A::P P;
661 void setHeaderInfo(macho_header<typename A::P>& header) const;
662 };
663
664 template <typename A>
665 class CustomStackAtom : public WriterAtom<A>
666 {
667 public:
668 CustomStackAtom(Writer<A>& writer);
669 virtual const char* getDisplayName() const { return "custom stack content"; }
670 virtual bool isZeroFill() const { return true; }
671 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
672 virtual const char* getSectionName() const { return "._stack"; }
673 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
674 private:
675 using WriterAtom<A>::fWriter;
676 typedef typename A::P P;
677 static bool stackGrowsDown();
678 };
679
680 template <typename A>
681 class LoadCommandAtom : public WriterAtom<A>
682 {
683 protected:
684 LoadCommandAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)), fOrdinal(fgCurrentOrdinal++) {}
685 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
686 virtual const char* getSectionName() const { return "._load_commands"; }
687 virtual uint32_t getOrdinal() const { return fOrdinal; }
688 static uint64_t alignedSize(uint64_t size);
689 protected:
690 uint32_t fOrdinal;
691 static uint32_t fgCurrentOrdinal;
692 };
693
694 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
695
696 template <typename A>
697 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
698 {
699 public:
700 SegmentLoadCommandsAtom(Writer<A>& writer)
701 : LoadCommandAtom<A>(writer), fCommandCount(0), fSize(0)
702 { writer.fSegmentCommands = this; }
703 virtual const char* getDisplayName() const { return "segment load commands"; }
704 virtual uint64_t getSize() const { return fSize; }
705 virtual void copyRawContent(uint8_t buffer[]) const;
706
707 void computeSize();
708 void setup();
709 unsigned int commandCount() { return fCommandCount; }
710 private:
711 using WriterAtom<A>::fWriter;
712 typedef typename A::P P;
713 unsigned int fCommandCount;
714 uint32_t fSize;
715 };
716
717
718 template <typename A>
719 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
720 {
721 public:
722 SymbolTableLoadCommandsAtom(Writer<A>&);
723 virtual const char* getDisplayName() const { return "symbol table load commands"; }
724 virtual uint64_t getSize() const;
725 virtual void copyRawContent(uint8_t buffer[]) const;
726 unsigned int commandCount();
727 void needDynamicTable();
728 private:
729 using WriterAtom<A>::fWriter;
730 typedef typename A::P P;
731 bool fNeedsDynamicSymbolTable;
732 macho_symtab_command<typename A::P> fSymbolTable;
733 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
734 };
735
736 template <typename A>
737 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
738 {
739 public:
740 ThreadsLoadCommandsAtom(Writer<A>& writer)
741 : LoadCommandAtom<A>(writer) {}
742 virtual const char* getDisplayName() const { return "thread load commands"; }
743 virtual uint64_t getSize() const;
744 virtual void copyRawContent(uint8_t buffer[]) const;
745 private:
746 using WriterAtom<A>::fWriter;
747 typedef typename A::P P;
748 uint8_t* fBuffer;
749 uint32_t fBufferSize;
750 };
751
752 template <typename A>
753 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
754 {
755 public:
756 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
757 virtual const char* getDisplayName() const { return "dyld load command"; }
758 virtual uint64_t getSize() const;
759 virtual void copyRawContent(uint8_t buffer[]) const;
760 private:
761 using WriterAtom<A>::fWriter;
762 typedef typename A::P P;
763 };
764
765 template <typename A>
766 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
767 {
768 public:
769 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
770 virtual const char* getDisplayName() const { return "segment split info load command"; }
771 virtual uint64_t getSize() const;
772 virtual void copyRawContent(uint8_t buffer[]) const;
773 private:
774 using WriterAtom<A>::fWriter;
775 typedef typename A::P P;
776 };
777
778 template <typename A>
779 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
780 {
781 public:
782 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
783 LoadCommandAtom<A>(writer), clientString(client) {}
784 virtual const char* getDisplayName() const { return "allowable_client load command"; }
785 virtual uint64_t getSize() const;
786 virtual void copyRawContent(uint8_t buffer[]) const;
787 private:
788 using WriterAtom<A>::fWriter;
789 typedef typename A::P P;
790 const char* clientString;
791 };
792
793 template <typename A>
794 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
795 {
796 public:
797 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
798 : LoadCommandAtom<A>(writer), fInfo(info),
799 fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
800 virtual const char* getDisplayName() const { return "dylib load command"; }
801 virtual uint64_t getSize() const;
802 virtual void copyRawContent(uint8_t buffer[]) const;
803 virtual void optimizeAway() { fOptimizedAway = true; }
804 bool linkedWeak() { return fInfo.options.fWeakImport; }
805 private:
806 using WriterAtom<A>::fWriter;
807 typedef typename A::P P;
808 ExecutableFile::DyLibUsed fInfo;
809 bool fOptimizedAway;
810 };
811
812 template <typename A>
813 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
814 {
815 public:
816 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
817 virtual const char* getDisplayName() const { return "dylib ID load command"; }
818 virtual uint64_t getSize() const;
819 virtual void copyRawContent(uint8_t buffer[]) const;
820 private:
821 using WriterAtom<A>::fWriter;
822 typedef typename A::P P;
823 };
824
825 template <typename A>
826 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
827 {
828 public:
829 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
830 virtual const char* getDisplayName() const { return "routines load command"; }
831 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
832 virtual void copyRawContent(uint8_t buffer[]) const;
833 private:
834 using WriterAtom<A>::fWriter;
835 typedef typename A::P P;
836 };
837
838 template <typename A>
839 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
840 {
841 public:
842 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
843 : LoadCommandAtom<A>(writer), fName(name) {}
844 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
845 virtual uint64_t getSize() const;
846 virtual void copyRawContent(uint8_t buffer[]) const;
847 private:
848 typedef typename A::P P;
849 const char* fName;
850 };
851
852 template <typename A>
853 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
854 {
855 public:
856 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
857 : LoadCommandAtom<A>(writer), fNameStart(nameStart), fNameLength(nameLen) {}
858 virtual const char* getDisplayName() const { return "sub-library load command"; }
859 virtual uint64_t getSize() const;
860 virtual void copyRawContent(uint8_t buffer[]) const;
861 private:
862 using WriterAtom<A>::fWriter;
863 typedef typename A::P P;
864 const char* fNameStart;
865 int fNameLength;
866 };
867
868 template <typename A>
869 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
870 {
871 public:
872 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
873 : LoadCommandAtom<A>(writer), fName(name) {}
874 virtual const char* getDisplayName() const { return "umbrella load command"; }
875 virtual uint64_t getSize() const;
876 virtual void copyRawContent(uint8_t buffer[]) const;
877 private:
878 using WriterAtom<A>::fWriter;
879 typedef typename A::P P;
880 const char* fName;
881 };
882
883 template <typename A>
884 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
885 {
886 public:
887 UUIDLoadCommandAtom(Writer<A>& writer)
888 : LoadCommandAtom<A>(writer), fEmit(false) {}
889 virtual const char* getDisplayName() const { return "uuid load command"; }
890 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
891 virtual void copyRawContent(uint8_t buffer[]) const;
892 virtual void generate();
893 void setContent(const uint8_t uuid[16]);
894 const uint8_t* getUUID() { return fUUID; }
895 private:
896 using WriterAtom<A>::fWriter;
897 typedef typename A::P P;
898 uuid_t fUUID;
899 bool fEmit;
900 };
901
902
903 template <typename A>
904 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
905 {
906 public:
907 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
908 : LoadCommandAtom<A>(writer), fPath(path) {}
909 virtual const char* getDisplayName() const { return "rpath load command"; }
910 virtual uint64_t getSize() const;
911 virtual void copyRawContent(uint8_t buffer[]) const;
912 private:
913 using WriterAtom<A>::fWriter;
914 typedef typename A::P P;
915 const char* fPath;
916 };
917
918 template <typename A>
919 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
920 {
921 public:
922 EncryptionLoadCommandsAtom(Writer<A>& writer)
923 : LoadCommandAtom<A>(writer), fStartOffset(0),
924 fEndOffset(0) {}
925 virtual const char* getDisplayName() const { return "encryption info load command"; }
926 virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
927 virtual void copyRawContent(uint8_t buffer[]) const;
928 void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
929 void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
930 private:
931 using WriterAtom<A>::fWriter;
932 typedef typename A::P P;
933 uint32_t fStartOffset;
934 uint32_t fEndOffset;
935 };
936
937 template <typename A>
938 class DyldInfoLoadCommandsAtom : public LoadCommandAtom<A>
939 {
940 public:
941 DyldInfoLoadCommandsAtom(Writer<A>& writer)
942 : LoadCommandAtom<A>(writer) {}
943 virtual const char* getDisplayName() const { return "dyld info load command"; }
944 virtual uint64_t getSize() const { return sizeof(macho_dyld_info_command<typename A::P>); }
945 virtual void copyRawContent(uint8_t buffer[]) const;
946 private:
947 using WriterAtom<A>::fWriter;
948 typedef typename A::P P;
949 };
950
951
952 template <typename A>
953 class LoadCommandsPaddingAtom : public WriterAtom<A>
954 {
955 public:
956 LoadCommandsPaddingAtom(Writer<A>& writer)
957 : WriterAtom<A>(writer, headerSegment(writer)), fSize(0) {}
958 virtual const char* getDisplayName() const { return "header padding"; }
959 virtual uint64_t getSize() const { return fSize; }
960 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
961 virtual void copyRawContent(uint8_t buffer[]) const;
962
963 void setSize(uint64_t newSize);
964 private:
965 using WriterAtom<A>::fWriter;
966 typedef typename A::P P;
967 uint64_t fSize;
968 };
969
970 template <typename A>
971 class UnwindInfoAtom : public WriterAtom<A>
972 {
973 public:
974 UnwindInfoAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment),
975 fHeaderSize(0), fPagesSize(0), fAlignment(4) {}
976 virtual const char* getName() const { return "unwind info"; }
977 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
978 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
979 virtual uint64_t getSize() const { return fHeaderSize+fPagesSize; }
980 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
981 virtual const char* getSectionName() const { return "__unwind_info"; }
982 virtual uint32_t getOrdinal() const { return 1; }
983 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)fReferences; }
984 virtual void copyRawContent(uint8_t buffer[]) const;
985
986 void addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
987 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsda,
988 ObjectFile::Atom* personalityPointer);
989 void generate();
990
991 private:
992 using WriterAtom<A>::fWriter;
993 typedef typename A::P P;
994 struct Info { ObjectFile::Atom* func; ObjectFile::Atom* fde; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; };
995 struct LSDAEntry { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; };
996 struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fde; };
997 struct CompressedFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fromFunc; };
998 struct CompressedEncodingFixUp { uint8_t* contentPointer; ObjectFile::Atom* fde; };
999
1000 bool encodingMeansUseDwarf(compact_unwind_encoding_t encoding);
1001 void compressDuplicates(std::vector<Info>& uniqueInfos);
1002 void findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings);
1003 void makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap);
1004 unsigned int makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize, unsigned int endIndex,
1005 uint8_t*& pageEnd);
1006 unsigned int makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
1007 const std::map<uint32_t,unsigned int> commonEncodings,
1008 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
1009 void makePersonalityIndex(std::vector<Info>& uniqueInfos);
1010
1011
1012 uint32_t fHeaderSize;
1013 uint32_t fPagesSize;
1014 uint8_t* fHeaderContent;
1015 uint8_t* fPagesContent;
1016 uint8_t* fPagesContentForDelete;
1017 ObjectFile::Alignment fAlignment;
1018 std::vector<Info> fInfos;
1019 std::map<ObjectFile::Atom*, uint32_t> fPersonalityIndexMap;
1020 std::vector<LSDAEntry> fLSDAIndex;
1021 std::vector<RegFixUp> fRegFixUps;
1022 std::vector<CompressedFixUp> fCompressedFixUps;
1023 std::vector<CompressedEncodingFixUp> fCompressedEncodingFixUps;
1024 std::vector<ObjectFile::Reference*> fReferences;
1025 };
1026
1027
1028
1029 template <typename A>
1030 class LinkEditAtom : public WriterAtom<A>
1031 {
1032 public:
1033 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
1034 uint64_t getFileOffset() const;
1035 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
1036 virtual uint32_t getOrdinal() const { return fOrdinal; }
1037 private:
1038 uint32_t fOrdinal;
1039 static uint32_t fgCurrentOrdinal;
1040 private:
1041 typedef typename A::P P;
1042 };
1043
1044 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
1045
1046 template <typename A>
1047 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
1048 {
1049 public:
1050 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1051 virtual const char* getDisplayName() const { return "section relocations"; }
1052 virtual uint64_t getSize() const;
1053 virtual const char* getSectionName() const { return "._section_relocs"; }
1054 virtual void copyRawContent(uint8_t buffer[]) const;
1055 private:
1056 using WriterAtom<A>::fWriter;
1057 typedef typename A::P P;
1058 };
1059
1060 template <typename A>
1061 class CompressedInfoLinkEditAtom : public LinkEditAtom<A>
1062 {
1063 public:
1064 CompressedInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1065 virtual uint64_t getSize() const { return fEncodedData.size(); }
1066 virtual void copyRawContent(uint8_t buffer[]) const { memcpy(buffer, fEncodedData.start(), fEncodedData.size()); }
1067 protected:
1068 typedef typename A::P::uint_t pint_t;
1069 ByteStream fEncodedData;
1070 private:
1071 using WriterAtom<A>::fWriter;
1072 typedef typename A::P P;
1073 };
1074
1075
1076
1077 template <typename A>
1078 class CompressedRebaseInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1079 {
1080 public:
1081 CompressedRebaseInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1082 virtual const char* getDisplayName() const { return "compressed rebase info"; }
1083 virtual const char* getSectionName() const { return "._rebase info"; }
1084 void encode();
1085 private:
1086 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1087 using CompressedInfoLinkEditAtom<A>::fWriter;
1088 typedef typename A::P P;
1089 typedef typename A::P::uint_t pint_t;
1090 };
1091
1092 template <typename A>
1093 class CompressedBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1094 {
1095 public:
1096 CompressedBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1097 virtual const char* getDisplayName() const { return "compressed binding info"; }
1098 virtual const char* getSectionName() const { return "._binding info"; }
1099 void encode();
1100 private:
1101 using CompressedInfoLinkEditAtom<A>::fWriter;
1102 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1103 typedef typename A::P P;
1104 typedef typename A::P::uint_t pint_t;
1105 };
1106
1107 template <typename A>
1108 class CompressedWeakBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1109 {
1110 public:
1111 CompressedWeakBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1112 virtual const char* getDisplayName() const { return "compressed weak binding info"; }
1113 virtual const char* getSectionName() const { return "._wkbinding info"; }
1114 void encode();
1115 private:
1116 using CompressedInfoLinkEditAtom<A>::fWriter;
1117 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1118 typedef typename A::P P;
1119 typedef typename A::P::uint_t pint_t;
1120 };
1121
1122 template <typename A>
1123 class CompressedLazyBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1124 {
1125 public:
1126 CompressedLazyBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1127 virtual const char* getDisplayName() const { return "compressed lazy binding info"; }
1128 virtual const char* getSectionName() const { return "._lzbinding info"; }
1129 void encode();
1130 private:
1131 std::vector<uint32_t> fStarts;
1132
1133 using CompressedInfoLinkEditAtom<A>::fWriter;
1134 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1135 typedef typename A::P P;
1136 typedef typename A::P::uint_t pint_t;
1137 };
1138
1139
1140 template <typename A>
1141 class CompressedExportInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1142 {
1143 public:
1144 CompressedExportInfoLinkEditAtom(Writer<A>& writer)
1145 : CompressedInfoLinkEditAtom<A>(writer), fStartNode(strdup("")) { }
1146 virtual const char* getDisplayName() const { return "compressed export info"; }
1147 virtual const char* getSectionName() const { return "._export info"; }
1148 void encode();
1149 private:
1150 using WriterAtom<A>::fWriter;
1151 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1152 typedef typename A::P P;
1153 typedef typename A::P::uint_t pint_t;
1154 struct node;
1155
1156 struct edge
1157 {
1158 edge(const char* s, struct node* n) : fSubString(s), fChild(n) { }
1159 ~edge() { }
1160 const char* fSubString;
1161 struct node* fChild;
1162
1163 };
1164
1165 struct node
1166 {
1167 node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false),
1168 fHaveExportInfo(false), fTrieOffset(0) {}
1169 ~node() { }
1170 const char* fCummulativeString;
1171 std::vector<edge> fChildren;
1172 uint64_t fAddress;
1173 uint32_t fFlags;
1174 bool fOrdered;
1175 bool fHaveExportInfo;
1176 uint32_t fTrieOffset;
1177
1178 void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
1179 const char* partialStr = &fullStr[strlen(fCummulativeString)];
1180 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1181 edge& e = *it;
1182 int subStringLen = strlen(e.fSubString);
1183 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1184 // already have matching edge, go down that path
1185 e.fChild->addSymbol(fullStr, address, flags);
1186 return;
1187 }
1188 else {
1189 for (int i=subStringLen-1; i > 0; --i) {
1190 if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
1191 // found a common substring, splice in new node
1192 // was A -> C, now A -> B -> C
1193 char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
1194 bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
1195 //node* aNode = this;
1196 node* bNode = new node(bNodeCummStr);
1197 node* cNode = e.fChild;
1198 char* abEdgeStr = strdup(e.fSubString);
1199 abEdgeStr[i] = '\0';
1200 char* bcEdgeStr = strdup(&e.fSubString[i]);
1201 edge& abEdge = e;
1202 abEdge.fSubString = abEdgeStr;
1203 abEdge.fChild = bNode;
1204 edge bcEdge(bcEdgeStr, cNode);
1205 bNode->fChildren.push_back(bcEdge);
1206 bNode->addSymbol(fullStr, address, flags);
1207 return;
1208 }
1209 }
1210 }
1211 }
1212 // no commonality with any existing child, make a new edge that is this whole string
1213 node* newNode = new node(strdup(fullStr));
1214 edge newEdge(strdup(partialStr), newNode);
1215 fChildren.push_back(newEdge);
1216 newNode->fAddress = address;
1217 newNode->fFlags = flags;
1218 newNode->fHaveExportInfo = true;
1219 }
1220
1221 void addOrderedNodes(const char* name, std::vector<node*>& orderedNodes) {
1222 if ( !fOrdered ) {
1223 orderedNodes.push_back(this);
1224 //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
1225 fOrdered = true;
1226 }
1227 const char* partialStr = &name[strlen(fCummulativeString)];
1228 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1229 edge& e = *it;
1230 int subStringLen = strlen(e.fSubString);
1231 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1232 // already have matching edge, go down that path
1233 e.fChild->addOrderedNodes(name, orderedNodes);
1234 return;
1235 }
1236 }
1237 }
1238
1239 // byte for terminal node size in bytes, or 0x00 if not terminal node
1240 // teminal node (uleb128 flags, uleb128 addr)
1241 // byte for child node count
1242 // each child: zero terminated substring, uleb128 node offset
1243 bool updateOffset(uint32_t& offset) {
1244 uint32_t nodeSize = 1; // byte for length of export info
1245 if ( fHaveExportInfo )
1246 nodeSize += ByteStream::uleb128_size(fFlags) + ByteStream::uleb128_size(fAddress);
1247
1248 // add children
1249 ++nodeSize; // byte for count of chidren
1250 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1251 edge& e = *it;
1252 nodeSize += strlen(e.fSubString) + 1 + ByteStream::uleb128_size(e.fChild->fTrieOffset);
1253 }
1254 bool result = (fTrieOffset != offset);
1255 fTrieOffset = offset;
1256 //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
1257 offset += nodeSize;
1258 // return true if fTrieOffset was changed
1259 return result;
1260 }
1261
1262 void appendToStream(ByteStream& out) {
1263 if ( fHaveExportInfo ) {
1264 // nodes with export info: size, flags, address
1265 out.append_byte(out.uleb128_size(fFlags) + out.uleb128_size(fAddress));
1266 out.append_uleb128(fFlags);
1267 out.append_uleb128(fAddress);
1268 }
1269 else {
1270 // no export info
1271 out.append_byte(0);
1272 }
1273 // write number of children
1274 out.append_byte(fChildren.size());
1275 // write each child
1276 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1277 edge& e = *it;
1278 out.append_string(e.fSubString);
1279 out.append_uleb128(e.fChild->fTrieOffset);
1280 }
1281 }
1282
1283 };
1284
1285
1286 struct node fStartNode;
1287 };
1288
1289 template <typename A>
1290 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
1291 {
1292 public:
1293 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1294 virtual const char* getDisplayName() const { return "local relocations"; }
1295 virtual uint64_t getSize() const;
1296 virtual const char* getSectionName() const { return "._local_relocs"; }
1297 virtual void copyRawContent(uint8_t buffer[]) const;
1298 private:
1299 using WriterAtom<A>::fWriter;
1300 typedef typename A::P P;
1301 };
1302
1303 template <typename A>
1304 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
1305 {
1306 public:
1307 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1308 virtual const char* getDisplayName() const { return "symbol table"; }
1309 virtual uint64_t getSize() const;
1310 virtual const char* getSectionName() const { return "._symbol_table"; }
1311 virtual void copyRawContent(uint8_t buffer[]) const;
1312 private:
1313 using WriterAtom<A>::fWriter;
1314 typedef typename A::P P;
1315 };
1316
1317 template <typename A>
1318 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
1319 {
1320 public:
1321 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1322 virtual const char* getDisplayName() const { return "external relocations"; }
1323 virtual uint64_t getSize() const;
1324 virtual const char* getSectionName() const { return "._extern_relocs"; }
1325 virtual void copyRawContent(uint8_t buffer[]) const;
1326 private:
1327 using WriterAtom<A>::fWriter;
1328 typedef typename A::P P;
1329 };
1330
1331 struct IndirectEntry {
1332 uint32_t indirectIndex;
1333 uint32_t symbolIndex;
1334 };
1335
1336
1337 template <typename A>
1338 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
1339 {
1340 public:
1341 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
1342 virtual const char* getDisplayName() const { return "split segment info"; }
1343 virtual uint64_t getSize() const;
1344 virtual const char* getSectionName() const { return "._split_info"; }
1345 virtual void copyRawContent(uint8_t buffer[]) const;
1346 bool canEncode() { return !fCantEncode; }
1347 void setCantEncode() { fCantEncode = true; }
1348 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
1349 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
1350 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
1351 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
1352 void encode();
1353
1354 private:
1355 using WriterAtom<A>::fWriter;
1356 typedef typename A::P P;
1357 typedef typename A::P::uint_t pint_t;
1358 struct AtomAndOffset {
1359 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
1360 const ObjectFile::Atom* atom;
1361 uint32_t offset;
1362 };
1363 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
1364
1365 std::vector<AtomAndOffset> fKind1Locations;
1366 std::vector<AtomAndOffset> fKind2Locations;
1367 std::vector<AtomAndOffset> fKind3Locations;
1368 std::vector<AtomAndOffset> fKind4Locations;
1369 std::vector<uint8_t> fEncodedData;
1370 bool fCantEncode;
1371 };
1372
1373 template <typename A>
1374 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
1375 {
1376 public:
1377 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1378 virtual const char* getDisplayName() const { return "indirect symbol table"; }
1379 virtual uint64_t getSize() const;
1380 virtual const char* getSectionName() const { return "._indirect_syms"; }
1381 virtual void copyRawContent(uint8_t buffer[]) const;
1382
1383 std::vector<IndirectEntry> fTable;
1384
1385 private:
1386 using WriterAtom<A>::fWriter;
1387 typedef typename A::P P;
1388 };
1389
1390 template <typename A>
1391 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
1392 {
1393 public:
1394 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
1395 virtual const char* getDisplayName() const { return "module table"; }
1396 virtual uint64_t getSize() const;
1397 virtual const char* getSectionName() const { return "._module_info"; }
1398 virtual void copyRawContent(uint8_t buffer[]) const;
1399
1400 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
1401 uint32_t getTableOfContentsFileOffset() const;
1402 uint32_t getModuleTableFileOffset() const;
1403 uint32_t getReferencesFileOffset() const;
1404 uint32_t getReferencesCount() const;
1405
1406 private:
1407 using WriterAtom<A>::fWriter;
1408 typedef typename A::P P;
1409 typedef typename A::P::uint_t pint_t;
1410 uint32_t fModuleNameOffset;
1411 };
1412
1413
1414 class CStringEquals
1415 {
1416 public:
1417 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
1418 };
1419
1420 template <typename A>
1421 class StringsLinkEditAtom : public LinkEditAtom<A>
1422 {
1423 public:
1424 StringsLinkEditAtom(Writer<A>& writer);
1425 virtual const char* getDisplayName() const { return "string pool"; }
1426 virtual uint64_t getSize() const;
1427 virtual const char* getSectionName() const { return "._string_pool"; }
1428 virtual void copyRawContent(uint8_t buffer[]) const;
1429
1430 int32_t add(const char* name);
1431 int32_t addUnique(const char* name);
1432 int32_t emptyString() { return 1; }
1433 const char* stringForIndex(int32_t) const;
1434
1435 private:
1436 using WriterAtom<A>::fWriter;
1437 typedef typename A::P P;
1438 enum { kBufferSize = 0x01000000 };
1439 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
1440
1441 std::vector<char*> fFullBuffers;
1442 char* fCurrentBuffer;
1443 uint32_t fCurrentBufferUsed;
1444 StringToOffset fUniqueStrings;
1445 };
1446
1447
1448
1449 template <typename A>
1450 class UndefinedSymbolProxyAtom : public WriterAtom<A>
1451 {
1452 public:
1453 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
1454 virtual const char* getName() const { return fName; }
1455 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
1456 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
1457 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1458 virtual uint64_t getSize() const { return 0; }
1459 virtual const char* getSectionName() const { return "._imports"; }
1460 private:
1461 using WriterAtom<A>::fWriter;
1462 typedef typename A::P P;
1463 const char* fName;
1464 };
1465
1466 template <typename A>
1467 class BranchIslandAtom : public WriterAtom<A>
1468 {
1469 public:
1470 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target,
1471 ObjectFile::Atom& finalTarget, uint32_t finalTargetOffset);
1472 virtual const char* getName() const { return fName; }
1473 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1474 virtual uint64_t getSize() const;
1475 virtual bool isThumb() const { return (fIslandKind == kBranchIslandToThumb2); }
1476 virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kBranchIsland; }
1477 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1478 virtual const char* getSectionName() const { return "__text"; }
1479 virtual void copyRawContent(uint8_t buffer[]) const;
1480 uint64_t getFinalTargetAdress() const { return fFinalTarget.getAddress() + fFinalTargetOffset; }
1481 private:
1482 using WriterAtom<A>::fWriter;
1483 enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1 };
1484 const char* fName;
1485 ObjectFile::Atom& fTarget;
1486 ObjectFile::Atom& fFinalTarget;
1487 uint32_t fFinalTargetOffset;
1488 IslandKind fIslandKind;
1489 };
1490
1491 template <typename A>
1492 class StubAtom : public WriterAtom<A>
1493 {
1494 public:
1495 StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
1496 virtual const char* getName() const { return fName; }
1497 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1498 virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStub; }
1499 virtual uint64_t getSize() const;
1500 virtual ObjectFile::Alignment getAlignment() const;
1501 virtual const char* getSectionName() const { return "__symbol_stub1"; }
1502 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1503 virtual void copyRawContent(uint8_t buffer[]) const;
1504 ObjectFile::Atom* getTarget() { return &fTarget; }
1505 virtual uint32_t getOrdinal() const { return fSortingOrdinal; }
1506 void setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; }
1507 private:
1508 static const char* stubName(const char* importName);
1509 friend class LazyPointerAtom<A>;
1510 using WriterAtom<A>::fWriter;
1511 enum StubKind { kStubPIC, kStubNoPIC, kStubShort, kJumpTable };
1512 const char* fName;
1513 ObjectFile::Atom& fTarget;
1514 std::vector<ObjectFile::Reference*> fReferences;
1515 bool fForLazyDylib;
1516 StubKind fKind;
1517 uint32_t fSortingOrdinal;
1518 };
1519
1520
1521 template <typename A>
1522 class FastStubHelperHelperAtom : public WriterAtom<A>
1523 {
1524 public:
1525 FastStubHelperHelperAtom(Writer<A>& writer);
1526 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1527 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1528 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1529 virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStubHelper; }
1530 virtual uint64_t getSize() const;
1531 virtual const char* getSectionName() const { return "__stub_helper"; }
1532 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1533 virtual void copyRawContent(uint8_t buffer[]) const;
1534 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1535 virtual uint32_t getOrdinal() const { return 0; }
1536 protected:
1537 using WriterAtom<A>::fWriter;
1538 std::vector<ObjectFile::Reference*> fReferences;
1539 };
1540
1541 template <typename A>
1542 class HybridStubHelperHelperAtom : public WriterAtom<A>
1543 {
1544 public:
1545 HybridStubHelperHelperAtom(Writer<A>& writer);
1546 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1547 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1548 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1549 virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStubHelper; }
1550 virtual uint64_t getSize() const;
1551 virtual const char* getSectionName() const { return "__stub_helper"; }
1552 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1553 virtual void copyRawContent(uint8_t buffer[]) const;
1554 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1555 virtual uint32_t getOrdinal() const { return 0; }
1556 protected:
1557 using WriterAtom<A>::fWriter;
1558 std::vector<ObjectFile::Reference*> fReferences;
1559 };
1560
1561 template <typename A>
1562 class StubHelperAtom : public WriterAtom<A>
1563 {
1564 public:
1565 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1566 LazyPointerAtom<A>& lazyPointer, bool forLazyDylib)
1567 : WriterAtom<A>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1568 fTarget(target), fLazyPointerAtom(lazyPointer) {
1569 writer.fAllSynthesizedStubHelpers.push_back(this);
1570 }
1571
1572 virtual const char* getName() const { return fName; }
1573 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1574 virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kStubHelper; }
1575 virtual const char* getSectionName() const { return "__stub_helper"; }
1576 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1577 ObjectFile::Atom* getTarget() { return &fTarget; }
1578 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1579 virtual uint32_t getOrdinal() const { return 1; }
1580 protected:
1581 static const char* stubName(const char* importName);
1582 using WriterAtom<A>::fWriter;
1583 const char* fName;
1584 ObjectFile::Atom& fTarget;
1585 LazyPointerAtom<A>& fLazyPointerAtom;
1586 std::vector<ObjectFile::Reference*> fReferences;
1587 };
1588
1589 template <typename A>
1590 class ClassicStubHelperAtom : public StubHelperAtom<A>
1591 {
1592 public:
1593 ClassicStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1594 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1595
1596 virtual uint64_t getSize() const;
1597 virtual void copyRawContent(uint8_t buffer[]) const;
1598 };
1599
1600
1601 template <typename A>
1602 class HybridStubHelperAtom : public StubHelperAtom<A>
1603 {
1604 public:
1605 HybridStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1606 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1607
1608 virtual uint64_t getSize() const;
1609 virtual void copyRawContent(uint8_t buffer[]) const;
1610 static class HybridStubHelperHelperAtom<A>* fgHelperHelperAtom;
1611 };
1612 template <typename A> class HybridStubHelperHelperAtom<A>* HybridStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1613
1614 template <typename A>
1615 class FastStubHelperAtom : public StubHelperAtom<A>
1616 {
1617 public:
1618 FastStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1619 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1620 virtual uint64_t getSize() const;
1621 virtual void copyRawContent(uint8_t buffer[]) const;
1622 static FastStubHelperHelperAtom<A>* fgHelperHelperAtom;
1623 };
1624 template <typename A> FastStubHelperHelperAtom<A>* FastStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1625
1626
1627
1628 template <typename A>
1629 class LazyPointerAtom : public WriterAtom<A>
1630 {
1631 public:
1632 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target,
1633 StubAtom<A>& stub, bool forLazyDylib);
1634 virtual const char* getName() const { return fName; }
1635 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
1636 virtual ObjectFile::Atom::ContentType getContentType() const { return fForLazyDylib ? ObjectFile::Atom::kLazyDylibPointer : ObjectFile::Atom::kLazyPointer; }
1637 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1638 virtual const char* getSectionName() const;
1639 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1640 virtual void copyRawContent(uint8_t buffer[]) const;
1641 ObjectFile::Atom* getTarget() { return &fExternalTarget; }
1642 void setLazyBindingInfoOffset(uint32_t off) { fLazyBindingOffset = off; }
1643 uint32_t getLazyBindingInfoOffset() { return fLazyBindingOffset; }
1644 virtual uint32_t getOrdinal() const { return fSortingOrdinal; }
1645 void setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; }
1646 private:
1647 using WriterAtom<A>::fWriter;
1648 static const char* lazyPointerName(const char* importName);
1649 const char* fName;
1650 ObjectFile::Atom& fTarget;
1651 ObjectFile::Atom& fExternalTarget;
1652 std::vector<ObjectFile::Reference*> fReferences;
1653 bool fForLazyDylib;
1654 bool fCloseStub;
1655 uint32_t fLazyBindingOffset;
1656 uint32_t fSortingOrdinal;
1657 };
1658
1659
1660 template <typename A>
1661 class NonLazyPointerAtom : public WriterAtom<A>
1662 {
1663 public:
1664 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1665 NonLazyPointerAtom(Writer<A>& writer, const char* targetName);
1666 NonLazyPointerAtom(Writer<A>& writer);
1667 virtual const char* getName() const { return fName; }
1668 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1669 virtual ObjectFile::Atom::ContentType getContentType() const { return ObjectFile::Atom::kNonLazyPointer; }
1670 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1671 virtual const char* getSectionName() const { return (fWriter.fOptions.outputKind() == Options::kKextBundle) ? "__got" : "__nl_symbol_ptr"; }
1672 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1673 virtual void copyRawContent(uint8_t buffer[]) const;
1674 ObjectFile::Atom* getTarget() { return fTarget; }
1675 virtual uint32_t getOrdinal() const { return fSortingOrdinal; }
1676 void setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; }
1677 private:
1678 using WriterAtom<A>::fWriter;
1679 static const char* nonlazyPointerName(const char* importName);
1680 const char* fName;
1681 ObjectFile::Atom* fTarget;
1682 std::vector<ObjectFile::Reference*> fReferences;
1683 uint32_t fSortingOrdinal;
1684 };
1685
1686
1687 template <typename A>
1688 class ObjCInfoAtom : public WriterAtom<A>
1689 {
1690 public:
1691 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1692 bool objcReplacementClasses);
1693 virtual const char* getName() const { return "objc$info"; }
1694 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1695 virtual uint64_t getSize() const { return 8; }
1696 virtual const char* getSectionName() const;
1697 virtual void copyRawContent(uint8_t buffer[]) const;
1698 private:
1699 Segment& getInfoSegment() const;
1700 uint32_t fContent[2];
1701 };
1702
1703
1704 template <typename A>
1705 class WriterReference : public ObjectFile::Reference
1706 {
1707 public:
1708 typedef typename A::ReferenceKinds Kinds;
1709
1710 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1711 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1712 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target), fTargetName(target->getName()),
1713 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1714 WriterReference(uint32_t offset, Kinds kind, const char* targetName)
1715 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(NULL), fTargetName(targetName),
1716 fTargetOffset(0), fFromTarget(NULL), fFromTargetOffset(0) {}
1717
1718 virtual ~WriterReference() {}
1719
1720 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return (fTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kUnboundByName; }
1721 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1722 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1723 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1724 virtual const char* getTargetName() const { return fTargetName; }
1725 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1726 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1727 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1728 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1729 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = &target; fTargetOffset = offset; }
1730 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = &target; }
1731 virtual void setFromTargetName(const char* name) { }
1732 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1733 virtual const char* getDescription() const { return "writer reference"; }
1734 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1735
1736 private:
1737 Kinds fKind;
1738 uint32_t fFixUpOffsetInSrc;
1739 ObjectFile::Atom* fTarget;
1740 const char* fTargetName;
1741 uint32_t fTargetOffset;
1742 ObjectFile::Atom* fFromTarget;
1743 uint32_t fFromTargetOffset;
1744 };
1745
1746
1747 template <typename A>
1748 const char* StubHelperAtom<A>::stubName(const char* name)
1749 {
1750 char* buf;
1751 asprintf(&buf, "%s$stubHelper", name);
1752 return buf;
1753 }
1754
1755 template <>
1756 ClassicStubHelperAtom<x86_64>::ClassicStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1757 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1758 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1759 {
1760 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &fLazyPointerAtom));
1761 if ( forLazyDylib ) {
1762 if ( fWriter.fDyldLazyDylibHelper == NULL )
1763 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1764 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldLazyDylibHelper));
1765 }
1766 else {
1767 if ( fWriter.fDyldClassicHelperAtom == NULL )
1768 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1769 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldClassicHelperAtom));
1770 }
1771 }
1772
1773
1774 template <>
1775 uint64_t ClassicStubHelperAtom<x86_64>::getSize() const
1776 {
1777 return 12;
1778 }
1779
1780 template <>
1781 void ClassicStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1782 {
1783 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1784 buffer[1] = 0x8D;
1785 buffer[2] = 0x1D;
1786 buffer[3] = 0x00;
1787 buffer[4] = 0x00;
1788 buffer[5] = 0x00;
1789 buffer[6] = 0x00;
1790 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1791 buffer[8] = 0x00;
1792 buffer[9] = 0x00;
1793 buffer[10] = 0x00;
1794 buffer[11] = 0x00;
1795 }
1796
1797
1798 template <>
1799 FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(Writer<x86_64>& writer)
1800 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1801 {
1802 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1803 fReferences.push_back(new WriterReference<x86_64>(11, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1804 }
1805
1806 template <>
1807 uint64_t FastStubHelperHelperAtom<x86_64>::getSize() const
1808 {
1809 return 16;
1810 }
1811
1812 template <>
1813 void FastStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1814 {
1815 buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
1816 buffer[1] = 0x8D;
1817 buffer[2] = 0x1D;
1818 buffer[3] = 0x00;
1819 buffer[4] = 0x00;
1820 buffer[5] = 0x00;
1821 buffer[6] = 0x00;
1822 buffer[7] = 0x41; // pushq %r11
1823 buffer[8] = 0x53;
1824 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1825 buffer[10] = 0x25;
1826 buffer[11] = 0x00;
1827 buffer[12] = 0x00;
1828 buffer[13] = 0x00;
1829 buffer[14] = 0x00;
1830 buffer[15] = 0x90; // nop
1831 }
1832
1833
1834 template <>
1835 HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(Writer<x86_64>& writer)
1836 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1837 {
1838 if ( writer.fDyldClassicHelperAtom == NULL )
1839 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1840 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32_1, writer.fFastStubGOTAtom));
1841 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1842 fReferences.push_back(new WriterReference<x86_64>(21, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1843 fReferences.push_back(new WriterReference<x86_64>(30, x86_64::kPCRel32, writer.fDyldClassicHelperAtom));
1844 }
1845
1846 template <>
1847 uint64_t HybridStubHelperHelperAtom<x86_64>::getSize() const
1848 {
1849 return 34;
1850 }
1851
1852 template <>
1853 void HybridStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1854 {
1855 buffer[0] = 0x48; // cmpl $0x00,_fast_lazy_bind
1856 buffer[1] = 0x83;
1857 buffer[2] = 0x3D;
1858 buffer[3] = 0x00;
1859 buffer[4] = 0x00;
1860 buffer[5] = 0x00;
1861 buffer[6] = 0x00;
1862 buffer[7] = 0x00;
1863 buffer[8] = 0x74; // je 16
1864 buffer[9] = 0x0F;
1865 buffer[10] = 0x4C; // leaq imageCache(%rip),%r11
1866 buffer[11] = 0x8D;
1867 buffer[12] = 0x1D;
1868 buffer[13] = 0x00;
1869 buffer[14] = 0x00;
1870 buffer[15] = 0x00;
1871 buffer[16] = 0x00;
1872 buffer[17] = 0x41; // pushq %r11
1873 buffer[18] = 0x53;
1874 buffer[19] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1875 buffer[20] = 0x25;
1876 buffer[21] = 0x00;
1877 buffer[22] = 0x00;
1878 buffer[23] = 0x00;
1879 buffer[24] = 0x00;
1880 buffer[25] = 0x48; // addq $8,%rsp
1881 buffer[26] = 0x83;
1882 buffer[27] = 0xC4;
1883 buffer[28] = 0x08;
1884 buffer[29] = 0xE9; // jmp dyld_stub_binding_helper
1885 buffer[30] = 0x00;
1886 buffer[31] = 0x00;
1887 buffer[32] = 0x00;
1888 buffer[33] = 0x00;
1889 }
1890
1891
1892 template <>
1893 HybridStubHelperAtom<x86_64>::HybridStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1894 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1895 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1896 {
1897 if ( fgHelperHelperAtom == NULL ) {
1898 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(fWriter);
1899 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1900 }
1901 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, &fLazyPointerAtom));
1902 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, fgHelperHelperAtom));
1903 }
1904
1905 template <>
1906 uint64_t HybridStubHelperAtom<x86_64>::getSize() const
1907 {
1908 return 18;
1909 }
1910
1911 template <>
1912 void HybridStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1913 {
1914 buffer[0] = 0x68; // pushq $lazy-info-offset
1915 buffer[1] = 0x00;
1916 buffer[2] = 0x00;
1917 buffer[3] = 0x00;
1918 buffer[4] = 0x00;
1919 buffer[5] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1920 buffer[6] = 0x8D;
1921 buffer[7] = 0x1D;
1922 buffer[8] = 0x00;
1923 buffer[9] = 0x00;
1924 buffer[10] = 0x00;
1925 buffer[11] = 0x00;
1926 buffer[12] = 0xE9; // jmp helper-helper
1927 buffer[13] = 0x00;
1928 buffer[14] = 0x00;
1929 buffer[15] = 0x00;
1930 buffer[16] = 0x00;
1931 buffer[17] = 0x90; // nop
1932
1933 // the lazy binding info is created later than this helper atom, so there
1934 // is no Reference to update. Instead we blast the offset here.
1935 uint32_t offset;
1936 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1937 memcpy(&buffer[1], &offset, 4);
1938 }
1939
1940 template <>
1941 FastStubHelperAtom<x86_64>::FastStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1942 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1943 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1944 {
1945 if ( fgHelperHelperAtom == NULL ) {
1946 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(fWriter);
1947 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1948 }
1949 fReferences.push_back(new WriterReference<x86_64>(6, x86_64::kPCRel32, fgHelperHelperAtom));
1950 }
1951
1952 template <>
1953 uint64_t FastStubHelperAtom<x86_64>::getSize() const
1954 {
1955 return 10;
1956 }
1957
1958 template <>
1959 void FastStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1960 {
1961 buffer[0] = 0x68; // pushq $lazy-info-offset
1962 buffer[1] = 0x00;
1963 buffer[2] = 0x00;
1964 buffer[3] = 0x00;
1965 buffer[4] = 0x00;
1966 buffer[5] = 0xE9; // jmp helperhelper
1967 buffer[6] = 0x00;
1968 buffer[7] = 0x00;
1969 buffer[8] = 0x00;
1970 buffer[9] = 0x00;
1971
1972 // the lazy binding info is created later than this helper atom, so there
1973 // is no Reference to update. Instead we blast the offset here.
1974 uint32_t offset;
1975 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1976 memcpy(&buffer[1], &offset, 4);
1977 }
1978
1979 template <>
1980 FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(Writer<x86>& writer)
1981 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1982 {
1983 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1984 fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, writer.fFastStubGOTAtom));
1985 }
1986
1987 template <>
1988 uint64_t FastStubHelperHelperAtom<x86>::getSize() const
1989 {
1990 return 12;
1991 }
1992
1993 template <>
1994 void FastStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1995 {
1996 buffer[0] = 0x68; // pushl $dyld_ImageLoaderCache
1997 buffer[1] = 0x00;
1998 buffer[2] = 0x00;
1999 buffer[3] = 0x00;
2000 buffer[4] = 0x00;
2001 buffer[5] = 0xFF; // jmp *_fast_lazy_bind
2002 buffer[6] = 0x25;
2003 buffer[7] = 0x00;
2004 buffer[8] = 0x00;
2005 buffer[9] = 0x00;
2006 buffer[10] = 0x00;
2007 buffer[11] = 0x90; // nop
2008 }
2009
2010
2011 template <>
2012 FastStubHelperHelperAtom<arm>::FastStubHelperHelperAtom(Writer<arm>& writer)
2013 : WriterAtom<arm>(writer, Segment::fgTextSegment)
2014 {
2015 fReferences.push_back(new WriterReference<arm>(28, arm::kPointerDiff, new NonLazyPointerAtom<arm>(writer), 0, this, 16));
2016 fReferences.push_back(new WriterReference<arm>(32, arm::kPointerDiff, writer.fFastStubGOTAtom, 0, this, 28));
2017 }
2018
2019 template <>
2020 uint64_t FastStubHelperHelperAtom<arm>::getSize() const
2021 {
2022 return 36;
2023 }
2024
2025 template <>
2026 void FastStubHelperHelperAtom<arm>::copyRawContent(uint8_t buffer[]) const
2027 {
2028 // push lazy-info-offset
2029 OSWriteLittleInt32(&buffer[ 0], 0, 0xe52dc004); // str ip, [sp, #-4]!
2030 // push address of dyld_mageLoaderCache
2031 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59fc010); // ldr ip, L1
2032 OSWriteLittleInt32(&buffer[ 8], 0, 0xe08fc00c); // add ip, pc, ip
2033 OSWriteLittleInt32(&buffer[12], 0, 0xe52dc004); // str ip, [sp, #-4]!
2034 // jump through _fast_lazy_bind
2035 OSWriteLittleInt32(&buffer[16], 0, 0xe59fc008); // ldr ip, L2
2036 OSWriteLittleInt32(&buffer[20], 0, 0xe08fc00c); // add ip, pc, ip
2037 OSWriteLittleInt32(&buffer[24], 0, 0xe59cf000); // ldr pc, [ip]
2038 OSWriteLittleInt32(&buffer[28], 0, 0x00000000); // L1: .long fFastStubGOTAtom - (helperhelper+16)
2039 OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // L2: .long _fast_lazy_bind - (helperhelper+28)
2040 }
2041
2042 template <>
2043 ObjectFile::Alignment StubHelperAtom<arm>::getAlignment() const { return ObjectFile::Alignment(2); }
2044
2045 template <>
2046 FastStubHelperAtom<arm>::FastStubHelperAtom(Writer<arm>& writer, ObjectFile::Atom& target,
2047 class LazyPointerAtom<arm>& lazyPointer, bool forLazyDylib)
2048 : StubHelperAtom<arm>(writer, target, lazyPointer, forLazyDylib)
2049 {
2050 if ( fgHelperHelperAtom == NULL ) {
2051 fgHelperHelperAtom = new FastStubHelperHelperAtom<arm>::FastStubHelperHelperAtom(fWriter);
2052 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2053 }
2054 fReferences.push_back(new WriterReference<arm>(4, arm::kBranch24, fgHelperHelperAtom));
2055 }
2056
2057 template <>
2058 uint64_t FastStubHelperAtom<arm>::getSize() const
2059 {
2060 return 12;
2061 }
2062
2063 template <>
2064 void FastStubHelperAtom<arm>::copyRawContent(uint8_t buffer[]) const
2065 {
2066 OSWriteLittleInt32(&buffer[0], 0, 0xe59fc000); // ldr ip, [pc, #0]
2067 OSWriteLittleInt32(&buffer[4], 0, 0xea000000); // b _helperhelper
2068 // the lazy binding info is created later than this helper atom, so there
2069 // is no Reference to update. Instead we blast the offset here.
2070 OSWriteLittleInt32(&buffer[8], 0, fLazyPointerAtom.getLazyBindingInfoOffset());
2071 }
2072
2073
2074 template <>
2075 HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(Writer<x86>& writer)
2076 : WriterAtom<x86>(writer, Segment::fgTextSegment)
2077 {
2078 if ( writer.fDyldClassicHelperAtom == NULL )
2079 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2080 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, writer.fFastStubGOTAtom));
2081 fReferences.push_back(new WriterReference<x86>(18, x86::kPCRel32, writer.fDyldClassicHelperAtom));
2082 fReferences.push_back(new WriterReference<x86>(26, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
2083 fReferences.push_back(new WriterReference<x86>(32, x86::kAbsolute32, writer.fFastStubGOTAtom));
2084 }
2085
2086 template <>
2087 uint64_t HybridStubHelperHelperAtom<x86>::getSize() const
2088 {
2089 return 36;
2090 }
2091
2092
2093 template <>
2094 void HybridStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2095 {
2096 buffer[0] = 0x83; // cmpl $0x00,_fast_lazy_bind
2097 buffer[1] = 0x3D;
2098 buffer[2] = 0x00;
2099 buffer[3] = 0x00;
2100 buffer[4] = 0x00;
2101 buffer[5] = 0x00;
2102 buffer[6] = 0x00;
2103 buffer[7] = 0x75; // jne 22
2104 buffer[8] = 0x0D;
2105 buffer[9] = 0x89; // %eax,4(%esp)
2106 buffer[10] = 0x44;
2107 buffer[11] = 0x24;
2108 buffer[12] = 0x04;
2109 buffer[13] = 0x58; // popl %eax
2110 buffer[14] = 0x87; // xchgl (%esp),%eax
2111 buffer[15] = 0x04;
2112 buffer[16] = 0x24;
2113 buffer[17] = 0xE9; // jmpl dyld_stub_binding_helper
2114 buffer[18] = 0x00;
2115 buffer[19] = 0x00;
2116 buffer[20] = 0x00;
2117 buffer[21] = 0x00;
2118 buffer[22] = 0x83; // addl $0x04,%esp
2119 buffer[23] = 0xC4;
2120 buffer[24] = 0x04;
2121 buffer[25] = 0x68; // pushl imageloadercahce
2122 buffer[26] = 0x00;
2123 buffer[27] = 0x00;
2124 buffer[28] = 0x00;
2125 buffer[29] = 0x00;
2126 buffer[30] = 0xFF; // jmp *_fast_lazy_bind(%rip)
2127 buffer[31] = 0x25;
2128 buffer[32] = 0x00;
2129 buffer[33] = 0x00;
2130 buffer[34] = 0x00;
2131 buffer[35] = 0x00;
2132 }
2133
2134
2135 template <>
2136 ClassicStubHelperAtom<x86>::ClassicStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2137 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2138 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2139 {
2140 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, &fLazyPointerAtom));
2141 if ( forLazyDylib ) {
2142 if ( fWriter.fDyldLazyDylibHelper == NULL )
2143 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2144 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldLazyDylibHelper));
2145 }
2146 else {
2147 if ( fWriter.fDyldClassicHelperAtom == NULL )
2148 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2149 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldClassicHelperAtom));
2150 }
2151 }
2152
2153 template <>
2154 uint64_t ClassicStubHelperAtom<x86>::getSize() const
2155 {
2156 return 10;
2157 }
2158
2159 template <>
2160 void ClassicStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2161 {
2162 buffer[0] = 0x68; // pushl $foo$lazy_ptr
2163 buffer[1] = 0x00;
2164 buffer[2] = 0x00;
2165 buffer[3] = 0x00;
2166 buffer[4] = 0x00;
2167 buffer[5] = 0xE9; // jmp helperhelper
2168 buffer[6] = 0x00;
2169 buffer[7] = 0x00;
2170 buffer[8] = 0x00;
2171 buffer[9] = 0x00;
2172 }
2173
2174 template <>
2175 HybridStubHelperAtom<x86>::HybridStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2176 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2177 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2178 {
2179 if ( fgHelperHelperAtom == NULL ) {
2180 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(fWriter);
2181 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2182 }
2183 fReferences.push_back(new WriterReference<x86>(6, x86::kAbsolute32, &fLazyPointerAtom));
2184 fReferences.push_back(new WriterReference<x86>(11, x86::kPCRel32, fgHelperHelperAtom));
2185 }
2186
2187
2188 template <>
2189 uint64_t HybridStubHelperAtom<x86>::getSize() const
2190 {
2191 return 16;
2192 }
2193
2194 template <>
2195 void HybridStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2196 {
2197 buffer[0] = 0x68; // pushl $lazy-info-offset
2198 buffer[1] = 0x00;
2199 buffer[2] = 0x00;
2200 buffer[3] = 0x00;
2201 buffer[4] = 0x00;
2202 buffer[5] = 0x68; // pushl $foo$lazy_ptr
2203 buffer[6] = 0x00;
2204 buffer[7] = 0x00;
2205 buffer[8] = 0x00;
2206 buffer[9] = 0x00;
2207 buffer[10] = 0xE9; // jmp dyld_hybrid_stub_binding_helper
2208 buffer[11] = 0x00;
2209 buffer[12] = 0x00;
2210 buffer[13] = 0x00;
2211 buffer[14] = 0x00;
2212 buffer[15] = 0x90; // nop
2213
2214 // the lazy binding info is created later than this helper atom, so there
2215 // is no Reference to update. Instead we blast the offset here.
2216 uint32_t offset;
2217 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2218 memcpy(&buffer[1], &offset, 4);
2219 }
2220
2221
2222 template <>
2223 FastStubHelperAtom<x86>::FastStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2224 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2225 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2226 {
2227 if ( fgHelperHelperAtom == NULL ) {
2228 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(fWriter);
2229 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2230 }
2231 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fgHelperHelperAtom));
2232 }
2233
2234
2235 template <>
2236 uint64_t FastStubHelperAtom<x86>::getSize() const
2237 {
2238 return 10;
2239 }
2240
2241 template <>
2242 void FastStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2243 {
2244 buffer[0] = 0x68; // pushl $lazy-info-offset
2245 buffer[1] = 0x00;
2246 buffer[2] = 0x00;
2247 buffer[3] = 0x00;
2248 buffer[4] = 0x00;
2249 buffer[5] = 0xE9; // jmp helperhelper
2250 buffer[6] = 0x00;
2251 buffer[7] = 0x00;
2252 buffer[8] = 0x00;
2253 buffer[9] = 0x00;
2254
2255 // the lazy binding info is created later than this helper atom, so there
2256 // is no Reference to update. Instead we blast the offset here.
2257 uint32_t offset;
2258 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2259 memcpy(&buffer[1], &offset, 4);
2260 }
2261
2262 template <typename A>
2263 const char* LazyPointerAtom<A>::getSectionName() const
2264 {
2265 if ( fCloseStub )
2266 return "__lazy_symbol";
2267 else if ( fForLazyDylib )
2268 return "__ld_symbol_ptr";
2269 else
2270 return "__la_symbol_ptr";
2271 }
2272
2273 // specialize lazy pointer for x86_64 to initially pointer to stub helper
2274 template <>
2275 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
2276 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2277 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
2278 {
2279 if ( forLazyDylib )
2280 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2281 else
2282 writer.fAllSynthesizedLazyPointers.push_back(this);
2283
2284 ObjectFile::Atom* helper;
2285 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2286 if ( writer.fOptions.makeClassicDyldInfo() )
2287 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2288 if ( writer.targetRequiresWeakBinding(target) )
2289 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2290 else
2291 helper = new HybridStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2292 else {
2293 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2294 helper = &target;
2295 else
2296 helper = new FastStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2297 }
2298 }
2299 else {
2300 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2301 }
2302 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
2303 }
2304
2305
2306 // specialize lazy pointer for x86 to initially pointer to stub helper
2307 template <>
2308 LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
2309 : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2310 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
2311 {
2312 if ( forLazyDylib )
2313 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2314 else
2315 writer.fAllSynthesizedLazyPointers.push_back(this);
2316
2317 ObjectFile::Atom* helper;
2318 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2319 if ( writer.fOptions.makeClassicDyldInfo() ) {
2320 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2321 if ( writer.targetRequiresWeakBinding(target) )
2322 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2323 else
2324 helper = new HybridStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2325 }
2326 else {
2327 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2328 helper = &target;
2329 else
2330 helper = new FastStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2331 }
2332 }
2333 else {
2334 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2335 }
2336 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, helper));
2337 }
2338
2339 // specialize lazy pointer for arm to initially pointer to stub helper
2340 template <>
2341 LazyPointerAtom<arm>::LazyPointerAtom(Writer<arm>& writer, ObjectFile::Atom& target, StubAtom<arm>& stub, bool forLazyDylib)
2342 : WriterAtom<arm>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2343 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
2344 {
2345 if ( forLazyDylib )
2346 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2347 else
2348 writer.fAllSynthesizedLazyPointers.push_back(this);
2349
2350 // The one instruction stubs must be close to the lazy pointers
2351 if ( stub.fKind == StubAtom<arm>::kStubShort )
2352 fCloseStub = true;
2353
2354 ObjectFile::Atom* helper;
2355 if ( forLazyDylib ) {
2356 if ( writer.fDyldLazyDylibHelper == NULL )
2357 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2358 helper = writer.fDyldLazyDylibHelper;
2359 }
2360 else if ( writer.fOptions.makeCompressedDyldInfo() ) {
2361 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2362 helper = &target;
2363 else
2364 helper = new FastStubHelperAtom<arm>(writer, target, *this, forLazyDylib);
2365 }
2366 else {
2367 if ( writer.fDyldClassicHelperAtom == NULL )
2368 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2369 helper = writer.fDyldClassicHelperAtom;
2370 }
2371 fReferences.push_back(new WriterReference<arm>(0, arm::kPointer, helper));
2372 }
2373
2374 template <typename A>
2375 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
2376 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2377 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
2378 {
2379 if ( forLazyDylib )
2380 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2381 else
2382 writer.fAllSynthesizedLazyPointers.push_back(this);
2383
2384 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2385 }
2386
2387
2388
2389 template <typename A>
2390 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
2391 {
2392 char* buf;
2393 asprintf(&buf, "%s$lazy_pointer", name);
2394 return buf;
2395 }
2396
2397 template <typename A>
2398 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2399 {
2400 bzero(buffer, getSize());
2401 }
2402
2403
2404 template <typename A>
2405 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
2406 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(&target)
2407 {
2408 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2409 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2410 }
2411
2412 template <typename A>
2413 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer)
2414 : WriterAtom<A>(writer, Segment::fgDataSegment), fName("none"), fTarget(NULL)
2415 {
2416 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2417 }
2418
2419 template <typename A>
2420 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, const char* targetName)
2421 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(targetName)), fTarget(NULL)
2422 {
2423 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2424 fReferences.push_back(new WriterReference<A>(0, A::kPointer, targetName));
2425 }
2426
2427 template <typename A>
2428 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
2429 {
2430 char* buf;
2431 asprintf(&buf, "%s$non_lazy_pointer", name);
2432 return buf;
2433 }
2434
2435 template <typename A>
2436 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2437 {
2438 bzero(buffer, getSize());
2439 }
2440
2441
2442
2443
2444 template <>
2445 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
2446 {
2447 return 2;
2448 }
2449
2450 template <>
2451 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
2452 {
2453 return 2;
2454 }
2455
2456 template <>
2457 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
2458 {
2459 return 2;
2460 }
2461
2462 template <>
2463 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2464 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2465 fTarget(target), fForLazyDylib(forLazyDylib)
2466 {
2467 writer.fAllSynthesizedStubs.push_back(this);
2468 LazyPointerAtom<ppc>* lp;
2469 if ( fWriter.fOptions.prebind() ) {
2470 // for prebound ppc, lazy pointer starts out pointing to target symbol's address
2471 // if target is a weak definition within this linkage unit or zero if in some dylib
2472 lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
2473 }
2474 else {
2475 // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2476 if ( forLazyDylib ) {
2477 if ( writer.fDyldLazyDylibHelper == NULL )
2478 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2479 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2480 }
2481 else {
2482 if ( writer.fDyldClassicHelperAtom == NULL )
2483 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2484 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2485 }
2486 }
2487 fKind = ( fWriter.fSlideable ? kStubPIC : kStubNoPIC );
2488 if ( fKind == kStubPIC ) {
2489 // picbase is 8 bytes into atom
2490 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
2491 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
2492 }
2493 else {
2494 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
2495 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
2496 }
2497 }
2498
2499 template <>
2500 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2501 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2502 fTarget(target), fForLazyDylib(forLazyDylib)
2503 {
2504 writer.fAllSynthesizedStubs.push_back(this);
2505
2506 LazyPointerAtom<ppc64>* lp;
2507 if ( forLazyDylib ) {
2508 if ( writer.fDyldLazyDylibHelper == NULL )
2509 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2510 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2511 }
2512 else {
2513 if ( writer.fDyldClassicHelperAtom == NULL )
2514 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2515 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2516 }
2517 if ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) )
2518 fKind = kStubPIC;
2519 else
2520 fKind = kStubNoPIC;
2521 if ( fKind == kStubPIC ) {
2522 // picbase is 8 bytes into atom
2523 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
2524 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
2525 }
2526 else {
2527 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
2528 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
2529 }
2530 }
2531
2532 template <>
2533 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2534 : WriterAtom<x86>(writer, (writer.fOptions.makeCompressedDyldInfo()|| forLazyDylib) ? Segment::fgTextSegment : Segment::fgImportSegment),
2535 fName(NULL), fTarget(target), fForLazyDylib(forLazyDylib)
2536 {
2537 if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) {
2538 fKind = kStubNoPIC;
2539 fName = stubName(target.getName());
2540 LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
2541 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
2542 writer.fAllSynthesizedStubs.push_back(this);
2543 }
2544 else {
2545 fKind = kJumpTable;
2546 if ( &target == NULL )
2547 asprintf((char**)&fName, "cache-line-crossing-stub %p", this);
2548 else {
2549 fName = stubName(target.getName());
2550 writer.fAllSynthesizedStubs.push_back(this);
2551 }
2552 }
2553 }
2554
2555
2556 template <>
2557 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2558 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2559 {
2560 writer.fAllSynthesizedStubs.push_back(this);
2561
2562 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
2563 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
2564 }
2565
2566 template <>
2567 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2568 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2569 {
2570 writer.fAllSynthesizedStubs.push_back(this);
2571 if ( (writer.fDylibSymbolCountUpperBound < 900)
2572 && writer.fOptions.makeCompressedDyldInfo()
2573 && (writer.fOptions.outputKind() != Options::kDynamicLibrary)
2574 && !forLazyDylib ) {
2575 // dylibs might have __TEXT and __DATA pulled apart to live in shared region
2576 // if > 1000 stubs, the displacement to the lazy pointer my be > 12 bits.
2577 fKind = kStubShort;
2578 }
2579 else if ( fWriter.fSlideable ) {
2580 fKind = kStubPIC;
2581 }
2582 else {
2583 fKind = kStubNoPIC;
2584 }
2585 LazyPointerAtom<arm>* lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
2586 switch ( fKind ) {
2587 case kStubPIC:
2588 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
2589 break;
2590 case kStubNoPIC:
2591 fReferences.push_back(new WriterReference<arm>(8, arm::kReadOnlyPointer, lp));
2592 break;
2593 case kStubShort:
2594 fReferences.push_back(new WriterReference<arm>(0, arm::kPointerDiff12, lp, 0, this, 8));
2595 break;
2596 default:
2597 throw "internal error";
2598 }
2599 }
2600
2601
2602
2603 template <typename A>
2604 const char* StubAtom<A>::stubName(const char* name)
2605 {
2606 char* buf;
2607 asprintf(&buf, "%s$stub", name);
2608 return buf;
2609 }
2610
2611 template <>
2612 uint64_t StubAtom<ppc>::getSize() const
2613 {
2614
2615 return ( (fKind == kStubPIC) ? 32 : 16 );
2616 }
2617
2618 template <>
2619 uint64_t StubAtom<ppc64>::getSize() const
2620 {
2621 return ( (fKind == kStubPIC) ? 32 : 16 );
2622 }
2623
2624
2625 template <>
2626 uint64_t StubAtom<arm>::getSize() const
2627 {
2628 switch ( fKind ) {
2629 case kStubPIC:
2630 return 16;
2631 case kStubNoPIC:
2632 return 12;
2633 case kStubShort:
2634 return 4;
2635 default:
2636 throw "internal error";
2637 }
2638 }
2639
2640 template <>
2641 uint64_t StubAtom<x86>::getSize() const
2642 {
2643 switch ( fKind ) {
2644 case kStubNoPIC:
2645 return 6;
2646 case kJumpTable:
2647 return 5;
2648 default:
2649 throw "internal error";
2650 }
2651 }
2652
2653 template <>
2654 uint64_t StubAtom<x86_64>::getSize() const
2655 {
2656 return 6;
2657 }
2658
2659 template <>
2660 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
2661 {
2662 switch ( fKind ) {
2663 case kStubNoPIC:
2664 return 1;
2665 case kJumpTable:
2666 return 0; // special case x86 self-modifying stubs to be byte aligned
2667 default:
2668 throw "internal error";
2669 }
2670 }
2671
2672 template <>
2673 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
2674 {
2675 if ( fKind == kStubPIC ) {
2676 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
2677 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2678 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2679 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2680 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2681 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2682 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2683 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2684 }
2685 else {
2686 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2687 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
2688 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2689 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2690 }
2691 }
2692
2693 template <>
2694 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
2695 {
2696 if ( fKind == kStubPIC ) {
2697 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
2698 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2699 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2700 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2701 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2702 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2703 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2704 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2705 }
2706 else {
2707 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2708 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
2709 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2710 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2711 }
2712 }
2713
2714 template <>
2715 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
2716 {
2717 switch ( fKind ) {
2718 case kStubNoPIC:
2719 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
2720 buffer[1] = 0x25;
2721 buffer[2] = 0x00;
2722 buffer[3] = 0x00;
2723 buffer[4] = 0x00;
2724 buffer[5] = 0x00;
2725 break;
2726 case kJumpTable:
2727 if ( fWriter.fOptions.prebind() ) {
2728 uint32_t address = this->getAddress();
2729 int32_t rel32 = 0 - (address+5);
2730 buffer[0] = 0xE9;
2731 buffer[1] = rel32 & 0xFF;
2732 buffer[2] = (rel32 >> 8) & 0xFF;
2733 buffer[3] = (rel32 >> 16) & 0xFF;
2734 buffer[4] = (rel32 >> 24) & 0xFF;
2735 }
2736 else {
2737 buffer[0] = 0xF4;
2738 buffer[1] = 0xF4;
2739 buffer[2] = 0xF4;
2740 buffer[3] = 0xF4;
2741 buffer[4] = 0xF4;
2742 }
2743 break;
2744 default:
2745 throw "internal error";
2746 }
2747 }
2748
2749 template <>
2750 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
2751 {
2752 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
2753 buffer[1] = 0x25;
2754 buffer[2] = 0x00;
2755 buffer[3] = 0x00;
2756 buffer[4] = 0x00;
2757 buffer[5] = 0x00;
2758 }
2759
2760 template <>
2761 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
2762 {
2763 switch ( fKind ) {
2764 case kStubPIC:
2765 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
2766 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
2767 OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
2768 OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
2769 break;
2770 case kStubNoPIC:
2771 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
2772 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
2773 OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
2774 break;
2775 case kStubShort:
2776 OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000);// ldr pc, [pc, #foo$lazy_ptr]
2777 break;
2778 default:
2779 throw "internal error";
2780 }
2781 }
2782
2783 // x86_64 stubs are 6 bytes
2784 template <>
2785 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
2786 {
2787 return 1;
2788 }
2789
2790 template <>
2791 const char* StubAtom<ppc>::getSectionName() const
2792 {
2793 return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1");
2794 }
2795
2796 template <>
2797 const char* StubAtom<ppc64>::getSectionName() const
2798 {
2799 return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1");
2800 }
2801
2802 template <>
2803 const char* StubAtom<arm>::getSectionName() const
2804 {
2805 switch ( fKind ) {
2806 case kStubPIC:
2807 return "__picsymbolstub4";
2808 case kStubNoPIC:
2809 return "__symbol_stub4";
2810 case kStubShort:
2811 return "__symbolstub1";
2812 default:
2813 throw "internal error";
2814 }
2815 }
2816
2817 template <>
2818 const char* StubAtom<x86>::getSectionName() const
2819 {
2820 switch ( fKind ) {
2821 case kStubNoPIC:
2822 return "__symbol_stub";
2823 case kJumpTable:
2824 return "__jump_table";
2825 default:
2826 throw "internal error";
2827 }
2828 }
2829
2830
2831
2832
2833 struct AtomByNameSorter
2834 {
2835 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2836 {
2837 return (strcmp(left->getName(), right->getName()) < 0);
2838 }
2839 };
2840
2841 template <typename P>
2842 struct ExternalRelocSorter
2843 {
2844 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
2845 {
2846 // sort first by symbol number
2847 if ( left.r_symbolnum() != right.r_symbolnum() )
2848 return (left.r_symbolnum() < right.r_symbolnum());
2849 // then sort all uses of the same symbol by address
2850 return (left.r_address() < right.r_address());
2851 }
2852 };
2853
2854
2855 template <typename A>
2856 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
2857 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
2858 fAllAtoms(NULL), fStabs(NULL), fRegularDefAtomsThatOverrideADylibsWeakDef(NULL), fLoadCommandsSection(NULL),
2859 fLoadCommandsSegment(NULL), fMachHeaderAtom(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
2860 fSymbolTableCommands(NULL), fHeaderPadding(NULL), fUnwindInfoAtom(NULL),
2861 fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL),
2862 fDyldClassicHelperAtom(NULL), fDyldCompressedHelperAtom(NULL), fDyldLazyDylibHelper(NULL),
2863 fSectionRelocationsAtom(NULL), fCompressedRebaseInfoAtom(NULL), fCompressedBindingInfoAtom(NULL),
2864 fCompressedWeakBindingInfoAtom(NULL), fCompressedLazyBindingInfoAtom(NULL), fCompressedExportInfoAtom(NULL),
2865 fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
2866 fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
2867 fStringsAtom(NULL), fPageZeroAtom(NULL), fFastStubGOTAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0),
2868 fSymbolTableStabsCount(0), fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
2869 fLargestAtomSize(1),
2870 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
2871 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
2872 fBiggerThanTwoGigs(false), fSlideable(false), fHasThumbBranches(false),
2873 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
2874 {
2875 switch ( fOptions.outputKind() ) {
2876 case Options::kDynamicExecutable:
2877 case Options::kStaticExecutable:
2878 if ( fOptions.zeroPageSize() != 0 )
2879 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
2880 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2881 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2882 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2883 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2884 if ( fOptions.makeCompressedDyldInfo() )
2885 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2886 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2887 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2888 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2889 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2890 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2891 if ( fOptions.hasCustomStack() )
2892 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
2893 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2894 if ( fOptions.needsUnwindInfoSection() )
2895 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2896 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2897 if ( fOptions.makeCompressedDyldInfo() ) {
2898 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2899 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2900 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2901 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2902 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2903 }
2904 if ( fOptions.makeClassicDyldInfo() )
2905 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2906 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2907 if ( fOptions.makeClassicDyldInfo() )
2908 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2909 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2910 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2911 break;
2912 case Options::kPreload:
2913 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2914 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2915 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2916 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2917 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2918 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2919 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2920 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2921 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2922 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2923 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2924 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2925 break;
2926 case Options::kDynamicLibrary:
2927 case Options::kDynamicBundle:
2928 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2929 case Options::kKextBundle:
2930 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2931 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2932 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
2933 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
2934 if ( fOptions.initFunctionName() != NULL )
2935 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
2936 }
2937 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2938 if ( fOptions.makeCompressedDyldInfo() )
2939 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2940 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2941 if ( fOptions.sharedRegionEligible() )
2942 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
2943 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2944 if ( fOptions.needsUnwindInfoSection() )
2945 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2946 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2947 if ( fOptions.makeCompressedDyldInfo() ) {
2948 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2949 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2950 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2951 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2952 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2953 }
2954 if ( fOptions.makeClassicDyldInfo() )
2955 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2956 if ( fOptions.sharedRegionEligible() ) {
2957 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
2958 }
2959 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2960 if ( fOptions.makeClassicDyldInfo() )
2961 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2962 if ( fOptions.outputKind() != Options::kKextBundle )
2963 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2964 if ( this->needsModuleTable() )
2965 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
2966 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2967 break;
2968 case Options::kObjectFile:
2969 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2970 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2971 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2972 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2973 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2974 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2975 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2976 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2977 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2978 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2979 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2980 break;
2981 case Options::kDyld:
2982 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2983 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2984 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2985 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2986 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2987 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2988 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2989 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2990 if ( fOptions.needsUnwindInfoSection() )
2991 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2992 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2993 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2994 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2995 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2996 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2997 break;
2998 }
2999
3000 // add extra commmands
3001 bool hasReExports = false;
3002 uint32_t ordinal = 1;
3003 switch ( fOptions.outputKind() ) {
3004 case Options::kDynamicExecutable:
3005 if ( fOptions.makeEncryptable() ) {
3006 fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
3007 fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
3008 }
3009 // fall through
3010 case Options::kDynamicLibrary:
3011 case Options::kDynamicBundle:
3012 {
3013 // add dylib load command atoms for all dynamic libraries
3014 const unsigned int libCount = dynamicLibraries.size();
3015 for (unsigned int i=0; i < libCount; ++i) {
3016 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
3017 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
3018
3019 if ( dylibInfo.options.fReExport ) {
3020 hasReExports = true;
3021 }
3022 else {
3023 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
3024 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
3025 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
3026 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
3027 hasReExports = true;
3028 }
3029 }
3030
3031 if ( dylibInfo.options.fWeakImport ) {
3032 fForcedWeakImportReaders.insert(dylibInfo.reader);
3033 }
3034
3035 if ( dylibInfo.options.fBundleLoader ) {
3036 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
3037 }
3038 else {
3039 // see if a DylibLoadCommandsAtom has already been created for this install path
3040 bool newDylib = true;
3041 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
3042 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
3043 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
3044 if ( !seenDylibInfo.options.fBundleLoader ) {
3045 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
3046 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
3047 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
3048 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
3049 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
3050 newDylib = false;
3051 break;
3052 }
3053 }
3054 }
3055
3056 if ( newDylib ) {
3057 // assign new ordinal and check for other paired load commands
3058 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
3059 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
3060 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
3061 fWriterSynthesizedAtoms.push_back(dyliblc);
3062 if ( dylibInfo.options.fReExport
3063 && !fOptions.useSimplifiedDylibReExports()
3064 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
3065 // see if child has sub-framework that is this
3066 bool isSubFramework = false;
3067 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
3068 if ( childInUmbrella != NULL ) {
3069 const char* myLeaf = strrchr(fOptions.installPath(), '/');
3070 if ( myLeaf != NULL ) {
3071 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
3072 isSubFramework = true;
3073 }
3074 }
3075 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
3076 if ( ! isSubFramework ) {
3077 // this dylib also needs a sub_x load command
3078 bool isFrameworkReExport = false;
3079 const char* lastSlash = strrchr(dylibInstallPath, '/');
3080 if ( lastSlash != NULL ) {
3081 char frameworkName[strlen(lastSlash)+20];
3082 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
3083 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
3084 }
3085 if ( isFrameworkReExport ) {
3086 // needs a LC_SUB_UMBRELLA command
3087 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
3088 }
3089 else {
3090 // needs a LC_SUB_LIBRARY command
3091 const char* nameStart = &lastSlash[1];
3092 if ( lastSlash == NULL )
3093 nameStart = dylibInstallPath;
3094 int len = strlen(nameStart);
3095 const char* dot = strchr(nameStart, '.');
3096 if ( dot != NULL )
3097 len = dot - nameStart;
3098 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
3099 }
3100 }
3101 }
3102 }
3103 }
3104 }
3105 // add umbrella command if needed
3106 if ( fOptions.umbrellaName() != NULL ) {
3107 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
3108 }
3109 // add allowable client commands if used
3110 std::vector<const char*>& allowableClients = fOptions.allowableClients();
3111 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
3112 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
3113 }
3114 break;
3115 case Options::kStaticExecutable:
3116 case Options::kObjectFile:
3117 case Options::kDyld:
3118 case Options::kPreload:
3119 case Options::kKextBundle:
3120 break;
3121 }
3122 fNoReExportedDylibs = !hasReExports;
3123
3124 // add any rpath load commands
3125 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
3126 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
3127 }
3128
3129 // set up fSlideable
3130 switch ( fOptions.outputKind() ) {
3131 case Options::kObjectFile:
3132 case Options::kStaticExecutable:
3133 fSlideable = false;
3134 break;
3135 case Options::kDynamicExecutable:
3136 fSlideable = fOptions.positionIndependentExecutable();
3137 break;
3138 case Options::kDyld:
3139 case Options::kDynamicLibrary:
3140 case Options::kDynamicBundle:
3141 case Options::kPreload:
3142 case Options::kKextBundle:
3143 fSlideable = true;
3144 break;
3145 }
3146
3147 //fprintf(stderr, "ordinals table:\n");
3148 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
3149 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
3150 //}
3151 }
3152
3153 template <typename A>
3154 Writer<A>::~Writer()
3155 {
3156 if ( fFilePath != NULL )
3157 free((void*)fFilePath);
3158 if ( fSymbolTable != NULL )
3159 delete [] fSymbolTable;
3160 }
3161
3162
3163 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
3164 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
3165 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
3166
3167
3168 template <typename A>
3169 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
3170 {
3171 if ( fOptions.outputKind() == Options::kKextBundle ) {
3172 return new UndefinedSymbolProxyAtom<A>(*this, name);
3173 }
3174 else if ( fOptions.outputKind() == Options::kObjectFile ) {
3175 // when doing -r -exported_symbols_list, don't create proxy for a symbol
3176 // that is supposed to be exported. We want an error instead
3177 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
3178 if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) )
3179 return NULL;
3180 else
3181 return new UndefinedSymbolProxyAtom<A>(*this, name);
3182 }
3183 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
3184 return new UndefinedSymbolProxyAtom<A>(*this, name);
3185 else
3186 return NULL;
3187 }
3188
3189 template <typename A>
3190 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
3191 {
3192 // flat namespace images use zero for all ordinals
3193 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3194 return 0;
3195
3196 // is an UndefinedSymbolProxyAtom
3197 if ( lib == this )
3198 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3199 return DYNAMIC_LOOKUP_ORDINAL;
3200
3201 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
3202 if ( pos != fLibraryToOrdinal.end() )
3203 return pos->second;
3204
3205 throw "can't find ordinal for imported symbol";
3206 }
3207
3208 template <typename A>
3209 bool Writer<A>::targetRequiresWeakBinding(const ObjectFile::Atom& target)
3210 {
3211 switch ( target.getDefinitionKind() ) {
3212 case ObjectFile::Atom::kExternalWeakDefinition:
3213 case ObjectFile::Atom::kWeakDefinition:
3214 return true;
3215 case ObjectFile::Atom::kExternalDefinition:
3216 case ObjectFile::Atom::kAbsoluteSymbol:
3217 case ObjectFile::Atom::kRegularDefinition:
3218 case ObjectFile::Atom::kTentativeDefinition:
3219 break;
3220 }
3221 return false;
3222 }
3223
3224 template <typename A>
3225 int Writer<A>::compressedOrdinalForImortedAtom(ObjectFile::Atom* target)
3226 {
3227 // flat namespace images use zero for all ordinals
3228 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3229 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3230
3231 // is an UndefinedSymbolProxyAtom
3232 ObjectFile::Reader* lib = target->getFile();
3233 if ( lib == this )
3234 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3235 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3236
3237 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos;
3238 switch ( target->getDefinitionKind() ) {
3239 case ObjectFile::Atom::kExternalDefinition:
3240 case ObjectFile::Atom::kExternalWeakDefinition:
3241 pos = fLibraryToOrdinal.find(lib);
3242 if ( pos != fLibraryToOrdinal.end() ) {
3243 if ( pos->second == EXECUTABLE_ORDINAL )
3244 return BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
3245 else
3246 return pos->second;
3247 }
3248 break;
3249 case ObjectFile::Atom::kWeakDefinition:
3250 throw "compressedOrdinalForImortedAtom() should not have been called on a weak definition";
3251 case ObjectFile::Atom::kAbsoluteSymbol:
3252 case ObjectFile::Atom::kRegularDefinition:
3253 case ObjectFile::Atom::kTentativeDefinition:
3254 return BIND_SPECIAL_DYLIB_SELF;
3255 }
3256
3257 throw "can't find ordinal for imported symbol";
3258 }
3259
3260
3261 template <typename A>
3262 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
3263 {
3264 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
3265 }
3266
3267 template <typename A>
3268 void Writer<A>::addSynthesizedAtoms(const std::vector<class ObjectFile::Atom*>& existingAtoms,
3269 class ObjectFile::Atom* dyldClassicHelperAtom,
3270 class ObjectFile::Atom* dyldCompressedHelperAtom,
3271 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
3272 bool biggerThanTwoGigs,
3273 uint32_t dylibSymbolCount,
3274 std::vector<class ObjectFile::Atom*>& newAtoms)
3275 {
3276 fDyldClassicHelperAtom = dyldClassicHelperAtom;
3277 fDyldCompressedHelperAtom = dyldCompressedHelperAtom;
3278 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
3279 fBiggerThanTwoGigs = biggerThanTwoGigs;
3280 fDylibSymbolCountUpperBound = dylibSymbolCount;
3281
3282 // create inter-library stubs
3283 synthesizeStubs(existingAtoms, newAtoms);
3284 }
3285
3286
3287 template <typename A>
3288 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
3289 std::vector<class ObjectFile::Reader::Stab>& stabs,
3290 class ObjectFile::Atom* entryPointAtom,
3291 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
3292 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
3293 bool hasExternalWeakDefinitions)
3294 {
3295 fAllAtoms = &atoms;
3296 fStabs = &stabs;
3297 fEntryPoint = entryPointAtom;
3298 fCanScatter = canScatter;
3299 fCpuConstraint = cpuConstraint;
3300 fHasWeakExports = hasExternalWeakDefinitions; // dyld needs to search this image as if it had weak exports
3301 fRegularDefAtomsThatOverrideADylibsWeakDef = &atomsThatOverrideWeak;
3302
3303
3304 try {
3305 // Set for create UUID
3306 if (createUUID)
3307 fUUIDAtom->generate();
3308
3309 // remove uneeded dylib load commands
3310 optimizeDylibReferences();
3311
3312 // check for mdynamic-no-pic codegen
3313 scanForAbsoluteReferences();
3314
3315 // create table of unwind info
3316 synthesizeUnwindInfoTable();
3317
3318 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
3319 partitionIntoSections();
3320
3321 // segment load command can now be sized and padding can be set
3322 adjustLoadCommandsAndPadding();
3323
3324 // assign each section a file offset
3325 assignFileOffsets();
3326
3327 // if need to add branch islands, reassign file offsets
3328 if ( addBranchIslands() )
3329 assignFileOffsets();
3330
3331 // now that addresses are assigned, create unwind info
3332 if ( fUnwindInfoAtom != NULL ) {
3333 fUnwindInfoAtom->generate();
3334 // re-layout
3335 adjustLoadCommandsAndPadding();
3336 assignFileOffsets();
3337 }
3338
3339 // make spit-seg info now that all atoms exist
3340 createSplitSegContent();
3341
3342 // build symbol table and relocations
3343 buildLinkEdit();
3344
3345 // write map file if requested
3346 writeMap();
3347
3348 // write everything
3349 return writeAtoms();
3350 } catch (...) {
3351 // clean up if any errors
3352 (void)unlink(fFilePath);
3353 throw;
3354 }
3355 }
3356
3357 template <typename A>
3358 void Writer<A>::buildLinkEdit()
3359 {
3360 this->collectExportedAndImportedAndLocalAtoms();
3361 this->buildSymbolTable();
3362 this->buildFixups();
3363 this->adjustLinkEditSections();
3364 }
3365
3366
3367
3368 template <typename A>
3369 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
3370 {
3371 return atom->getAddress();
3372 // SectionInfo* info = (SectionInfo*)atom->getSection();
3373 // return info->getBaseAddress() + atom->getSectionOffset();
3374 }
3375
3376 template <>
3377 bool Writer<x86_64>::stringsNeedLabelsInObjects()
3378 {
3379 return true;
3380 }
3381
3382 template <typename A>
3383 bool Writer<A>::stringsNeedLabelsInObjects()
3384 {
3385 return false;
3386 }
3387
3388 template <typename A>
3389 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
3390 {
3391 static unsigned int counter = 0;
3392 const char* name;
3393 if ( stringsNeedLabelsInObjects()
3394 && (atom->getContentType() == ObjectFile::Atom::kCStringType)
3395 && (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) )
3396 asprintf((char**)&name, "LC%u", counter++);
3397 else
3398 name = atom->getName();
3399 return name;
3400 return atom->getName();
3401 }
3402
3403 template <typename A>
3404 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3405 {
3406 // set n_strx
3407 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
3408
3409 // set n_type
3410 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
3411 entry->set_n_type(N_EXT | N_ABS);
3412 }
3413 else {
3414 entry->set_n_type(N_EXT | N_SECT);
3415 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
3416 if ( fOptions.keepPrivateExterns() )
3417 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
3418 }
3419 }
3420
3421 // set n_sect (section number of implementation )
3422 uint8_t sectionIndex = atom->getSection()->getIndex();
3423 entry->set_n_sect(sectionIndex);
3424
3425 // the __mh_execute_header is magic and must be an absolute symbol
3426 if ( (sectionIndex==0)
3427 && (fOptions.outputKind() == Options::kDynamicExecutable)
3428 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
3429 entry->set_n_type(N_EXT | N_ABS);
3430
3431 // set n_desc
3432 uint16_t desc = 0;
3433 if ( atom->isThumb() )
3434 desc |= N_ARM_THUMB_DEF;
3435 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3436 desc |= REFERENCED_DYNAMICALLY;
3437 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3438 desc |= N_NO_DEAD_STRIP;
3439 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
3440 desc |= N_WEAK_DEF;
3441 fHasWeakExports = true;
3442 }
3443 entry->set_n_desc(desc);
3444
3445 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3446 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3447 entry->set_n_value(atom->getSectionOffset());
3448 else
3449 entry->set_n_value(this->getAtomLoadAddress(atom));
3450 }
3451
3452 template <typename A>
3453 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3454 {
3455 // set n_strx
3456 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
3457
3458 // set n_type
3459 if ( fOptions.outputKind() == Options::kObjectFile ) {
3460 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3461 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
3462 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
3463 else
3464 entry->set_n_type(N_UNDF | N_EXT);
3465 }
3466 else {
3467 if ( fOptions.prebind() )
3468 entry->set_n_type(N_PBUD | N_EXT);
3469 else
3470 entry->set_n_type(N_UNDF | N_EXT);
3471 }
3472
3473 // set n_sect
3474 entry->set_n_sect(0);
3475
3476 uint16_t desc = 0;
3477 if ( fOptions.outputKind() != Options::kObjectFile ) {
3478 // set n_desc ( high byte is library ordinal, low byte is reference type )
3479 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
3480 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
3481 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
3482 else
3483 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
3484 try {
3485 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
3486 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
3487 SET_LIBRARY_ORDINAL(desc, ordinal);
3488 }
3489 catch (const char* msg) {
3490 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3491 }
3492 }
3493 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
3494 uint8_t align = atom->getAlignment().powerOf2;
3495 // always record custom alignment of common symbols to match what compiler does
3496 SET_COMM_ALIGN(desc, align);
3497 }
3498 if ( atom->isThumb() )
3499 desc |= N_ARM_THUMB_DEF;
3500 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3501 desc |= REFERENCED_DYNAMICALLY;
3502 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
3503 desc |= N_REF_TO_WEAK;
3504 fReferencesWeakImports = true;
3505 }
3506 // set weak_import attribute
3507 if ( fWeakImportMap[atom] )
3508 desc |= N_WEAK_REF;
3509 entry->set_n_desc(desc);
3510
3511 // set n_value, zero for import proxy and size for tentative definition
3512 entry->set_n_value(atom->getSize());
3513 }
3514
3515
3516 template <typename A>
3517 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3518 {
3519 // set n_strx
3520 const char* symbolName = this->symbolTableName(atom);
3521 char anonName[32];
3522 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
3523 if ( stringsNeedLabelsInObjects() && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3524 // don't use 'l' labels for x86_64 strings
3525 // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
3526 }
3527 else {
3528 sprintf(anonName, "l%u", fAnonNameIndex++);
3529 symbolName = anonName;
3530 }
3531 }
3532 entry->set_n_strx(this->fStringsAtom->add(symbolName));
3533
3534 // set n_type
3535 uint8_t type = N_SECT;
3536 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3537 type = N_ABS;
3538 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
3539 type |= N_PEXT;
3540 entry->set_n_type(type);
3541
3542 // set n_sect (section number of implementation )
3543 uint8_t sectIndex = atom->getSection()->getIndex();
3544 if ( sectIndex == 0 ) {
3545 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
3546 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
3547 sectIndex = 1;
3548 }
3549 entry->set_n_sect(sectIndex);
3550
3551 // set n_desc
3552 uint16_t desc = 0;
3553 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3554 desc |= N_NO_DEAD_STRIP;
3555 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
3556 desc |= N_WEAK_DEF;
3557 if ( atom->isThumb() )
3558 desc |= N_ARM_THUMB_DEF;
3559 entry->set_n_desc(desc);
3560
3561 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3562 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3563 entry->set_n_value(atom->getSectionOffset());
3564 else
3565 entry->set_n_value(this->getAtomLoadAddress(atom));
3566 }
3567
3568
3569 template <typename A>
3570 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3571 {
3572 macho_nlist<P> entry;
3573
3574 // set n_strx
3575 entry.set_n_strx(fStringsAtom->add(name));
3576
3577 // set n_type
3578 entry.set_n_type(N_SECT);
3579
3580 // set n_sect (section number of implementation )
3581 entry.set_n_sect(atom.getSection()->getIndex());
3582
3583 // set n_desc
3584 entry.set_n_desc(0);
3585
3586 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3587 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3588
3589 // add
3590 fLocalExtraLabels.push_back(entry);
3591 }
3592
3593
3594
3595 template <typename A>
3596 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3597 {
3598 macho_nlist<P> entry;
3599
3600 // set n_strx
3601 entry.set_n_strx(fStringsAtom->add(name));
3602
3603 // set n_type
3604 entry.set_n_type(N_SECT|N_EXT);
3605
3606 // set n_sect (section number of implementation )
3607 entry.set_n_sect(atom.getSection()->getIndex());
3608
3609 // set n_desc
3610 entry.set_n_desc(0);
3611
3612 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3613 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3614
3615 // add
3616 fGlobalExtraLabels.push_back(entry);
3617 }
3618
3619 template <typename A>
3620 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
3621 {
3622 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3623 for (uint32_t i=0; i < count; ++i, ++entry) {
3624 ObjectFile::Atom* atom = atoms[i];
3625 if ( &atoms == &fExportedAtoms ) {
3626 this->setExportNlist(atom, entry);
3627 }
3628 else if ( &atoms == &fImportedAtoms ) {
3629 this->setImportNlist(atom, entry);
3630 }
3631 else {
3632 this->setLocalNlist(atom, entry);
3633 }
3634 }
3635 }
3636
3637 template <typename A>
3638 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
3639 {
3640 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
3641 fSymbolTable[startIndex++] = *it;
3642 }
3643
3644
3645 template <typename A>
3646 struct NListNameSorter
3647 {
3648 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
3649
3650 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
3651 {
3652 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
3653 }
3654 private:
3655 StringsLinkEditAtom<A>* fStringPool;
3656 };
3657
3658
3659 template <typename A>
3660 void Writer<A>::buildSymbolTable()
3661 {
3662 fSymbolTableStabsStartIndex = 0;
3663 fSymbolTableStabsCount = fStabs->size();
3664 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
3665 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
3666 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
3667 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
3668 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
3669 fSymbolTableImportCount = fImportedAtoms.size();
3670
3671 // allocate symbol table
3672 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
3673 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
3674
3675 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
3676 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
3677 if ( fLocalExtraLabels.size() != 0 )
3678 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
3679 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
3680 if ( fGlobalExtraLabels.size() != 0 ) {
3681 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
3682 // re-sort combined range
3683 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
3684 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
3685 NListNameSorter<A>(fStringsAtom) );
3686 }
3687 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
3688 addStabs(fSymbolTableStabsStartIndex);
3689
3690 // set up module table
3691 if ( fModuleInfoAtom != NULL )
3692 fModuleInfoAtom->setName();
3693
3694 // create atom to symbol index map
3695 // imports
3696 int i = 0;
3697 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
3698 fAtomToSymbolIndex[*it] = i + fSymbolTableImportStartIndex;
3699 ++i;
3700 }
3701 // locals
3702 i = 0;
3703 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
3704 fAtomToSymbolIndex[*it] = i + fSymbolTableLocalStartIndex;
3705 ++i;
3706 }
3707 // exports
3708 i = 0;
3709 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
3710 fAtomToSymbolIndex[*it] = i + fSymbolTableExportStartIndex;
3711 ++i;
3712 }
3713
3714 }
3715
3716
3717
3718 template <typename A>
3719 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
3720 {
3721 switch ( atom.getSymbolTableInclusion() ) {
3722 case ObjectFile::Atom::kSymbolTableNotIn:
3723 return false;
3724 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3725 return true;
3726 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3727 case ObjectFile::Atom::kSymbolTableIn:
3728 switch ( atom.getScope() ) {
3729 case ObjectFile::Atom::scopeGlobal:
3730 return true;
3731 case ObjectFile::Atom::scopeLinkageUnit:
3732 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
3733 default:
3734 return false;
3735 }
3736 break;
3737 }
3738 return false;
3739 }
3740
3741 template <typename A>
3742 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
3743 {
3744 const int atomCount = fAllAtoms->size();
3745 // guess at sizes of each bucket to minimize re-allocations
3746 fImportedAtoms.reserve(100);
3747 fExportedAtoms.reserve(atomCount/2);
3748 fLocalSymbolAtoms.reserve(atomCount);
3749
3750 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3751 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3752 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3753 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3754 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3755 ObjectFile::Atom* atom = *ait;
3756 // only named atoms go in symbol table
3757 if ( atom->getName() != NULL ) {
3758 // put atom into correct bucket: imports, exports, locals
3759 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
3760 switch ( atom->getDefinitionKind() ) {
3761 case ObjectFile::Atom::kExternalDefinition:
3762 case ObjectFile::Atom::kExternalWeakDefinition:
3763 fImportedAtoms.push_back(atom);
3764 break;
3765 case ObjectFile::Atom::kTentativeDefinition:
3766 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
3767 fImportedAtoms.push_back(atom);
3768 break;
3769 }
3770 // else fall into
3771 case ObjectFile::Atom::kWeakDefinition:
3772 if ( stringsNeedLabelsInObjects()
3773 && (fOptions.outputKind() == Options::kObjectFile)
3774 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn)
3775 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3776 && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3777 fLocalSymbolAtoms.push_back(atom);
3778 break;
3779 }
3780 // else fall into
3781 case ObjectFile::Atom::kRegularDefinition:
3782 case ObjectFile::Atom::kAbsoluteSymbol:
3783 if ( this->shouldExport(*atom) )
3784 fExportedAtoms.push_back(atom);
3785 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
3786 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
3787 fLocalSymbolAtoms.push_back(atom);
3788 break;
3789 }
3790 }
3791 // when geneating a .o file, dtrace static probes become local labels
3792 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
3793 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3794 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3795 ObjectFile::Reference* ref = *rit;
3796 if ( ref->getKind() == A::kDtraceProbe ) {
3797 // dtrace probe points to be add back into generated .o file
3798 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3799 }
3800 }
3801 }
3802 // when linking kernel, old style dtrace static probes become global labels
3803 else if ( fOptions.readerOptions().fForStatic ) {
3804 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3805 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3806 ObjectFile::Reference* ref = *rit;
3807 if ( ref->getKind() == A::kDtraceProbe ) {
3808 // dtrace probe points to be add back into generated .o file
3809 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3810 }
3811 }
3812 }
3813 }
3814 }
3815 }
3816
3817 // sort exported atoms by name
3818 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
3819 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
3820 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
3821 }
3822
3823
3824 template <typename A>
3825 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
3826 {
3827 switch ( stab.type ) {
3828 case N_FUN:
3829 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3830 // end of function N_FUN has size
3831 return stab.atom->getSize();
3832 }
3833 else {
3834 // start of function N_FUN has address
3835 return getAtomLoadAddress(stab.atom);
3836 }
3837 case N_LBRAC:
3838 case N_RBRAC:
3839 case N_SLINE:
3840 if ( stab.atom == NULL )
3841 // some weird assembly files have slines not associated with a function
3842 return stab.value;
3843 else
3844 // all these stab types need their value changed from an offset in the atom to an address
3845 return getAtomLoadAddress(stab.atom) + stab.value;
3846 case N_STSYM:
3847 case N_LCSYM:
3848 case N_BNSYM:
3849 // all these need address of atom
3850 return getAtomLoadAddress(stab.atom);;
3851 case N_ENSYM:
3852 return stab.atom->getSize();
3853 case N_SO:
3854 if ( stab.atom == NULL ) {
3855 return 0;
3856 }
3857 else {
3858 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3859 // end of translation unit N_SO has address of end of last atom
3860 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
3861 }
3862 else {
3863 // start of translation unit N_SO has address of end of first atom
3864 return getAtomLoadAddress(stab.atom);
3865 }
3866 }
3867 break;
3868 default:
3869 return stab.value;
3870 }
3871 }
3872
3873 template <typename A>
3874 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
3875 {
3876 switch (stab.type) {
3877 case N_SO:
3878 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
3879 return this->fStringsAtom->emptyString();
3880 break;
3881 }
3882 // fall into uniquing case
3883 case N_SOL:
3884 case N_BINCL:
3885 case N_EXCL:
3886 return this->fStringsAtom->addUnique(stab.string);
3887 break;
3888 default:
3889 if ( stab.string == NULL )
3890 return 0;
3891 else if ( stab.string[0] == '\0' )
3892 return this->fStringsAtom->emptyString();
3893 else
3894 return this->fStringsAtom->add(stab.string);
3895 }
3896 return 0;
3897 }
3898
3899 template <typename A>
3900 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
3901 {
3902 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
3903 if ( stab.type == N_FUN )
3904 return stab.other;
3905 else if ( stab.atom != NULL )
3906 return stab.atom->getSection()->getIndex();
3907 else
3908 return stab.other;
3909 }
3910
3911 template <typename A>
3912 void Writer<A>::addStabs(uint32_t startIndex)
3913 {
3914 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3915 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
3916 const ObjectFile::Reader::Stab& stab = *it;
3917 entry->set_n_type(stab.type);
3918 entry->set_n_sect(sectionIndexForStab(stab));
3919 entry->set_n_desc(stab.desc);
3920 entry->set_n_value(valueForStab(stab));
3921 entry->set_n_strx(stringOffsetForStab(stab));
3922 }
3923 }
3924
3925
3926
3927 template <typename A>
3928 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
3929 {
3930 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fAtomToSymbolIndex.find(&atom);
3931 if ( pos != fAtomToSymbolIndex.end() )
3932 return pos->second;
3933 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
3934 }
3935
3936
3937 template <>
3938 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3939 {
3940 switch ( target.getSymbolTableInclusion() ) {
3941 case ObjectFile::Atom::kSymbolTableNotIn:
3942 return false;
3943 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3944 case ObjectFile::Atom::kSymbolTableIn:
3945 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3946 return true;
3947 };
3948 return false;
3949 }
3950
3951 template <typename A>
3952 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3953 {
3954 switch ( target.getDefinitionKind() ) {
3955 case ObjectFile::Atom::kRegularDefinition:
3956 case ObjectFile::Atom::kWeakDefinition:
3957 case ObjectFile::Atom::kAbsoluteSymbol:
3958 return false;
3959 case ObjectFile::Atom::kTentativeDefinition:
3960 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
3961 return false;
3962 else
3963 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
3964 case ObjectFile::Atom::kExternalDefinition:
3965 case ObjectFile::Atom::kExternalWeakDefinition:
3966 return shouldExport(target);
3967 }
3968 return false;
3969 }
3970
3971 template <typename A>
3972 void Writer<A>::buildFixups()
3973 {
3974 if ( fOptions.outputKind() == Options::kObjectFile ) {
3975 this->buildObjectFileFixups();
3976 }
3977 else {
3978 if ( fOptions.keepRelocations() )
3979 this->buildObjectFileFixups();
3980 this->buildExecutableFixups();
3981 }
3982 }
3983
3984 template <>
3985 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3986 {
3987 ObjectFile::Atom& target = ref->getTarget();
3988 bool external = this->makesExternalRelocatableReference(target);
3989 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
3990 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3991 macho_relocation_info<P> reloc1;
3992 macho_relocation_info<P> reloc2;
3993 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
3994
3995 switch ( kind ) {
3996 case x86_64::kNoFixUp:
3997 case x86_64::kGOTNoFixUp:
3998 case x86_64::kFollowOn:
3999 case x86_64::kGroupSubordinate:
4000 return 0;
4001
4002 case x86_64::kPointer:
4003 case x86_64::kPointerWeakImport:
4004 reloc1.set_r_address(address);
4005 reloc1.set_r_symbolnum(symbolIndex);
4006 reloc1.set_r_pcrel(false);
4007 reloc1.set_r_length(3);
4008 reloc1.set_r_extern(external);
4009 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
4010 fSectionRelocs.push_back(reloc1);
4011 return 1;
4012
4013 case x86_64::kPointer32:
4014 reloc1.set_r_address(address);
4015 reloc1.set_r_symbolnum(symbolIndex);
4016 reloc1.set_r_pcrel(false);
4017 reloc1.set_r_length(2);
4018 reloc1.set_r_extern(external);
4019 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
4020 fSectionRelocs.push_back(reloc1);
4021 return 1;
4022
4023 case x86_64::kPointerDiff32:
4024 case x86_64::kPointerDiff:
4025 {
4026 ObjectFile::Atom& fromTarget = ref->getFromTarget();
4027 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
4028 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
4029 reloc1.set_r_address(address);
4030 reloc1.set_r_symbolnum(symbolIndex);
4031 reloc1.set_r_pcrel(false);
4032 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
4033 reloc1.set_r_extern(external);
4034 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
4035 reloc2.set_r_address(address);
4036 reloc2.set_r_symbolnum(fromSymbolIndex);
4037 reloc2.set_r_pcrel(false);
4038 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
4039 reloc2.set_r_extern(fromExternal);
4040 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
4041 fSectionRelocs.push_back(reloc1);
4042 fSectionRelocs.push_back(reloc2);
4043 return 2;
4044 }
4045
4046 case x86_64::kBranchPCRel32:
4047 case x86_64::kBranchPCRel32WeakImport:
4048 case x86_64::kDtraceProbeSite:
4049 case x86_64::kDtraceIsEnabledSite:
4050 reloc1.set_r_address(address);
4051 reloc1.set_r_symbolnum(symbolIndex);
4052 reloc1.set_r_pcrel(true);
4053 reloc1.set_r_length(2);
4054 reloc1.set_r_extern(external);
4055 reloc1.set_r_type(X86_64_RELOC_BRANCH);
4056 fSectionRelocs.push_back(reloc1);
4057 return 1;
4058
4059 case x86_64::kPCRel32:
4060 reloc1.set_r_address(address);
4061 reloc1.set_r_symbolnum(symbolIndex);
4062 reloc1.set_r_pcrel(true);
4063 reloc1.set_r_length(2);
4064 reloc1.set_r_extern(external);
4065 reloc1.set_r_type(X86_64_RELOC_SIGNED);
4066 fSectionRelocs.push_back(reloc1);
4067 return 1;
4068
4069 case x86_64::kPCRel32_1:
4070 reloc1.set_r_address(address);
4071 reloc1.set_r_symbolnum(symbolIndex);
4072 reloc1.set_r_pcrel(true);
4073 reloc1.set_r_length(2);
4074 reloc1.set_r_extern(external);
4075 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
4076 fSectionRelocs.push_back(reloc1);
4077 return 1;
4078
4079 case x86_64::kPCRel32_2:
4080 reloc1.set_r_address(address);
4081 reloc1.set_r_symbolnum(symbolIndex);
4082 reloc1.set_r_pcrel(true);
4083 reloc1.set_r_length(2);
4084 reloc1.set_r_extern(external);
4085 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
4086 fSectionRelocs.push_back(reloc1);
4087 return 1;
4088
4089 case x86_64::kPCRel32_4:
4090 reloc1.set_r_address(address);
4091 reloc1.set_r_symbolnum(symbolIndex);
4092 reloc1.set_r_pcrel(true);
4093 reloc1.set_r_length(2);
4094 reloc1.set_r_extern(external);
4095 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
4096 fSectionRelocs.push_back(reloc1);
4097 return 1;
4098
4099 case x86_64::kBranchPCRel8:
4100 reloc1.set_r_address(address);
4101 reloc1.set_r_symbolnum(symbolIndex);
4102 reloc1.set_r_pcrel(true);
4103 reloc1.set_r_length(0);
4104 reloc1.set_r_extern(external);
4105 reloc1.set_r_type(X86_64_RELOC_BRANCH);
4106 fSectionRelocs.push_back(reloc1);
4107 return 1;
4108
4109 case x86_64::kPCRel32GOT:
4110 case x86_64::kPCRel32GOTWeakImport:
4111 reloc1.set_r_address(address);
4112 reloc1.set_r_symbolnum(symbolIndex);
4113 reloc1.set_r_pcrel(true);
4114 reloc1.set_r_length(2);
4115 reloc1.set_r_extern(external);
4116 reloc1.set_r_type(X86_64_RELOC_GOT);
4117 fSectionRelocs.push_back(reloc1);
4118 return 1;
4119
4120 case x86_64::kPCRel32GOTLoad:
4121 case x86_64::kPCRel32GOTLoadWeakImport:
4122 reloc1.set_r_address(address);
4123 reloc1.set_r_symbolnum(symbolIndex);
4124 reloc1.set_r_pcrel(true);
4125 reloc1.set_r_length(2);
4126 reloc1.set_r_extern(external);
4127 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
4128 fSectionRelocs.push_back(reloc1);
4129 return 1;
4130
4131 case x86_64::kPointerDiff24:
4132 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4133
4134 case x86_64::kImageOffset32:
4135 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4136
4137 case x86_64::kSectionOffset24:
4138 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
4139
4140 case x86_64::kDtraceTypeReference:
4141 case x86_64::kDtraceProbe:
4142 // generates no relocs
4143 return 0;
4144 }
4145 return 0;
4146 }
4147
4148
4149 template <>
4150 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4151 {
4152 ObjectFile::Atom& target = ref->getTarget();
4153 bool isExtern = this->makesExternalRelocatableReference(target);
4154 uint32_t symbolIndex = 0;
4155 if ( isExtern )
4156 symbolIndex = this->symbolIndex(target);
4157 uint32_t sectionNum = target.getSection()->getIndex();
4158 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4159 macho_relocation_info<P> reloc1;
4160 macho_relocation_info<P> reloc2;
4161 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4162 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4163 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
4164
4165 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
4166 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
4167 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
4168
4169
4170 switch ( kind ) {
4171 case x86::kNoFixUp:
4172 case x86::kFollowOn:
4173 case x86::kGroupSubordinate:
4174 return 0;
4175
4176 case x86::kPointer:
4177 case x86::kPointerWeakImport:
4178 case x86::kAbsolute32:
4179 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4180 // use scattered reloc is target offset is non-zero
4181 sreloc1->set_r_scattered(true);
4182 sreloc1->set_r_pcrel(false);
4183 sreloc1->set_r_length(2);
4184 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4185 sreloc1->set_r_address(address);
4186 sreloc1->set_r_value(target.getAddress());
4187 }
4188 else {
4189 reloc1.set_r_address(address);
4190 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4191 reloc1.set_r_pcrel(false);
4192 reloc1.set_r_length(2);
4193 reloc1.set_r_extern(isExtern);
4194 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4195 }
4196 fSectionRelocs.push_back(reloc1);
4197 return 1;
4198
4199 case x86::kPointerDiff16:
4200 case x86::kPointerDiff:
4201 {
4202 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4203 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
4204 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
4205 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
4206 sreloc1->set_r_scattered(true);
4207 sreloc1->set_r_pcrel(false);
4208 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4209 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4210 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
4211 else
4212 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
4213 sreloc1->set_r_address(address);
4214 sreloc1->set_r_value(target.getAddress());
4215
4216 sreloc2->set_r_scattered(true);
4217 sreloc2->set_r_pcrel(false);
4218 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4219 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
4220 sreloc2->set_r_address(0);
4221 if ( &ref->getFromTarget() == atom )
4222 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4223 else
4224 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4225 fSectionRelocs.push_back(reloc2);
4226 fSectionRelocs.push_back(reloc1);
4227 return 2;
4228 }
4229
4230 case x86::kPCRel32WeakImport:
4231 case x86::kPCRel32:
4232 case x86::kPCRel16:
4233 case x86::kPCRel8:
4234 case x86::kDtraceProbeSite:
4235 case x86::kDtraceIsEnabledSite:
4236 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4237 // use scattered reloc is target offset is non-zero
4238 sreloc1->set_r_scattered(true);
4239 sreloc1->set_r_pcrel(true);
4240 sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4241 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4242 sreloc1->set_r_address(address);
4243 sreloc1->set_r_value(target.getAddress());
4244 }
4245 else {
4246 reloc1.set_r_address(address);
4247 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4248 reloc1.set_r_pcrel(true);
4249 reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4250 reloc1.set_r_extern(isExtern);
4251 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4252 }
4253 fSectionRelocs.push_back(reloc1);
4254 return 1;
4255
4256 case x86::kPointerDiff24:
4257 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4258
4259 case x86::kImageOffset32:
4260 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4261
4262 case x86::kSectionOffset24:
4263 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
4264
4265 case x86::kDtraceTypeReference:
4266 case x86::kDtraceProbe:
4267 // generates no relocs
4268 return 0;
4269
4270 }
4271 return 0;
4272 }
4273
4274 template <>
4275 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4276 {
4277 ObjectFile::Atom& target = ref->getTarget();
4278 bool isExtern = this->makesExternalRelocatableReference(target);
4279 uint32_t symbolIndex = 0;
4280 if ( isExtern )
4281 symbolIndex = this->symbolIndex(target);
4282 uint32_t sectionNum = target.getSection()->getIndex();
4283 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4284 macho_relocation_info<P> reloc1;
4285 macho_relocation_info<P> reloc2;
4286 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4287 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4288 arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
4289
4290 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
4291 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
4292 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
4293
4294
4295 switch ( kind ) {
4296 case arm::kNoFixUp:
4297 case arm::kFollowOn:
4298 case arm::kGroupSubordinate:
4299 return 0;
4300
4301 case arm::kPointer:
4302 case arm::kReadOnlyPointer:
4303 case arm::kPointerWeakImport:
4304 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4305 // use scattered reloc is target offset is non-zero
4306 sreloc1->set_r_scattered(true);
4307 sreloc1->set_r_pcrel(false);
4308 sreloc1->set_r_length(2);
4309 sreloc1->set_r_type(ARM_RELOC_VANILLA);
4310 sreloc1->set_r_address(address);
4311 sreloc1->set_r_value(target.getAddress());
4312 }
4313 else {
4314 reloc1.set_r_address(address);
4315 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4316 reloc1.set_r_pcrel(false);
4317 reloc1.set_r_length(2);
4318 reloc1.set_r_extern(isExtern);
4319 reloc1.set_r_type(ARM_RELOC_VANILLA);
4320 }
4321 fSectionRelocs.push_back(reloc1);
4322 return 1;
4323
4324 case arm::kPointerDiff:
4325 {
4326 sreloc1->set_r_scattered(true);
4327 sreloc1->set_r_pcrel(false);
4328 sreloc1->set_r_length(2);
4329 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4330 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
4331 else
4332 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
4333 sreloc1->set_r_address(address);
4334 sreloc1->set_r_value(target.getAddress());
4335 sreloc2->set_r_scattered(true);
4336 sreloc2->set_r_pcrel(false);
4337 sreloc2->set_r_length(2);
4338 sreloc2->set_r_type(ARM_RELOC_PAIR);
4339 sreloc2->set_r_address(0);
4340 if ( &ref->getFromTarget() == atom )
4341 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4342 else
4343 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4344 fSectionRelocs.push_back(reloc2);
4345 fSectionRelocs.push_back(reloc1);
4346 return 2;
4347 }
4348
4349 case arm::kBranch24WeakImport:
4350 case arm::kBranch24:
4351 case arm::kDtraceProbeSite:
4352 case arm::kDtraceIsEnabledSite:
4353 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4354 // use scattered reloc is target offset is non-zero
4355 sreloc1->set_r_scattered(true);
4356 sreloc1->set_r_pcrel(true);
4357 sreloc1->set_r_length(2);
4358 sreloc1->set_r_type(ARM_RELOC_BR24);
4359 sreloc1->set_r_address(address);
4360 sreloc1->set_r_value(target.getAddress());
4361 }
4362 else {
4363 reloc1.set_r_address(address);
4364 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4365 reloc1.set_r_pcrel(true);
4366 reloc1.set_r_length(2);
4367 reloc1.set_r_extern(isExtern);
4368 reloc1.set_r_type(ARM_RELOC_BR24);
4369 }
4370 fSectionRelocs.push_back(reloc1);
4371 return 1;
4372
4373 case arm::kThumbBranch22WeakImport:
4374 case arm::kThumbBranch22:
4375 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4376 // use scattered reloc if target offset is non-zero
4377 sreloc1->set_r_scattered(true);
4378 sreloc1->set_r_pcrel(true);
4379 sreloc1->set_r_length(2);
4380 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
4381 sreloc1->set_r_address(address);
4382 sreloc1->set_r_value(target.getAddress());
4383 }
4384 else {
4385 reloc1.set_r_address(address);
4386 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4387 reloc1.set_r_pcrel(true);
4388 reloc1.set_r_length(2);
4389 reloc1.set_r_extern(isExtern);
4390 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
4391 }
4392 fSectionRelocs.push_back(reloc1);
4393 return 1;
4394
4395 case arm::kPointerDiff12:
4396 throw "internal error. no reloc for 12-bit pointer diffs";
4397
4398 case arm::kDtraceTypeReference:
4399 case arm::kDtraceProbe:
4400 // generates no relocs
4401 return 0;
4402
4403 }
4404 return 0;
4405 }
4406
4407 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
4408 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4409 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
4410 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4411 template <> uint64_t Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
4412
4413 template <>
4414 uint8_t Writer<ppc>::getRelocPointerSize()
4415 {
4416 return 2;
4417 }
4418
4419 template <>
4420 uint8_t Writer<ppc64>::getRelocPointerSize()
4421 {
4422 return 3;
4423 }
4424
4425 template <>
4426 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4427 {
4428 return addObjectRelocs_powerpc(atom, ref);
4429 }
4430
4431 template <>
4432 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4433 {
4434 return addObjectRelocs_powerpc(atom, ref);
4435 }
4436
4437 //
4438 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
4439 // they use a common addObjectRelocs_powerpc() method.
4440 //
4441 template <typename A>
4442 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4443 {
4444 ObjectFile::Atom& target = ref->getTarget();
4445 bool isExtern = this->makesExternalRelocatableReference(target);
4446 uint32_t symbolIndex = 0;
4447 if ( isExtern )
4448 symbolIndex = this->symbolIndex(target);
4449 uint32_t sectionNum = target.getSection()->getIndex();
4450 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4451 macho_relocation_info<P> reloc1;
4452 macho_relocation_info<P> reloc2;
4453 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4454 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4455 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
4456
4457 switch ( kind ) {
4458 case A::kNoFixUp:
4459 case A::kFollowOn:
4460 case A::kGroupSubordinate:
4461 return 0;
4462
4463 case A::kPointer:
4464 case A::kPointerWeakImport:
4465 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
4466 // use scattered reloc is target offset is outside target
4467 sreloc1->set_r_scattered(true);
4468 sreloc1->set_r_pcrel(false);
4469 sreloc1->set_r_length(getRelocPointerSize());
4470 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4471 sreloc1->set_r_address(address);
4472 sreloc1->set_r_value(target.getAddress());
4473 }
4474 else {
4475 reloc1.set_r_address(address);
4476 if ( isExtern )
4477 reloc1.set_r_symbolnum(symbolIndex);
4478 else
4479 reloc1.set_r_symbolnum(sectionNum);
4480 reloc1.set_r_pcrel(false);
4481 reloc1.set_r_length(getRelocPointerSize());
4482 reloc1.set_r_extern(isExtern);
4483 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4484 }
4485 fSectionRelocs.push_back(reloc1);
4486 return 1;
4487
4488 case A::kPointerDiff16:
4489 case A::kPointerDiff32:
4490 case A::kPointerDiff64:
4491 {
4492 sreloc1->set_r_scattered(true);
4493 sreloc1->set_r_pcrel(false);
4494 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
4495 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4496 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
4497 else
4498 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
4499 sreloc1->set_r_address(address);
4500 sreloc1->set_r_value(target.getAddress());
4501 sreloc2->set_r_scattered(true);
4502 sreloc2->set_r_pcrel(false);
4503 sreloc2->set_r_length(sreloc1->r_length());
4504 sreloc2->set_r_type(PPC_RELOC_PAIR);
4505 sreloc2->set_r_address(0);
4506 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4507 fSectionRelocs.push_back(reloc2);
4508 fSectionRelocs.push_back(reloc1);
4509 return 2;
4510 }
4511
4512 case A::kBranch24WeakImport:
4513 case A::kBranch24:
4514 case A::kDtraceProbeSite:
4515 case A::kDtraceIsEnabledSite:
4516 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4517 reloc1.set_r_address(address);
4518 if ( isExtern )
4519 reloc1.set_r_symbolnum(symbolIndex);
4520 else
4521 reloc1.set_r_symbolnum(sectionNum);
4522 reloc1.set_r_pcrel(true);
4523 reloc1.set_r_length(2);
4524 reloc1.set_r_type(PPC_RELOC_BR24);
4525 reloc1.set_r_extern(isExtern);
4526 }
4527 else {
4528 sreloc1->set_r_scattered(true);
4529 sreloc1->set_r_pcrel(true);
4530 sreloc1->set_r_length(2);
4531 sreloc1->set_r_type(PPC_RELOC_BR24);
4532 sreloc1->set_r_address(address);
4533 sreloc1->set_r_value(target.getAddress());
4534 }
4535 fSectionRelocs.push_back(reloc1);
4536 return 1;
4537
4538 case A::kBranch14:
4539 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4540 reloc1.set_r_address(address);
4541 if ( isExtern )
4542 reloc1.set_r_symbolnum(symbolIndex);
4543 else
4544 reloc1.set_r_symbolnum(sectionNum);
4545 reloc1.set_r_pcrel(true);
4546 reloc1.set_r_length(2);
4547 reloc1.set_r_type(PPC_RELOC_BR14);
4548 reloc1.set_r_extern(isExtern);
4549 }
4550 else {
4551 sreloc1->set_r_scattered(true);
4552 sreloc1->set_r_pcrel(true);
4553 sreloc1->set_r_length(2);
4554 sreloc1->set_r_type(PPC_RELOC_BR14);
4555 sreloc1->set_r_address(address);
4556 sreloc1->set_r_value(target.getAddress());
4557 }
4558 fSectionRelocs.push_back(reloc1);
4559 return 1;
4560
4561 case A::kPICBaseLow16:
4562 case A::kPICBaseLow14:
4563 {
4564 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4565 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4566 sreloc1->set_r_scattered(true);
4567 sreloc1->set_r_pcrel(false);
4568 sreloc1->set_r_length(2);
4569 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
4570 sreloc1->set_r_address(address);
4571 sreloc1->set_r_value(target.getAddress());
4572 sreloc2->set_r_scattered(true);
4573 sreloc2->set_r_pcrel(false);
4574 sreloc2->set_r_length(2);
4575 sreloc2->set_r_type(PPC_RELOC_PAIR);
4576 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
4577 sreloc2->set_r_value(fromAddr);
4578 fSectionRelocs.push_back(reloc2);
4579 fSectionRelocs.push_back(reloc1);
4580 return 2;
4581 }
4582
4583 case A::kPICBaseHigh16:
4584 {
4585 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4586 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4587 sreloc1->set_r_scattered(true);
4588 sreloc1->set_r_pcrel(false);
4589 sreloc1->set_r_length(2);
4590 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
4591 sreloc1->set_r_address(address);
4592 sreloc1->set_r_value(target.getAddress());
4593 sreloc2->set_r_scattered(true);
4594 sreloc2->set_r_pcrel(false);
4595 sreloc2->set_r_length(2);
4596 sreloc2->set_r_type(PPC_RELOC_PAIR);
4597 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
4598 sreloc2->set_r_value(fromAddr);
4599 fSectionRelocs.push_back(reloc2);
4600 fSectionRelocs.push_back(reloc1);
4601 return 2;
4602 }
4603
4604 case A::kAbsLow14:
4605 case A::kAbsLow16:
4606 {
4607 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4608 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4609 reloc1.set_r_address(address);
4610 if ( isExtern )
4611 reloc1.set_r_symbolnum(symbolIndex);
4612 else
4613 reloc1.set_r_symbolnum(sectionNum);
4614 reloc1.set_r_pcrel(false);
4615 reloc1.set_r_length(2);
4616 reloc1.set_r_extern(isExtern);
4617 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4618 }
4619 else {
4620 sreloc1->set_r_scattered(true);
4621 sreloc1->set_r_pcrel(false);
4622 sreloc1->set_r_length(2);
4623 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4624 sreloc1->set_r_address(address);
4625 sreloc1->set_r_value(target.getAddress());
4626 }
4627 if ( isExtern )
4628 reloc2.set_r_address(ref->getTargetOffset() >> 16);
4629 else
4630 reloc2.set_r_address(toAddr >> 16);
4631 reloc2.set_r_symbolnum(0);
4632 reloc2.set_r_pcrel(false);
4633 reloc2.set_r_length(2);
4634 reloc2.set_r_extern(false);
4635 reloc2.set_r_type(PPC_RELOC_PAIR);
4636 fSectionRelocs.push_back(reloc2);
4637 fSectionRelocs.push_back(reloc1);
4638 return 2;
4639 }
4640
4641 case A::kAbsHigh16:
4642 {
4643 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4644 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4645 reloc1.set_r_address(address);
4646 if ( isExtern )
4647 reloc1.set_r_symbolnum(symbolIndex);
4648 else
4649 reloc1.set_r_symbolnum(sectionNum);
4650 reloc1.set_r_pcrel(false);
4651 reloc1.set_r_length(2);
4652 reloc1.set_r_extern(isExtern);
4653 reloc1.set_r_type(PPC_RELOC_HI16);
4654 }
4655 else {
4656 sreloc1->set_r_scattered(true);
4657 sreloc1->set_r_pcrel(false);
4658 sreloc1->set_r_length(2);
4659 sreloc1->set_r_type(PPC_RELOC_HI16);
4660 sreloc1->set_r_address(address);
4661 sreloc1->set_r_value(target.getAddress());
4662 }
4663 if ( isExtern )
4664 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4665 else
4666 reloc2.set_r_address(toAddr & 0xFFFF);
4667 reloc2.set_r_symbolnum(0);
4668 reloc2.set_r_pcrel(false);
4669 reloc2.set_r_length(2);
4670 reloc2.set_r_extern(false);
4671 reloc2.set_r_type(PPC_RELOC_PAIR);
4672 fSectionRelocs.push_back(reloc2);
4673 fSectionRelocs.push_back(reloc1);
4674 return 2;
4675 }
4676
4677 case A::kAbsHigh16AddLow:
4678 {
4679 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4680 uint32_t overflow = 0;
4681 if ( (toAddr & 0x00008000) != 0 )
4682 overflow = 0x10000;
4683 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4684 reloc1.set_r_address(address);
4685 if ( isExtern )
4686 reloc1.set_r_symbolnum(symbolIndex);
4687 else
4688 reloc1.set_r_symbolnum(sectionNum);
4689 reloc1.set_r_pcrel(false);
4690 reloc1.set_r_length(2);
4691 reloc1.set_r_extern(isExtern);
4692 reloc1.set_r_type(PPC_RELOC_HA16);
4693 }
4694 else {
4695 sreloc1->set_r_scattered(true);
4696 sreloc1->set_r_pcrel(false);
4697 sreloc1->set_r_length(2);
4698 sreloc1->set_r_type(PPC_RELOC_HA16);
4699 sreloc1->set_r_address(address);
4700 sreloc1->set_r_value(target.getAddress());
4701 }
4702 if ( isExtern )
4703 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4704 else
4705 reloc2.set_r_address(toAddr & 0xFFFF);
4706 reloc2.set_r_symbolnum(0);
4707 reloc2.set_r_pcrel(false);
4708 reloc2.set_r_length(2);
4709 reloc2.set_r_extern(false);
4710 reloc2.set_r_type(PPC_RELOC_PAIR);
4711 fSectionRelocs.push_back(reloc2);
4712 fSectionRelocs.push_back(reloc1);
4713 return 2;
4714 }
4715
4716 case A::kDtraceTypeReference:
4717 case A::kDtraceProbe:
4718 // generates no relocs
4719 return 0;
4720 }
4721 return 0;
4722 }
4723
4724
4725
4726 //
4727 // There are cases when an entry in the indirect symbol table is the magic value
4728 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
4729 // the content of the corresponding part of the __nl_symbol_pointer section
4730 // must also change.
4731 //
4732 template <typename A>
4733 bool Writer<A>::indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const
4734 {
4735 // cannot use INDIRECT_SYMBOL_LOCAL to tentative definitions in object files
4736 // because tentative defs don't have addresses
4737 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition )
4738 return false;
4739
4740 // must use INDIRECT_SYMBOL_LOCAL if there is an addend
4741 if ( ref->getTargetOffset() != 0 )
4742 return true;
4743
4744 // don't use INDIRECT_SYMBOL_LOCAL for external symbols
4745 return ! this->shouldExport(ref->getTarget());
4746 }
4747
4748
4749 template <typename A>
4750 void Writer<A>::buildObjectFileFixups()
4751 {
4752 uint32_t relocIndex = 0;
4753 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
4754 const int segCount = segmentInfos.size();
4755 for(int i=0; i < segCount; ++i) {
4756 SegmentInfo* curSegment = segmentInfos[i];
4757 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4758 const int sectionCount = sectionInfos.size();
4759 for(int j=0; j < sectionCount; ++j) {
4760 SectionInfo* curSection = sectionInfos[j];
4761 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
4762 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
4763 if ( ! curSection->fAllZeroFill ) {
4764 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4765 || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
4766 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
4767 curSection->fRelocOffset = relocIndex;
4768 const int atomCount = sectionAtoms.size();
4769 for (int k=0; k < atomCount; ++k) {
4770 ObjectFile::Atom* atom = sectionAtoms[k];
4771 //fprintf(stderr, "buildObjectFileFixups(): atom %s has %lu references\n", atom->getDisplayName(), atom->getReferences().size());
4772 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
4773 const int refCount = refs.size();
4774 for (int l=0; l < refCount; ++l) {
4775 ObjectFile::Reference* ref = refs[l];
4776 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4777 || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
4778 uint32_t offsetInSection = atom->getSectionOffset();
4779 uint32_t indexInSection = offsetInSection / atom->getSize();
4780 uint32_t undefinedSymbolIndex;
4781 if ( curSection->fAllStubs ) {
4782 ObjectFile::Atom& stubTarget =ref->getTarget();
4783 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
4784 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
4785 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
4786 }
4787 else if ( curSection->fAllNonLazyPointers) {
4788 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
4789 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
4790 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4791 else
4792 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
4793 }
4794 else {
4795 // should never get here, fAllLazyPointers not used in generated .o files
4796 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4797 }
4798 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
4799 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
4800 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
4801 fIndirectTableAtom->fTable.push_back(entry);
4802 if ( curSection->fAllLazyPointers ) {
4803 ObjectFile::Atom& target = ref->getTarget();
4804 ObjectFile::Atom& fromTarget = ref->getFromTarget();
4805 if ( &fromTarget == NULL ) {
4806 warning("lazy pointer %s missing initial binding", atom->getDisplayName());
4807 }
4808 else {
4809 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
4810 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
4811 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
4812 macho_relocation_info<P> reloc1;
4813 reloc1.set_r_address(atom->getSectionOffset());
4814 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
4815 reloc1.set_r_pcrel(false);
4816 reloc1.set_r_length();
4817 reloc1.set_r_extern(isExtern);
4818 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4819 fSectionRelocs.push_back(reloc1);
4820 ++relocIndex;
4821 }
4822 }
4823 else if ( curSection->fAllStubs ) {
4824 relocIndex += this->addObjectRelocs(atom, ref);
4825 }
4826 }
4827 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
4828 relocIndex += this->addObjectRelocs(atom, ref);
4829 }
4830 }
4831 }
4832 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
4833 }
4834 }
4835 }
4836
4837 // reverse the relocs
4838 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
4839
4840 // now reverse section reloc offsets
4841 for(int i=0; i < segCount; ++i) {
4842 SegmentInfo* curSegment = segmentInfos[i];
4843 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4844 const int sectionCount = sectionInfos.size();
4845 for(int j=0; j < sectionCount; ++j) {
4846 SectionInfo* curSection = sectionInfos[j];
4847 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
4848 }
4849 }
4850
4851 }
4852
4853
4854 template <>
4855 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
4856 {
4857 uint64_t result;
4858 if ( fOptions.outputKind() == Options::kKextBundle ) {
4859 // for x86_64 kext bundles, the r_address field in relocs
4860 // is the offset from the start address of the first segment
4861 result = address - fSegmentInfos[0]->fBaseAddress;
4862 if ( result > 0xFFFFFFFF ) {
4863 throwf("kext bundle too large: address can't fit in 31-bit r_address field in %s from %s",
4864 atom->getDisplayName(), atom->getFile()->getPath());
4865 }
4866 }
4867 else {
4868 // for x86_64, the r_address field in relocs for final linked images
4869 // is the offset from the start address of the first writable segment
4870 result = address - fFirstWritableSegment->fBaseAddress;
4871 if ( result > 0xFFFFFFFF ) {
4872 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
4873 throwf("text relocs not supported for x86_64 in %s from %s",
4874 atom->getDisplayName(), atom->getFile()->getPath());
4875 else
4876 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
4877 atom->getDisplayName(), atom->getFile()->getPath());
4878 }
4879 }
4880 return result;
4881 }
4882
4883
4884 template <>
4885 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4886 {
4887 switch ( ref.getKind() ) {
4888 case ppc::kAbsLow16:
4889 case ppc::kAbsLow14:
4890 case ppc::kAbsHigh16:
4891 case ppc::kAbsHigh16AddLow:
4892 if ( fSlideable )
4893 return true;
4894 }
4895 return false;
4896 }
4897
4898
4899 template <>
4900 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4901 {
4902 switch ( ref.getKind() ) {
4903 case ppc::kAbsLow16:
4904 case ppc::kAbsLow14:
4905 case ppc::kAbsHigh16:
4906 case ppc::kAbsHigh16AddLow:
4907 if ( fSlideable )
4908 return true;
4909 }
4910 return false;
4911 }
4912
4913 template <>
4914 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4915 {
4916 if ( ref.getKind() == x86::kAbsolute32 ) {
4917 switch ( ref.getTarget().getDefinitionKind() ) {
4918 case ObjectFile::Atom::kTentativeDefinition:
4919 case ObjectFile::Atom::kRegularDefinition:
4920 case ObjectFile::Atom::kWeakDefinition:
4921 // illegal in dylibs/bundles, until we support TEXT relocs
4922 return fSlideable;
4923 case ObjectFile::Atom::kExternalDefinition:
4924 case ObjectFile::Atom::kExternalWeakDefinition:
4925 // illegal until we support TEXT relocs
4926 return true;
4927 case ObjectFile::Atom::kAbsoluteSymbol:
4928 // absolute symbbols only allowed in static executables
4929 return ( fOptions.outputKind() != Options::kStaticExecutable);
4930 }
4931 }
4932 return false;
4933 }
4934
4935 template <>
4936 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4937 {
4938 if ( fOptions.outputKind() == Options::kKextBundle ) {
4939 switch ( ref.getTarget().getDefinitionKind() ) {
4940 case ObjectFile::Atom::kTentativeDefinition:
4941 case ObjectFile::Atom::kRegularDefinition:
4942 case ObjectFile::Atom::kWeakDefinition:
4943 case ObjectFile::Atom::kAbsoluteSymbol:
4944 return false;
4945 case ObjectFile::Atom::kExternalDefinition:
4946 case ObjectFile::Atom::kExternalWeakDefinition:
4947 // true means we need a TEXT relocs
4948 switch ( ref.getKind() ) {
4949 case x86_64::kBranchPCRel32:
4950 case x86_64::kBranchPCRel32WeakImport:
4951 case x86_64::kPCRel32GOTLoad:
4952 case x86_64::kPCRel32GOTLoadWeakImport:
4953 case x86_64::kPCRel32GOT:
4954 case x86_64::kPCRel32GOTWeakImport:
4955 return true;
4956 }
4957 break;
4958 }
4959 }
4960 return false;
4961 }
4962
4963 template <>
4964 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4965 {
4966 switch ( fOptions.outputKind()) {
4967 case Options::kStaticExecutable:
4968 case Options::kPreload:
4969 // all relocations allowed in static executables
4970 return false;
4971 default:
4972 break;
4973 }
4974 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4975 switch ( ref.getTarget().getDefinitionKind() ) {
4976 case ObjectFile::Atom::kTentativeDefinition:
4977 case ObjectFile::Atom::kRegularDefinition:
4978 case ObjectFile::Atom::kWeakDefinition:
4979 // illegal in dylibs/bundles, until we support TEXT relocs
4980 return fSlideable;
4981 case ObjectFile::Atom::kExternalDefinition:
4982 case ObjectFile::Atom::kExternalWeakDefinition:
4983 // illegal until we support TEXT relocs
4984 return true;
4985 case ObjectFile::Atom::kAbsoluteSymbol:
4986 // absolute symbbols only allowed in static executables
4987 return true;
4988 }
4989 }
4990 return false;
4991 }
4992
4993 template <>
4994 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4995 {
4996 if ( ref.getKind() == x86::kAbsolute32 ) {
4997 switch ( ref.getTarget().getDefinitionKind() ) {
4998 case ObjectFile::Atom::kTentativeDefinition:
4999 case ObjectFile::Atom::kRegularDefinition:
5000 case ObjectFile::Atom::kWeakDefinition:
5001 // a reference to the absolute address of something in this same linkage unit can be
5002 // encoded as a local text reloc in a dylib or bundle
5003 if ( fSlideable ) {
5004 macho_relocation_info<P> reloc;
5005 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
5006 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5007 reloc.set_r_symbolnum(sectInfo->getIndex());
5008 reloc.set_r_pcrel(false);
5009 reloc.set_r_length();
5010 reloc.set_r_extern(false);
5011 reloc.set_r_type(GENERIC_RELOC_VANILLA);
5012 fInternalRelocs.push_back(reloc);
5013 atomSection->fHasTextLocalRelocs = true;
5014 if ( fOptions.makeCompressedDyldInfo() ) {
5015 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
5016 }
5017 return true;
5018 }
5019 return false;
5020 case ObjectFile::Atom::kExternalDefinition:
5021 case ObjectFile::Atom::kExternalWeakDefinition:
5022 case ObjectFile::Atom::kAbsoluteSymbol:
5023 return false;
5024 }
5025 }
5026 return false;
5027 }
5028
5029 template <>
5030 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
5031 {
5032 macho_relocation_info<P> reloc1;
5033 macho_relocation_info<P> reloc2;
5034 switch ( ref.getTarget().getDefinitionKind() ) {
5035 case ObjectFile::Atom::kTentativeDefinition:
5036 case ObjectFile::Atom::kRegularDefinition:
5037 case ObjectFile::Atom::kWeakDefinition:
5038 switch ( ref.getKind() ) {
5039 case ppc::kAbsLow16:
5040 case ppc::kAbsLow14:
5041 // a reference to the absolute address of something in this same linkage unit can be
5042 // encoded as a local text reloc in a dylib or bundle
5043 if ( fSlideable ) {
5044 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
5045 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
5046 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5047 reloc1.set_r_symbolnum(sectInfo->getIndex());
5048 reloc1.set_r_pcrel(false);
5049 reloc1.set_r_length(2);
5050 reloc1.set_r_extern(false);
5051 reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
5052 reloc2.set_r_address(targetAddr >> 16);
5053 reloc2.set_r_symbolnum(0);
5054 reloc2.set_r_pcrel(false);
5055 reloc2.set_r_length(2);
5056 reloc2.set_r_extern(false);
5057 reloc2.set_r_type(PPC_RELOC_PAIR);
5058 fInternalRelocs.push_back(reloc1);
5059 fInternalRelocs.push_back(reloc2);
5060 atomSection->fHasTextLocalRelocs = true;
5061 return true;
5062 }
5063 break;
5064 case ppc::kAbsHigh16:
5065 case ppc::kAbsHigh16AddLow:
5066 if ( fSlideable ) {
5067 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
5068 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
5069 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5070 reloc1.set_r_symbolnum(sectInfo->getIndex());
5071 reloc1.set_r_pcrel(false);
5072 reloc1.set_r_length(2);
5073 reloc1.set_r_extern(false);
5074 reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
5075 reloc2.set_r_address(targetAddr & 0xFFFF);
5076 reloc2.set_r_symbolnum(0);
5077 reloc2.set_r_pcrel(false);
5078 reloc2.set_r_length(2);
5079 reloc2.set_r_extern(false);
5080 reloc2.set_r_type(PPC_RELOC_PAIR);
5081 fInternalRelocs.push_back(reloc1);
5082 fInternalRelocs.push_back(reloc2);
5083 atomSection->fHasTextLocalRelocs = true;
5084 return true;
5085 }
5086 }
5087 break;
5088 case ObjectFile::Atom::kExternalDefinition:
5089 case ObjectFile::Atom::kExternalWeakDefinition:
5090 case ObjectFile::Atom::kAbsoluteSymbol:
5091 return false;
5092 }
5093 return false;
5094 }
5095
5096 template <>
5097 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
5098 {
5099 if ( ref.getKind() == arm::kReadOnlyPointer ) {
5100 switch ( ref.getTarget().getDefinitionKind() ) {
5101 case ObjectFile::Atom::kTentativeDefinition:
5102 case ObjectFile::Atom::kRegularDefinition:
5103 case ObjectFile::Atom::kWeakDefinition:
5104 // a reference to the absolute address of something in this same linkage unit can be
5105 // encoded as a local text reloc in a dylib or bundle
5106 if ( fSlideable ) {
5107 macho_relocation_info<P> reloc;
5108 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
5109 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5110 reloc.set_r_symbolnum(sectInfo->getIndex());
5111 reloc.set_r_pcrel(false);
5112 reloc.set_r_length();
5113 reloc.set_r_extern(false);
5114 reloc.set_r_type(GENERIC_RELOC_VANILLA);
5115 fInternalRelocs.push_back(reloc);
5116 atomSection->fHasTextLocalRelocs = true;
5117 if ( fOptions.makeCompressedDyldInfo() ) {
5118 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
5119 }
5120 return true;
5121 }
5122 return false;
5123 case ObjectFile::Atom::kExternalDefinition:
5124 case ObjectFile::Atom::kExternalWeakDefinition:
5125 case ObjectFile::Atom::kAbsoluteSymbol:
5126 return false;
5127 }
5128 }
5129 return false;
5130 }
5131
5132
5133 template <>
5134 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5135 {
5136 // text relocs not supported (usually never needed because of RIP addressing)
5137 return false;
5138 }
5139
5140 template <>
5141 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5142 {
5143 // text relocs not supported
5144 return false;
5145 }
5146
5147 template <>
5148 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
5149 {
5150 if ( ref.getKind() == x86::kAbsolute32 ) {
5151 macho_relocation_info<P> reloc;
5152 switch ( ref.getTarget().getDefinitionKind() ) {
5153 case ObjectFile::Atom::kTentativeDefinition:
5154 case ObjectFile::Atom::kRegularDefinition:
5155 case ObjectFile::Atom::kWeakDefinition:
5156 return false;
5157 case ObjectFile::Atom::kExternalDefinition:
5158 case ObjectFile::Atom::kExternalWeakDefinition:
5159 // a reference to the absolute address of something in another linkage unit can be
5160 // encoded as an external text reloc in a dylib or bundle
5161 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5162 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
5163 reloc.set_r_pcrel(false);
5164 reloc.set_r_length();
5165 reloc.set_r_extern(true);
5166 reloc.set_r_type(GENERIC_RELOC_VANILLA);
5167 fExternalRelocs.push_back(reloc);
5168 atomSection->fHasTextExternalRelocs = true;
5169 return true;
5170 case ObjectFile::Atom::kAbsoluteSymbol:
5171 return false;
5172 }
5173 }
5174 return false;
5175 }
5176
5177 template <>
5178 bool Writer<x86_64>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
5179 {
5180 if ( fOptions.outputKind() == Options::kKextBundle ) {
5181 macho_relocation_info<P> reloc;
5182 switch ( ref.getTarget().getDefinitionKind() ) {
5183 case ObjectFile::Atom::kTentativeDefinition:
5184 case ObjectFile::Atom::kRegularDefinition:
5185 case ObjectFile::Atom::kWeakDefinition:
5186 case ObjectFile::Atom::kAbsoluteSymbol:
5187 return false;
5188 case ObjectFile::Atom::kExternalDefinition:
5189 case ObjectFile::Atom::kExternalWeakDefinition:
5190 switch ( ref.getKind() ) {
5191 case x86_64::kBranchPCRel32:
5192 case x86_64::kBranchPCRel32WeakImport:
5193 // a branch to something in another linkage unit is
5194 // encoded as an external text reloc in a kext bundle
5195 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5196 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
5197 reloc.set_r_pcrel(true);
5198 reloc.set_r_length(2);
5199 reloc.set_r_extern(true);
5200 reloc.set_r_type(X86_64_RELOC_BRANCH);
5201 fExternalRelocs.push_back(reloc);
5202 atomSection->fHasTextExternalRelocs = true;
5203 return true;
5204 case x86_64::kPCRel32GOTLoad:
5205 case x86_64::kPCRel32GOTLoadWeakImport:
5206 // a load of the GOT entry for a symbol in another linkage unit is
5207 // encoded as an external text reloc in a kext bundle
5208 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5209 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
5210 reloc.set_r_pcrel(true);
5211 reloc.set_r_length(2);
5212 reloc.set_r_extern(true);
5213 reloc.set_r_type(X86_64_RELOC_GOT_LOAD);
5214 fExternalRelocs.push_back(reloc);
5215 atomSection->fHasTextExternalRelocs = true;
5216 return true;
5217 case x86_64::kPCRel32GOT:
5218 case x86_64::kPCRel32GOTWeakImport:
5219 // a use of the GOT entry for a symbol in another linkage unit is
5220 // encoded as an external text reloc in a kext bundle
5221 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5222 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
5223 reloc.set_r_pcrel(true);
5224 reloc.set_r_length(2);
5225 reloc.set_r_extern(true);
5226 reloc.set_r_type(X86_64_RELOC_GOT);
5227 fExternalRelocs.push_back(reloc);
5228 atomSection->fHasTextExternalRelocs = true;
5229 return true;
5230 }
5231 break;
5232 }
5233 }
5234 return false;
5235 }
5236
5237
5238 template <typename A>
5239 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5240 {
5241 return false;
5242 }
5243
5244
5245
5246
5247 template <typename A>
5248 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
5249 {
5250 switch ( target.getDefinitionKind() ) {
5251 case ObjectFile::Atom::kTentativeDefinition:
5252 case ObjectFile::Atom::kRegularDefinition:
5253 // in main executables, the only way regular symbols are indirected is if -interposable is used
5254 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
5255 if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
5256 return kRelocExternal;
5257 else if ( fSlideable )
5258 return kRelocInternal;
5259 else
5260 return kRelocNone;
5261 }
5262 // for flat-namespace or interposable two-level-namespace
5263 // all references to exported symbols get indirected
5264 else if ( this->shouldExport(target) &&
5265 ((fOptions.nameSpace() == Options::kFlatNameSpace)
5266 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
5267 || fOptions.interposable(target.getName()))
5268 && (target.getName() != NULL)
5269 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
5270 return kRelocExternal;
5271 else if ( fSlideable )
5272 return kRelocInternal;
5273 else
5274 return kRelocNone;
5275 case ObjectFile::Atom::kWeakDefinition:
5276 // all calls to global weak definitions get indirected
5277 if ( this->shouldExport(target) )
5278 return kRelocExternal;
5279 else if ( fSlideable )
5280 return kRelocInternal;
5281 else
5282 return kRelocNone;
5283 case ObjectFile::Atom::kExternalDefinition:
5284 case ObjectFile::Atom::kExternalWeakDefinition:
5285 return kRelocExternal;
5286 case ObjectFile::Atom::kAbsoluteSymbol:
5287 return kRelocNone;
5288 }
5289 return kRelocNone;
5290 }
5291
5292 template <typename A>
5293 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5294 {
5295 // for 32-bit architectures, the r_address field in relocs
5296 // for final linked images is the offset from the first segment
5297 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
5298 if ( fOptions.outputKind() == Options::kPreload ) {
5299 // kPreload uses a virtual __HEADER segment to cover the load commands
5300 result = address - fSegmentInfos[1]->fBaseAddress;
5301 }
5302 // or the offset from the first writable segment if built split-seg
5303 if ( fOptions.splitSeg() )
5304 result = address - fFirstWritableSegment->fBaseAddress;
5305 if ( result > 0x7FFFFFFF ) {
5306 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
5307 atom->getDisplayName(), atom->getFile()->getPath());
5308 }
5309 return result;
5310 }
5311
5312 template <>
5313 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5314 {
5315 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
5316 // the 10.5 dyld, iterprets the r_address as:
5317 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
5318 // 2) an offset from the base address of the first writable segment
5319 // For dyld, r_address is always the offset from the base address
5320 uint64_t result;
5321 bool badFor10_4 = false;
5322 if ( fWritableSegmentPastFirst4GB ) {
5323 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
5324 badFor10_4 = true;
5325 result = address - fFirstWritableSegment->fBaseAddress;
5326 if ( result > 0xFFFFFFFF ) {
5327 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
5328 atom->getDisplayName(), atom->getFile()->getPath());
5329 }
5330 }
5331 else {
5332 result = address - fSegmentInfos[0]->fBaseAddress;
5333 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
5334 badFor10_4 = true;
5335 }
5336 if ( badFor10_4 ) {
5337 throwf("image or pagezero_size too large for Mac OS X 10.4: address can't fit in 31-bit r_address field for %s from %s",
5338 atom->getDisplayName(), atom->getFile()->getPath());
5339 }
5340 return result;
5341 }
5342
5343
5344 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
5345 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5346 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
5347 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5348 template <> bool Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
5349
5350 template <typename A>
5351 void Writer<A>::buildExecutableFixups()
5352 {
5353 if ( fIndirectTableAtom != NULL )
5354 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
5355 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
5356 const int segCount = segmentInfos.size();
5357 for(int i=0; i < segCount; ++i) {
5358 SegmentInfo* curSegment = segmentInfos[i];
5359 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5360 const int sectionCount = sectionInfos.size();
5361 for(int j=0; j < sectionCount; ++j) {
5362 SectionInfo* curSection = sectionInfos[j];
5363 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
5364 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5365 if ( ! curSection->fAllZeroFill ) {
5366 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers
5367 || curSection->fAllStubs || curSection->fAllSelfModifyingStubs ) {
5368 if ( fIndirectTableAtom != NULL )
5369 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
5370 }
5371 const int atomCount = sectionAtoms.size();
5372 for (int k=0; k < atomCount; ++k) {
5373 ObjectFile::Atom* atom = sectionAtoms[k];
5374 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
5375 const int refCount = refs.size();
5376 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
5377 if ( curSection->fAllNonLazyPointers && (refCount == 0) ) {
5378 // handle imageloadercache GOT slot
5379 uint32_t offsetInSection = atom->getSectionOffset();
5380 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5381 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5382 // use INDIRECT_SYMBOL_ABS so 10.5 dyld will leave value as zero
5383 IndirectEntry entry = { indirectTableIndex, INDIRECT_SYMBOL_ABS };
5384 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5385 // indirectTableIndex, INDIRECT_SYMBOL_LOCAL, curSection->fSectionName);
5386 fIndirectTableAtom->fTable.push_back(entry);
5387 }
5388 for (int l=0; l < refCount; ++l) {
5389 ObjectFile::Reference* ref = refs[l];
5390 if ( (fOptions.outputKind() != Options::kKextBundle) &&
5391 (curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers) ) {
5392 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
5393 if ( atom->getSize() != sizeof(pint_t) ) {
5394 warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
5395 }
5396 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
5397 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5398 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
5399 }
5400 uint32_t offsetInSection = atom->getSectionOffset();
5401 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5402 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
5403 if (atom == fFastStubGOTAtom)
5404 undefinedSymbolIndex = INDIRECT_SYMBOL_ABS;
5405 else if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
5406 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
5407 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5408 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5409 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5410 // indirectTableIndex, undefinedSymbolIndex, curSection->fSectionName);
5411 fIndirectTableAtom->fTable.push_back(entry);
5412 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5413 uint8_t preboundLazyType;
5414 if ( fOptions.prebind() && (fDyldClassicHelperAtom != NULL)
5415 && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
5416 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
5417 macho_scattered_relocation_info<P> pblaReloc;
5418 pblaReloc.set_r_scattered(true);
5419 pblaReloc.set_r_pcrel(false);
5420 pblaReloc.set_r_length();
5421 pblaReloc.set_r_type(preboundLazyType);
5422 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5423 pblaReloc.set_r_value(fDyldClassicHelperAtom->getAddress());
5424 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
5425 }
5426 else if ( fSlideable ) {
5427 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
5428 macho_relocation_info<P> dyldHelperReloc;
5429 uint32_t sectionNum = 1;
5430 if ( fDyldClassicHelperAtom != NULL )
5431 sectionNum = ((SectionInfo*)(fDyldClassicHelperAtom->getSection()))->getIndex();
5432 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
5433 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5434 dyldHelperReloc.set_r_symbolnum(sectionNum);
5435 dyldHelperReloc.set_r_pcrel(false);
5436 dyldHelperReloc.set_r_length();
5437 dyldHelperReloc.set_r_extern(false);
5438 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
5439 fInternalRelocs.push_back(dyldHelperReloc);
5440 if ( fOptions.makeCompressedDyldInfo() ) {
5441 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5442 }
5443 }
5444 if ( fOptions.makeCompressedDyldInfo() ) {
5445 uint8_t type = BIND_TYPE_POINTER;
5446 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5447 if ( pointerTarget->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5448 // This is a referece to a weak def in some dylib (e.g. operator new)
5449 // need to bind into to directly bind this
5450 // later weak binding info may override
5451 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5452 fBindingInfo.push_back(BindingInfo(type, ordinal, pointerTarget->getName(), false, addresss, 0));
5453 }
5454 if ( targetRequiresWeakBinding(*pointerTarget) ) {
5455 // note: lazy pointers to weak symbols are not bound lazily
5456 fWeakBindingInfo.push_back(BindingInfo(type, pointerTarget->getName(), false, addresss, 0));
5457 }
5458 }
5459 }
5460 if ( curSection->fAllNonLazyPointers && fOptions.makeCompressedDyldInfo() ) {
5461 if ( pointerTarget != NULL ) {
5462 switch ( this->relocationNeededInFinalLinkedImage(*pointerTarget) ) {
5463 case kRelocNone:
5464 // no rebase or binding info needed
5465 break;
5466 case kRelocInternal:
5467 // a non-lazy pointer that has been optimized to LOCAL needs rebasing info
5468 // but not the magic fFastStubGOTAtom atom
5469 if (atom != fFastStubGOTAtom)
5470 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5471 break;
5472 case kRelocExternal:
5473 {
5474 uint8_t type = BIND_TYPE_POINTER;
5475 uint64_t addresss = atom->getAddress();
5476 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5477 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, 0));
5478 // if this is a non-lazy pointer to a weak definition within this linkage unit
5479 // the pointer needs to initially point within linkage unit and have
5480 // rebase command to slide it.
5481 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5482 // unless if this is a hybrid format, in which case the non-lazy pointer
5483 // is zero on disk. So use a bind instead of a rebase to set initial value
5484 if ( fOptions.makeClassicDyldInfo() )
5485 fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, 0));
5486 else
5487 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5488 }
5489 // if this is a non-lazy pointer to a weak definition in a dylib,
5490 // the pointer needs to initially bind to the dylib
5491 else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5492 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5493 fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, pointerTarget->getName(), false, addresss, 0));
5494 }
5495 }
5496 else {
5497 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5498 bool weak_import = fWeakImportMap[pointerTarget];
5499 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, 0));
5500 }
5501 }
5502 }
5503 }
5504 }
5505 }
5506 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
5507 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
5508 if ( fOptions.allowTextRelocs() ) {
5509 if ( fOptions.warnAboutTextRelocs() )
5510 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5511 }
5512 else {
5513 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
5514 atom->getDisplayName(), atom->getFile()->getPath());
5515 }
5516 }
5517 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
5518 case kRelocNone:
5519 // no reloc needed
5520 break;
5521 case kRelocInternal:
5522 {
5523 macho_relocation_info<P> internalReloc;
5524 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
5525 uint32_t sectionNum = sectInfo->getIndex();
5526 // special case _mh_dylib_header and friends which are not in any real section
5527 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
5528 sectionNum = 1;
5529 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5530 internalReloc.set_r_symbolnum(sectionNum);
5531 internalReloc.set_r_pcrel(false);
5532 internalReloc.set_r_length();
5533 internalReloc.set_r_extern(false);
5534 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5535 fInternalRelocs.push_back(internalReloc);
5536 if ( fOptions.makeCompressedDyldInfo() ) {
5537 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, atom->getAddress() + ref->getFixUpOffset()));
5538 }
5539 }
5540 break;
5541 case kRelocExternal:
5542 {
5543 macho_relocation_info<P> externalReloc;
5544 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5545 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
5546 externalReloc.set_r_pcrel(false);
5547 externalReloc.set_r_length();
5548 externalReloc.set_r_extern(true);
5549 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5550 fExternalRelocs.push_back(externalReloc);
5551 if ( fOptions.makeCompressedDyldInfo() ) {
5552 int64_t addend = ref->getTargetOffset();
5553 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5554 if ( !fOptions.makeClassicDyldInfo() ) {
5555 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5556 // pointers to internal weak defs need a rebase
5557 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, addresss));
5558 }
5559 }
5560 uint8_t type = BIND_TYPE_POINTER;
5561 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5562 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, addend));
5563 if ( fOptions.makeClassicDyldInfo() && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
5564 // hybrid linkedit puts addend in data, so we need bind phase to reset pointer to local definifion
5565 fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, addend));
5566 }
5567 // if this is a pointer to a weak definition in a dylib,
5568 // the pointer needs to initially bind to the dylib
5569 else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5570 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5571 fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, ref->getTarget().getName(), false, addresss, addend));
5572 }
5573 }
5574 else {
5575 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5576 bool weak_import = fWeakImportMap[&(ref->getTarget())];
5577 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, addend));
5578 }
5579 }
5580 }
5581 break;
5582 }
5583 }
5584 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
5585 // new x86 stubs always require text relocs
5586 if ( curSection->fAllStubs || curSection->fAllStubHelpers ) {
5587 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5588 // relocs added to fInternalRelocs
5589 }
5590 }
5591 else if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
5592 if ( fOptions.warnAboutTextRelocs() )
5593 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5594 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5595 // relocs added to fInternalRelocs
5596 }
5597 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
5598 // relocs added to fExternalRelocs
5599 }
5600 else {
5601 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
5602 }
5603 }
5604 else {
5605 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
5606 "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
5607 }
5608 }
5609 }
5610 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
5611 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
5612 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
5613 uint32_t offsetInSection = atom->getSectionOffset();
5614 uint32_t indexInSection = offsetInSection / atom->getSize();
5615 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5616 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5617 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
5618 fIndirectTableAtom->fTable.push_back(entry);
5619 }
5620 }
5621 }
5622 }
5623 }
5624 if ( fSplitCodeToDataContentAtom != NULL )
5625 fSplitCodeToDataContentAtom->encode();
5626 if ( fCompressedRebaseInfoAtom != NULL )
5627 fCompressedRebaseInfoAtom->encode();
5628 if ( fCompressedBindingInfoAtom != NULL )
5629 fCompressedBindingInfoAtom->encode();
5630 if ( fCompressedWeakBindingInfoAtom != NULL )
5631 fCompressedWeakBindingInfoAtom->encode();
5632 if ( fCompressedLazyBindingInfoAtom != NULL )
5633 fCompressedLazyBindingInfoAtom->encode();
5634 if ( fCompressedExportInfoAtom != NULL )
5635 fCompressedExportInfoAtom->encode();
5636 }
5637
5638
5639 template <>
5640 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5641 {
5642 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
5643 case ppc::kPICBaseHigh16:
5644 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5645 break;
5646 case ppc::kPointerDiff32:
5647 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5648 break;
5649 case ppc::kPointerDiff64:
5650 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5651 break;
5652 case ppc::kNoFixUp:
5653 case ppc::kGroupSubordinate:
5654 case ppc::kPointer:
5655 case ppc::kPointerWeakImport:
5656 case ppc::kPICBaseLow16:
5657 case ppc::kPICBaseLow14:
5658 // ignore
5659 break;
5660 default:
5661 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5662 fSplitCodeToDataContentAtom->setCantEncode();
5663 }
5664 }
5665
5666 template <>
5667 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5668 {
5669 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
5670 case ppc64::kPICBaseHigh16:
5671 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5672 break;
5673 case ppc64::kPointerDiff32:
5674 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5675 break;
5676 case ppc64::kPointerDiff64:
5677 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5678 break;
5679 case ppc64::kNoFixUp:
5680 case ppc64::kGroupSubordinate:
5681 case ppc64::kPointer:
5682 case ppc64::kPointerWeakImport:
5683 case ppc64::kPICBaseLow16:
5684 case ppc64::kPICBaseLow14:
5685 // ignore
5686 break;
5687 default:
5688 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5689 fSplitCodeToDataContentAtom->setCantEncode();
5690 }
5691 }
5692
5693 template <>
5694 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5695 {
5696 switch ( (x86::ReferenceKinds)ref->getKind() ) {
5697 case x86::kPointerDiff:
5698 case x86::kImageOffset32:
5699 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
5700 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5701 else
5702 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5703 break;
5704 case x86::kNoFixUp:
5705 case x86::kGroupSubordinate:
5706 case x86::kPointer:
5707 case x86::kPointerWeakImport:
5708 // ignore
5709 break;
5710 case x86::kPCRel32:
5711 case x86::kPCRel32WeakImport:
5712 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
5713 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
5714 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5715 break;
5716 }
5717 // fall into warning case
5718 default:
5719 if ( fOptions.makeCompressedDyldInfo() && (ref->getKind() == x86::kAbsolute32) ) {
5720 // will be encoded in rebase info
5721 }
5722 else {
5723 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
5724 fSplitCodeToDataContentAtom->setCantEncode();
5725 }
5726 }
5727 }
5728
5729 template <>
5730 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5731 {
5732 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
5733 case x86_64::kPCRel32:
5734 case x86_64::kPCRel32_1:
5735 case x86_64::kPCRel32_2:
5736 case x86_64::kPCRel32_4:
5737 case x86_64::kPCRel32GOTLoad:
5738 case x86_64::kPCRel32GOTLoadWeakImport:
5739 case x86_64::kPCRel32GOT:
5740 case x86_64::kPCRel32GOTWeakImport:
5741 case x86_64::kPointerDiff32:
5742 case x86_64::kImageOffset32:
5743 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5744 break;
5745 case x86_64::kPointerDiff:
5746 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5747 break;
5748 case x86_64::kNoFixUp:
5749 case x86_64::kGroupSubordinate:
5750 case x86_64::kPointer:
5751 case x86_64::kGOTNoFixUp:
5752 // ignore
5753 break;
5754 default:
5755 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
5756 fSplitCodeToDataContentAtom->setCantEncode();
5757 }
5758 }
5759
5760 template <>
5761 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5762 {
5763 switch ( (arm::ReferenceKinds)ref->getKind() ) {
5764 case arm::kPointerDiff:
5765 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5766 break;
5767 case arm::kNoFixUp:
5768 case arm::kGroupSubordinate:
5769 case arm::kPointer:
5770 case arm::kPointerWeakImport:
5771 case arm::kReadOnlyPointer:
5772 // ignore
5773 break;
5774 default:
5775 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
5776 fSplitCodeToDataContentAtom->setCantEncode();
5777 }
5778 }
5779
5780 template <typename A>
5781 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
5782 {
5783 switch ( to.getDefinitionKind() ) {
5784 case ObjectFile::Atom::kExternalDefinition:
5785 case ObjectFile::Atom::kExternalWeakDefinition:
5786 case ObjectFile::Atom::kAbsoluteSymbol:
5787 return false;
5788 case ObjectFile::Atom::kRegularDefinition:
5789 case ObjectFile::Atom::kWeakDefinition:
5790 case ObjectFile::Atom::kTentativeDefinition:
5791 // segments with same permissions slide together
5792 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
5793 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
5794 }
5795 throw "ld64 internal error";
5796 }
5797
5798
5799 template <>
5800 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
5801 {
5802 uint32_t ppcNop;
5803 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5804 for (uint32_t p=from; p < to; p += 4)
5805 ::pwrite(fd, &ppcNop, 4, p);
5806 }
5807
5808 template <>
5809 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5810 {
5811 uint32_t ppcNop;
5812 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5813 for (uint32_t p=from; p < to; p += 4)
5814 ::pwrite(fd, &ppcNop, 4, p);
5815 }
5816
5817 template <>
5818 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
5819 {
5820 uint8_t x86Nop = 0x90;
5821 for (uint32_t p=from; p < to; ++p)
5822 ::pwrite(fd, &x86Nop, 1, p);
5823 }
5824
5825 template <>
5826 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5827 {
5828 uint8_t x86Nop = 0x90;
5829 for (uint32_t p=from; p < to; ++p)
5830 ::pwrite(fd, &x86Nop, 1, p);
5831 }
5832
5833 template <>
5834 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
5835 {
5836 // FIXME: need thumb nop?
5837 uint32_t armNop;
5838 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
5839 for (uint32_t p=from; p < to; p += 4)
5840 ::pwrite(fd, &armNop, 4, p);
5841 }
5842
5843 template <>
5844 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
5845 {
5846 for (uint8_t* p=from; p < to; p += 4)
5847 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5848 }
5849
5850 template <>
5851 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
5852 {
5853 for (uint8_t* p=from; p < to; p += 4)
5854 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5855 }
5856
5857 template <>
5858 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
5859 {
5860 for (uint8_t* p=from; p < to; ++p)
5861 *p = 0x90;
5862 }
5863
5864 template <>
5865 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
5866 {
5867 for (uint8_t* p=from; p < to; ++p)
5868 *p = 0x90;
5869 }
5870
5871 template <>
5872 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
5873 {
5874 // fixme: need thumb nop?
5875 for (uint8_t* p=from; p < to; p += 4)
5876 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
5877 }
5878
5879 static const char* stringName(const char* str)
5880 {
5881 if ( strncmp(str, "cstring=", 8) == 0) {
5882 static char buffer[1024];
5883 char* t = buffer;
5884 *t++ = '\"';
5885 for(const char*s = &str[8]; *s != '\0'; ++s) {
5886 switch(*s) {
5887 case '\n':
5888 *t++ = '\\';
5889 *t++ = 'n';
5890 break;
5891 case '\t':
5892 *t++ = '\\';
5893 *t++ = 't';
5894 break;
5895 default:
5896 *t++ = *s;
5897 break;
5898 }
5899 if ( t > &buffer[1020] ) {
5900 *t++= '\"';
5901 *t++= '.';
5902 *t++= '.';
5903 *t++= '.';
5904 *t++= '\0';
5905 return buffer;
5906 }
5907 }
5908 *t++= '\"';
5909 *t++= '\0';
5910 return buffer;
5911 }
5912 else {
5913 return str;
5914 }
5915 }
5916
5917
5918 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
5919 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
5920 template <> const char* Writer<x86>::getArchString() { return "i386"; }
5921 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
5922 template <> const char* Writer<arm>::getArchString() { return "arm"; }
5923
5924 template <typename A>
5925 void Writer<A>::writeMap()
5926 {
5927 if ( fOptions.generatedMapPath() != NULL ) {
5928 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
5929 if ( mapFile != NULL ) {
5930 // write output path
5931 fprintf(mapFile, "# Path: %s\n", fFilePath);
5932 // write output architecure
5933 fprintf(mapFile, "# Arch: %s\n", getArchString());
5934 // write UUID
5935 if ( fUUIDAtom != NULL ) {
5936 const uint8_t* uuid = fUUIDAtom->getUUID();
5937 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
5938 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
5939 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
5940 }
5941 // write table of object files
5942 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
5943 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
5944 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
5945 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5946 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5947 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5948 if ( ! (*secit)->fVirtualSection ) {
5949 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5950 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5951 ObjectFile::Reader* reader = (*ait)->getFile();
5952 uint32_t readerOrdinal = (*ait)->getOrdinal();
5953 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
5954 if ( pos == readerToOrdinal.end() ) {
5955 readerToOrdinal[reader] = readerOrdinal;
5956 ordinalToReader[readerOrdinal] = reader;
5957 }
5958 }
5959 }
5960 }
5961 }
5962 fprintf(mapFile, "# Object files:\n");
5963 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
5964 uint32_t fileIndex = 0;
5965 readerToFileOrdinal[this] = fileIndex++;
5966 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
5967 if ( it->first != 0 ) {
5968 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
5969 readerToFileOrdinal[it->second] = fileIndex++;
5970 }
5971 }
5972 // write table of sections
5973 fprintf(mapFile, "# Sections:\n");
5974 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
5975 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5976 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5977 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5978 if ( ! (*secit)->fVirtualSection ) {
5979 SectionInfo* sect = *secit;
5980 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
5981 (*segit)->fName, sect->fSectionName);
5982 }
5983 }
5984 }
5985 // write table of symbols
5986 fprintf(mapFile, "# Symbols:\n");
5987 fprintf(mapFile, "# Address\tSize \tFile Name\n");
5988 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5989 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5990 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5991 if ( ! (*secit)->fVirtualSection ) {
5992 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5993 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
5994 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5995 ObjectFile::Atom* atom = *ait;
5996 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
5997 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
5998 }
5999 }
6000 }
6001 }
6002 fclose(mapFile);
6003 }
6004 else {
6005 warning("could not write map file: %s\n", fOptions.generatedMapPath());
6006 }
6007 }
6008 }
6009
6010 static const char* sCleanupFile = NULL;
6011 static void cleanup(int sig)
6012 {
6013 ::signal(sig, SIG_DFL);
6014 if ( sCleanupFile != NULL ) {
6015 ::unlink(sCleanupFile);
6016 }
6017 if ( sig == SIGINT )
6018 ::exit(1);
6019 }
6020
6021
6022 template <typename A>
6023 uint64_t Writer<A>::writeAtoms()
6024 {
6025 // for UNIX conformance, error if file exists and is not writable
6026 if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
6027 throwf("can't write output file: %s", fFilePath);
6028
6029 int permissions = 0777;
6030 if ( fOptions.outputKind() == Options::kObjectFile )
6031 permissions = 0666;
6032 // Calling unlink first assures the file is gone so that open creates it with correct permissions
6033 // It also handles the case where fFilePath file is not writable but its directory is
6034 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
6035 (void)unlink(fFilePath);
6036
6037 // try to allocate buffer for entire output file content
6038 int fd = -1;
6039 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
6040 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
6041 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
6042 uint8_t* atomBuffer = NULL;
6043 bool streaming = false;
6044 if ( wholeBuffer == NULL ) {
6045 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
6046 if ( fd == -1 )
6047 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
6048 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
6049 streaming = true;
6050 // install signal handlers to delete output file if program is killed
6051 sCleanupFile = fFilePath;
6052 ::signal(SIGINT, cleanup);
6053 ::signal(SIGBUS, cleanup);
6054 ::signal(SIGSEGV, cleanup);
6055 }
6056 uint32_t size = 0;
6057 uint32_t end = 0;
6058 try {
6059 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
6060 SegmentInfo* curSegment = *segit;
6061 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
6062 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
6063 SectionInfo* curSection = *secit;
6064 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
6065 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
6066 //fprintf(stderr, "writing %lu atoms for section %p %s at file offset 0x%08llX\n", sectionAtoms.size(), curSection, curSection->fSectionName, curSection->fFileOffset);
6067 if ( ! curSection->fAllZeroFill ) {
6068 bool needsNops = ((strcmp(curSection->fSegmentName, "__TEXT") == 0) && (strncmp(curSection->fSectionName, "__text", 6) == 0));
6069 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
6070 ObjectFile::Atom* atom = *ait;
6071 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
6072 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
6073 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
6074 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
6075 if ( fileOffset != end ) {
6076 //fprintf(stderr, "writing %d pad bytes, needsNops=%d\n", fileOffset-end, needsNops);
6077 if ( needsNops ) {
6078 // fill gaps with no-ops
6079 if ( streaming )
6080 writeNoOps(fd, end, fileOffset);
6081 else
6082 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
6083 }
6084 else if ( streaming ) {
6085 // zero fill gaps
6086 if ( (fileOffset-end) == 4 ) {
6087 uint32_t zero = 0;
6088 ::pwrite(fd, &zero, 4, end);
6089 }
6090 else {
6091 uint8_t zero = 0x00;
6092 for (uint32_t p=end; p < fileOffset; ++p)
6093 ::pwrite(fd, &zero, 1, p);
6094 }
6095 }
6096 }
6097 uint64_t atomSize = atom->getSize();
6098 if ( streaming ) {
6099 if ( atomSize > fLargestAtomSize )
6100 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%llX > 0x%X",
6101 atom->getDisplayName(), atomSize, fLargestAtomSize);
6102 }
6103 else {
6104 if ( fileOffset > fileBufferSize )
6105 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
6106 atom->getDisplayName(), fileOffset, fileBufferSize);
6107 }
6108 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
6109 end = fileOffset+atomSize;
6110 // copy raw bytes
6111 atom->copyRawContent(buffer);
6112 // apply any fix-ups
6113 try {
6114 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6115 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
6116 ObjectFile::Reference* ref = *it;
6117 if ( fOptions.outputKind() == Options::kObjectFile ) {
6118 // doing ld -r
6119 // skip fix-ups for undefined targets
6120 if ( &(ref->getTarget()) != NULL )
6121 this->fixUpReferenceRelocatable(ref, atom, buffer);
6122 }
6123 else {
6124 // producing final linked image
6125 this->fixUpReferenceFinal(ref, atom, buffer);
6126 }
6127 }
6128 }
6129 catch (const char* msg) {
6130 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
6131 }
6132 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %p %s from %s\n",
6133 // fileOffset, end, atom->getAddress(), atom->getSize(), atom, atom->getDisplayName(), atom->getFile()->getPath());
6134 if ( streaming ) {
6135 // write out
6136 ::pwrite(fd, buffer, atomSize, fileOffset);
6137 }
6138 else {
6139 if ( (fileOffset + atomSize) > size )
6140 size = fileOffset + atomSize;
6141 }
6142 }
6143 }
6144 }
6145 }
6146 }
6147
6148 // update content based UUID
6149 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
6150 uint8_t digest[CC_MD5_DIGEST_LENGTH];
6151 if ( streaming ) {
6152 // if output file file did not fit in memory, re-read file to generate md5 hash
6153 uint32_t kMD5BufferSize = 16*1024;
6154 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
6155 if ( md5Buffer != NULL ) {
6156 CC_MD5_CTX md5State;
6157 CC_MD5_Init(&md5State);
6158 ::lseek(fd, 0, SEEK_SET);
6159 ssize_t len;
6160 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
6161 CC_MD5_Update(&md5State, md5Buffer, len);
6162 CC_MD5_Final(digest, &md5State);
6163 ::free(md5Buffer);
6164 }
6165 else {
6166 // if malloc fails, fall back to random uuid
6167 ::uuid_generate_random(digest);
6168 }
6169 fUUIDAtom->setContent(digest);
6170 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
6171 fUUIDAtom->copyRawContent(atomBuffer);
6172 ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
6173 }
6174 else {
6175 // if output file fit in memory, just genrate an md5 hash in memory
6176 #if 1
6177 // temp hack for building on Tiger
6178 CC_MD5_CTX md5State;
6179 CC_MD5_Init(&md5State);
6180 CC_MD5_Update(&md5State, wholeBuffer, size);
6181 CC_MD5_Final(digest, &md5State);
6182 #else
6183 CC_MD5(wholeBuffer, size, digest);
6184 #endif
6185 fUUIDAtom->setContent(digest);
6186 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
6187 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
6188 }
6189 }
6190 }
6191 catch (...) {
6192 if ( sCleanupFile != NULL )
6193 ::unlink(sCleanupFile);
6194 throw;
6195 }
6196
6197 // finish up
6198 if ( streaming ) {
6199 delete [] atomBuffer;
6200 close(fd);
6201 // restore default signal handlers
6202 sCleanupFile = NULL;
6203 ::signal(SIGINT, SIG_DFL);
6204 ::signal(SIGBUS, SIG_DFL);
6205 ::signal(SIGSEGV, SIG_DFL);
6206 }
6207 else {
6208 // write whole output file in one chunk
6209 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
6210 if ( fd == -1 )
6211 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
6212 ::pwrite(fd, wholeBuffer, size, 0);
6213 close(fd);
6214 delete [] wholeBuffer;
6215 }
6216
6217 return end;
6218 }
6219
6220 template <>
6221 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6222 {
6223 int64_t displacement;
6224 int64_t baseAddr;
6225 uint32_t instruction;
6226 uint32_t newInstruction;
6227 uint64_t targetAddr = 0;
6228 uint32_t firstDisp;
6229 uint32_t nextDisp;
6230 uint32_t opcode = 0;
6231 bool relocateableExternal = false;
6232 bool is_bl;
6233 bool is_blx;
6234 bool targetIsThumb;
6235
6236 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6237 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6238 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
6239 }
6240
6241 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6242 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6243 case arm::kNoFixUp:
6244 case arm::kFollowOn:
6245 case arm::kGroupSubordinate:
6246 // do nothing
6247 break;
6248 case arm::kPointerWeakImport:
6249 case arm::kPointer:
6250 // If this is the lazy pointers section, then set all lazy pointers to
6251 // point to the dyld stub binding helper.
6252 if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers
6253 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
6254 switch (ref->getTarget().getDefinitionKind()) {
6255 case ObjectFile::Atom::kExternalDefinition:
6256 case ObjectFile::Atom::kExternalWeakDefinition:
6257 // prebound lazy pointer to another dylib ==> pointer contains zero
6258 LittleEndian::set32(*fixUp, 0);
6259 break;
6260 case ObjectFile::Atom::kTentativeDefinition:
6261 case ObjectFile::Atom::kRegularDefinition:
6262 case ObjectFile::Atom::kWeakDefinition:
6263 case ObjectFile::Atom::kAbsoluteSymbol:
6264 // prebound lazy pointer to withing this dylib ==> pointer contains address
6265 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6266 targetAddr |= 1;
6267 LittleEndian::set32(*fixUp, targetAddr);
6268 break;
6269 }
6270 }
6271 else if ( relocateableExternal ) {
6272 if ( fOptions.prebind() ) {
6273 switch (ref->getTarget().getDefinitionKind()) {
6274 case ObjectFile::Atom::kExternalDefinition:
6275 case ObjectFile::Atom::kExternalWeakDefinition:
6276 // prebound external relocation ==> pointer contains addend
6277 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6278 break;
6279 case ObjectFile::Atom::kTentativeDefinition:
6280 case ObjectFile::Atom::kRegularDefinition:
6281 case ObjectFile::Atom::kWeakDefinition:
6282 // prebound external relocation to internal atom ==> pointer contains target address + addend
6283 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6284 targetAddr |= 1;
6285 LittleEndian::set32(*fixUp, targetAddr);
6286 break;
6287 case ObjectFile::Atom::kAbsoluteSymbol:
6288 break;
6289 }
6290 }
6291 else if ( !fOptions.makeClassicDyldInfo()
6292 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6293 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
6294 if ( ref->getTarget().isThumb() )
6295 targetAddr |= 1;
6296 LittleEndian::set32(*fixUp, targetAddr);
6297 }
6298 else {
6299 // external relocation ==> pointer contains addend
6300 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6301 }
6302 }
6303 else {
6304 // pointer contains target address
6305 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6306 targetAddr |= 1;
6307 LittleEndian::set32(*fixUp, targetAddr);
6308 }
6309 break;
6310 case arm::kPointerDiff:
6311 LittleEndian::set32(*fixUp,
6312 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6313 break;
6314 case arm::kReadOnlyPointer:
6315 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6316 targetAddr |= 1;
6317 switch ( ref->getTarget().getDefinitionKind() ) {
6318 case ObjectFile::Atom::kRegularDefinition:
6319 case ObjectFile::Atom::kWeakDefinition:
6320 case ObjectFile::Atom::kTentativeDefinition:
6321 // pointer contains target address
6322 LittleEndian::set32(*fixUp, targetAddr);
6323 break;
6324 case ObjectFile::Atom::kExternalDefinition:
6325 case ObjectFile::Atom::kExternalWeakDefinition:
6326 // external relocation ==> pointer contains addend
6327 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6328 break;
6329 case ObjectFile::Atom::kAbsoluteSymbol:
6330 // pointer contains target address
6331 LittleEndian::set32(*fixUp, targetAddr);
6332 break;
6333 }
6334 break;
6335 case arm::kBranch24WeakImport:
6336 case arm::kBranch24:
6337 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6338 // check if this is a branch to a branch island that can be skipped
6339 if ( ref->getTarget().getContentType() == ObjectFile::Atom::kBranchIsland ) {
6340 uint64_t finalTargetAddress = ((BranchIslandAtom<arm>*)(&(ref->getTarget())))->getFinalTargetAdress();
6341 int64_t altDisplacment = finalTargetAddress - (inAtom->getAddress() + ref->getFixUpOffset());
6342 if ( (altDisplacment < 33554428LL) && (altDisplacment > (-33554432LL)) ) {
6343 //fprintf(stderr, "using altDisplacment = %lld\n", altDisplacment);
6344 // yes, we can skip the branch island
6345 displacement = altDisplacment;
6346 }
6347 }
6348 // The pc added will be +8 from the pc
6349 displacement -= 8;
6350 //fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6351 // max positive displacement is 0x007FFFFF << 2
6352 // max negative displacement is 0xFF800000 << 2
6353 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6354 throwf("b/bl/blx out of range (%lld max is +/-32M) from 0x%08llX %s in %s to 0x%08llX %s in %s",
6355 displacement, inAtom->getAddress(), inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6356 ref->getTarget().getAddress(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6357 }
6358 instruction = LittleEndian::get32(*fixUp);
6359 // Make sure we are calling arm with bl, thumb with blx
6360 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6361 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6362 if ( is_bl && ref->getTarget().isThumb() ) {
6363 uint32_t opcode = 0xFA000000;
6364 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6365 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6366 newInstruction = opcode | h_bit | disp;
6367 }
6368 else if ( is_blx && !ref->getTarget().isThumb() ) {
6369 uint32_t opcode = 0xEB000000;
6370 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6371 newInstruction = opcode | disp;
6372 }
6373 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6374 throwf("don't know how to convert instruction %x referencing %s to thumb",
6375 instruction, ref->getTarget().getDisplayName());
6376 }
6377 else {
6378 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6379 }
6380 LittleEndian::set32(*fixUp, newInstruction);
6381 break;
6382 case arm::kThumbBranch22WeakImport:
6383 case arm::kThumbBranch22:
6384 instruction = LittleEndian::get32(*fixUp);
6385 is_bl = ((instruction & 0xD000F800) == 0xD000F000);
6386 is_blx = ((instruction & 0xD000F800) == 0xC000F000);
6387 targetIsThumb = ref->getTarget().isThumb();
6388
6389 // The pc added will be +4 from the pc
6390 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6391 // If the target is not thumb, we will be generating a blx instruction
6392 // Since blx cannot have the low bit set, set bit[1] of the target to
6393 // bit[1] of the base address, so that the difference is a multiple of
6394 // 4 bytes.
6395 if ( !targetIsThumb ) {
6396 targetAddr &= -3ULL;
6397 targetAddr |= (baseAddr & 2LL);
6398 }
6399 displacement = targetAddr - baseAddr;
6400
6401 // max positive displacement is 0x003FFFFE
6402 // max negative displacement is 0xFFC00000
6403 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6404 // armv7 supports a larger displacement
6405 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6406 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6407 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6408 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6409 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6410 }
6411 else {
6412 // The instruction is really two instructions:
6413 // The lower 16 bits are the first instruction, which contains the high
6414 // 11 bits of the displacement.
6415 // The upper 16 bits are the second instruction, which contains the low
6416 // 11 bits of the displacement, as well as differentiating bl and blx.
6417 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6418 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6419 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6420 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6421 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6422 uint32_t j1 = (i1 == s);
6423 uint32_t j2 = (i2 == s);
6424 if ( is_bl ) {
6425 if ( targetIsThumb )
6426 opcode = 0xD000F000; // keep bl
6427 else
6428 opcode = 0xC000F000; // change to blx
6429 }
6430 else if ( is_blx ) {
6431 if ( targetIsThumb )
6432 opcode = 0xD000F000; // change to bl
6433 else
6434 opcode = 0xC000F000; // keep blx
6435 }
6436 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6437 throwf("don't know how to convert instruction %x referencing %s to arm",
6438 instruction, ref->getTarget().getDisplayName());
6439 }
6440 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6441 firstDisp = (s << 10) | imm10;
6442 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6443 //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
6444 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6445 LittleEndian::set32(*fixUp, newInstruction);
6446 }
6447 }
6448 else {
6449 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6450 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6451 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6452 }
6453 }
6454 else {
6455 // The instruction is really two instructions:
6456 // The lower 16 bits are the first instruction, which contains the high
6457 // 11 bits of the displacement.
6458 // The upper 16 bits are the second instruction, which contains the low
6459 // 11 bits of the displacement, as well as differentiating bl and blx.
6460 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6461 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6462 if ( is_bl && !targetIsThumb ) {
6463 opcode = 0xE800F000;
6464 }
6465 else if ( is_blx && targetIsThumb ) {
6466 opcode = 0xF800F000;
6467 }
6468 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6469 throwf("don't know how to convert instruction %x referencing %s to arm",
6470 instruction, ref->getTarget().getDisplayName());
6471 }
6472 else {
6473 opcode = instruction & 0xF800F800;
6474 }
6475 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6476 LittleEndian::set32(*fixUp, newInstruction);
6477 }
6478 break;
6479 case arm::kDtraceProbeSite:
6480 if ( inAtom->isThumb() ) {
6481 // change 32-bit blx call site to two thumb NOPs
6482 LittleEndian::set32(*fixUp, 0x46C046C0);
6483 }
6484 else {
6485 // change call site to a NOP
6486 LittleEndian::set32(*fixUp, 0xE1A00000);
6487 }
6488 break;
6489 case arm::kDtraceIsEnabledSite:
6490 if ( inAtom->isThumb() ) {
6491 // change 32-bit blx call site to 'nop', 'eor r0, r0'
6492 LittleEndian::set32(*fixUp, 0x46C04040);
6493 }
6494 else {
6495 // change call site to 'eor r0, r0, r0'
6496 LittleEndian::set32(*fixUp, 0xE0200000);
6497 }
6498 break;
6499 case arm::kDtraceTypeReference:
6500 case arm::kDtraceProbe:
6501 // nothing to fix up
6502 break;
6503 case arm::kPointerDiff12:
6504 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6505 if ( (displacement > 4092LL) || (displacement <-4092LL) ) {
6506 throwf("ldr 12-bit displacement out of range (%lld max +/-4096) in %s", displacement, inAtom->getDisplayName());
6507 }
6508 instruction = LittleEndian::get32(*fixUp);
6509 if ( displacement >= 0 ) {
6510 instruction &= 0xFFFFF000;
6511 instruction |= ((uint32_t)displacement & 0xFFF);
6512 }
6513 else {
6514 instruction &= 0xFF7FF000;
6515 instruction |= ((uint32_t)(-displacement) & 0xFFF);
6516 }
6517 LittleEndian::set32(*fixUp, instruction);
6518 break;
6519 }
6520 }
6521
6522 template <>
6523 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6524 {
6525 int64_t displacement;
6526 uint32_t instruction;
6527 uint32_t newInstruction;
6528 uint64_t targetAddr = 0;
6529 int64_t baseAddr;
6530 uint32_t firstDisp;
6531 uint32_t nextDisp;
6532 uint32_t opcode = 0;
6533 bool relocateableExternal = false;
6534 bool is_bl;
6535 bool is_blx;
6536 bool targetIsThumb;
6537
6538 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6539 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6540 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
6541 }
6542
6543 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6544 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6545 case arm::kNoFixUp:
6546 case arm::kFollowOn:
6547 case arm::kGroupSubordinate:
6548 // do nothing
6549 break;
6550 case arm::kPointer:
6551 case arm::kReadOnlyPointer:
6552 case arm::kPointerWeakImport:
6553 {
6554 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6555 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
6556 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6557 LittleEndian::set32(*fixUp, targetAddr);
6558 else
6559 LittleEndian::set32(*fixUp, 0);
6560 }
6561 else if ( relocateableExternal ) {
6562 if ( fOptions.prebind() ) {
6563 switch (ref->getTarget().getDefinitionKind()) {
6564 case ObjectFile::Atom::kExternalDefinition:
6565 case ObjectFile::Atom::kExternalWeakDefinition:
6566 // prebound external relocation ==> pointer contains addend
6567 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6568 break;
6569 case ObjectFile::Atom::kTentativeDefinition:
6570 case ObjectFile::Atom::kRegularDefinition:
6571 case ObjectFile::Atom::kWeakDefinition:
6572 // prebound external relocation to internal atom ==> pointer contains target address + addend
6573 LittleEndian::set32(*fixUp, targetAddr);
6574 break;
6575 case ObjectFile::Atom::kAbsoluteSymbol:
6576 break;
6577 }
6578 }
6579 }
6580 else {
6581 // internal relocation
6582 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6583 // pointer contains target address
6584 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6585 targetAddr |= 1;
6586 LittleEndian::set32(*fixUp, targetAddr);
6587 }
6588 else {
6589 // pointer contains addend
6590 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6591 }
6592 }
6593 }
6594 break;
6595 case arm::kPointerDiff:
6596 LittleEndian::set32(*fixUp,
6597 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6598 break;
6599 case arm::kDtraceProbeSite:
6600 case arm::kDtraceIsEnabledSite:
6601 case arm::kBranch24WeakImport:
6602 case arm::kBranch24:
6603 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6604 // The pc added will be +8 from the pc
6605 displacement -= 8;
6606 // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6607 if ( relocateableExternal ) {
6608 // doing "ld -r" to an external symbol
6609 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6610 displacement -= ref->getTarget().getAddress();
6611 }
6612 else {
6613 // max positive displacement is 0x007FFFFF << 2
6614 // max negative displacement is 0xFF800000 << 2
6615 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6616 throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6617 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6618 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6619 }
6620 }
6621 instruction = LittleEndian::get32(*fixUp);
6622 // Make sure we are calling arm with bl, thumb with blx
6623 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6624 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6625 if ( is_bl && ref->getTarget().isThumb() ) {
6626 uint32_t opcode = 0xFA000000;
6627 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6628 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6629 newInstruction = opcode | h_bit | disp;
6630 }
6631 else if ( is_blx && !ref->getTarget().isThumb() ) {
6632 uint32_t opcode = 0xEB000000;
6633 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6634 newInstruction = opcode | disp;
6635 }
6636 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6637 throwf("don't know how to convert instruction %x referencing %s to thumb",
6638 instruction, ref->getTarget().getDisplayName());
6639 }
6640 else {
6641 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6642 }
6643 LittleEndian::set32(*fixUp, newInstruction);
6644 break;
6645 case arm::kThumbBranch22WeakImport:
6646 case arm::kThumbBranch22:
6647 instruction = LittleEndian::get32(*fixUp);
6648 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
6649 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
6650 targetIsThumb = ref->getTarget().isThumb();
6651
6652 // The pc added will be +4 from the pc
6653 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6654 // If the target is not thumb, we will be generating a blx instruction
6655 // Since blx cannot have the low bit set, set bit[1] of the target to
6656 // bit[1] of the base address, so that the difference is a multiple of
6657 // 4 bytes.
6658 if (!targetIsThumb) {
6659 targetAddr &= -3ULL;
6660 targetAddr |= (baseAddr & 2LL);
6661 }
6662 displacement = targetAddr - baseAddr;
6663
6664 //fprintf(stderr, "thumb %s fixup to %s at 0x%08llX, baseAddr = 0x%08llX, displacement = 0x%08llX, %d\n", is_blx ? "blx" : "bl", ref->getTarget().getDisplayName(), targetAddr, baseAddr, displacement, targetIsThumb);
6665 if ( relocateableExternal ) {
6666 // doing "ld -r" to an external symbol
6667 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6668 displacement -= ref->getTarget().getAddress();
6669 }
6670
6671 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6672 // armv7 supports a larger displacement
6673 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6674 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6675 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6676 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6677 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6678 }
6679 else {
6680 // The instruction is really two instructions:
6681 // The lower 16 bits are the first instruction, which contains the high
6682 // 11 bits of the displacement.
6683 // The upper 16 bits are the second instruction, which contains the low
6684 // 11 bits of the displacement, as well as differentiating bl and blx.
6685 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6686 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6687 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6688 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6689 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6690 uint32_t j1 = (i1 == s);
6691 uint32_t j2 = (i2 == s);
6692 if ( is_bl ) {
6693 if ( targetIsThumb )
6694 opcode = 0xD000F000; // keep bl
6695 else
6696 opcode = 0xC000F000; // change to blx
6697 }
6698 else if ( is_blx ) {
6699 if ( targetIsThumb )
6700 opcode = 0xD000F000; // change to bl
6701 else
6702 opcode = 0xC000F000; // keep blx
6703 }
6704 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6705 throwf("don't know how to convert instruction %x referencing %s to arm",
6706 instruction, ref->getTarget().getDisplayName());
6707 }
6708 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6709 firstDisp = (s << 10) | imm10;
6710 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6711 //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
6712 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6713 LittleEndian::set32(*fixUp, newInstruction);
6714 break;
6715 }
6716 }
6717 else {
6718 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6719 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6720 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6721 }
6722 }
6723 // The instruction is really two instructions:
6724 // The lower 16 bits are the first instruction, which contains the first
6725 // 11 bits of the displacement.
6726 // The upper 16 bits are the second instruction, which contains the next
6727 // 11 bits of the displacement, as well as differentiating bl and blx.
6728 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6729 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6730 if ( is_bl && !targetIsThumb ) {
6731 opcode = 0xE800F000;
6732 }
6733 else if ( is_blx && targetIsThumb ) {
6734 opcode = 0xF800F000;
6735 }
6736 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6737 throwf("don't know how to convert instruction %x referencing %s to arm",
6738 instruction, ref->getTarget().getDisplayName());
6739 }
6740 else {
6741 opcode = instruction & 0xF800F800;
6742 }
6743 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6744 LittleEndian::set32(*fixUp, newInstruction);
6745 break;
6746 case arm::kDtraceProbe:
6747 case arm::kDtraceTypeReference:
6748 // nothing to fix up
6749 break;
6750 case arm::kPointerDiff12:
6751 throw "internal error. no reloc for 12-bit pointer diffs";
6752 }
6753 }
6754
6755 template <>
6756 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6757 {
6758 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6759 uint8_t* dtraceProbeSite;
6760 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6761 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6762 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6763 const int64_t kOneTwentyEightLimit = 0x7F;
6764 int64_t displacement;
6765 uint32_t temp;
6766 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6767 switch ( kind ) {
6768 case x86::kNoFixUp:
6769 case x86::kFollowOn:
6770 case x86::kGroupSubordinate:
6771 // do nothing
6772 break;
6773 case x86::kPointerWeakImport:
6774 case x86::kPointer:
6775 {
6776 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6777 if ( fOptions.prebind() ) {
6778 switch (ref->getTarget().getDefinitionKind()) {
6779 case ObjectFile::Atom::kExternalDefinition:
6780 case ObjectFile::Atom::kExternalWeakDefinition:
6781 // prebound external relocation ==> pointer contains addend
6782 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6783 break;
6784 case ObjectFile::Atom::kTentativeDefinition:
6785 case ObjectFile::Atom::kRegularDefinition:
6786 case ObjectFile::Atom::kWeakDefinition:
6787 // prebound external relocation to internal atom ==> pointer contains target address + addend
6788 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6789 break;
6790 case ObjectFile::Atom::kAbsoluteSymbol:
6791 break;
6792 }
6793 }
6794 else if ( !fOptions.makeClassicDyldInfo()
6795 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6796 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
6797 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6798 }
6799 else {
6800 // external relocation ==> pointer contains addend
6801 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6802 }
6803 }
6804 else {
6805 // pointer contains target address
6806 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6807 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6808 }
6809 }
6810 break;
6811 case x86::kPointerDiff:
6812 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6813 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6814 break;
6815 case x86::kPointerDiff16:
6816 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6817 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6818 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6819 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6820 break;
6821 case x86::kPointerDiff24:
6822 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6823 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6824 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6825 temp = LittleEndian::get32(*fixUp);
6826 temp &= 0xFF000000;
6827 temp |= (displacement & 0x00FFFFFF);
6828 LittleEndian::set32(*fixUp, temp);
6829 break;
6830 case x86::kSectionOffset24:
6831 displacement = ref->getTarget().getSectionOffset();
6832 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6833 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6834 temp = LittleEndian::get32(*fixUp);
6835 temp &= 0xFF000000;
6836 temp |= (displacement & 0x00FFFFFF);
6837 LittleEndian::set32(*fixUp, temp);
6838 break;
6839 case x86::kDtraceProbeSite:
6840 // change call site to a NOP
6841 dtraceProbeSite = (uint8_t*)fixUp;
6842 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6843 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6844 dtraceProbeSite[1] = 0x1F;
6845 dtraceProbeSite[2] = 0x40;
6846 dtraceProbeSite[3] = 0x00;
6847 break;
6848 case x86::kDtraceIsEnabledSite:
6849 // change call site to a clear eax
6850 dtraceProbeSite = (uint8_t*)fixUp;
6851 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
6852 dtraceProbeSite[0] = 0xC0;
6853 dtraceProbeSite[1] = 0x90; // 1-byte nop
6854 dtraceProbeSite[2] = 0x90; // 1-byte nop
6855 dtraceProbeSite[3] = 0x90; // 1-byte nop
6856 break;
6857 case x86::kPCRel32WeakImport:
6858 case x86::kPCRel32:
6859 case x86::kPCRel16:
6860 case x86::kPCRel8:
6861 displacement = 0;
6862 switch ( ref->getTarget().getDefinitionKind() ) {
6863 case ObjectFile::Atom::kRegularDefinition:
6864 case ObjectFile::Atom::kWeakDefinition:
6865 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6866 break;
6867 case ObjectFile::Atom::kExternalDefinition:
6868 case ObjectFile::Atom::kExternalWeakDefinition:
6869 throw "codegen problem, can't use rel32 to external symbol";
6870 case ObjectFile::Atom::kTentativeDefinition:
6871 displacement = 0;
6872 break;
6873 case ObjectFile::Atom::kAbsoluteSymbol:
6874 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6875 break;
6876 }
6877 if ( kind == x86::kPCRel8 ) {
6878 displacement += 3;
6879 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6880 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
6881 throwf("rel8 out of range in %s", inAtom->getDisplayName());
6882 }
6883 *(int8_t*)fixUp = (int8_t)displacement;
6884 }
6885 else if ( kind == x86::kPCRel16 ) {
6886 displacement += 2;
6887 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6888 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
6889 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6890 }
6891 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6892 }
6893 else {
6894 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6895 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
6896 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6897 }
6898 LittleEndian::set32(*fixUp, (int32_t)displacement);
6899 }
6900 break;
6901 case x86::kAbsolute32:
6902 switch ( ref->getTarget().getDefinitionKind() ) {
6903 case ObjectFile::Atom::kRegularDefinition:
6904 case ObjectFile::Atom::kWeakDefinition:
6905 case ObjectFile::Atom::kTentativeDefinition:
6906 // pointer contains target address
6907 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6908 break;
6909 case ObjectFile::Atom::kExternalDefinition:
6910 case ObjectFile::Atom::kExternalWeakDefinition:
6911 // external relocation ==> pointer contains addend
6912 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6913 break;
6914 case ObjectFile::Atom::kAbsoluteSymbol:
6915 // pointer contains target address
6916 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
6917 break;
6918 }
6919 break;
6920 case x86::kImageOffset32:
6921 // offset of target atom from mach_header
6922 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6923 LittleEndian::set32(*fixUp, (int32_t)displacement);
6924 break;
6925 case x86::kDtraceTypeReference:
6926 case x86::kDtraceProbe:
6927 // nothing to fix up
6928 break;
6929 }
6930 }
6931
6932
6933
6934 template <>
6935 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6936 {
6937 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6938 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6939 const int64_t kOneTwentyEightLimit = 0x7F;
6940 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6941 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
6942 int64_t displacement;
6943 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6944 switch ( kind ) {
6945 case x86::kNoFixUp:
6946 case x86::kFollowOn:
6947 case x86::kGroupSubordinate:
6948 // do nothing
6949 break;
6950 case x86::kPointer:
6951 case x86::kPointerWeakImport:
6952 case x86::kAbsolute32:
6953 {
6954 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6955 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
6956 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6957 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6958 else
6959 LittleEndian::set32(*fixUp, 0);
6960 }
6961 else if ( isExtern ) {
6962 // external relocation ==> pointer contains addend
6963 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6964 }
6965 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6966 // internal relocation => pointer contains target address
6967 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6968 }
6969 else {
6970 // internal relocation to tentative ==> pointer contains addend
6971 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6972 }
6973 }
6974 break;
6975 case x86::kPointerDiff:
6976 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6977 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6978 break;
6979 case x86::kPointerDiff16:
6980 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6981 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6982 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6983 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6984 break;
6985 case x86::kPCRel8:
6986 case x86::kPCRel16:
6987 case x86::kPCRel32:
6988 case x86::kPCRel32WeakImport:
6989 case x86::kDtraceProbeSite:
6990 case x86::kDtraceIsEnabledSite:
6991 {
6992 if ( isExtern )
6993 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6994 else
6995 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6996 if ( kind == x86::kPCRel8 ) {
6997 displacement += 3;
6998 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6999 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
7000 throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
7001 }
7002 int8_t byte = (int8_t)displacement;
7003 *((int8_t*)fixUp) = byte;
7004 }
7005 else if ( kind == x86::kPCRel16 ) {
7006 displacement += 2;
7007 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
7008 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
7009 throwf("rel16 out of range in %s", inAtom->getDisplayName());
7010 }
7011 int16_t word = (int16_t)displacement;
7012 LittleEndian::set16(*((uint16_t*)fixUp), word);
7013 }
7014 else {
7015 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
7016 //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement,
7017 // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
7018 throwf("rel32 out of range in %s", inAtom->getDisplayName());
7019 }
7020 LittleEndian::set32(*fixUp, (int32_t)displacement);
7021 }
7022 }
7023 break;
7024 case x86::kPointerDiff24:
7025 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
7026 case x86::kImageOffset32:
7027 throw "internal linker error, kImageOffset32 can't be encoded into object files";
7028 case x86::kSectionOffset24:
7029 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
7030 case x86::kDtraceProbe:
7031 case x86::kDtraceTypeReference:
7032 // nothing to fix up
7033 break;
7034 }
7035 }
7036
7037 template <>
7038 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7039 {
7040 const int64_t twoGigLimit = 0x7FFFFFFF;
7041 const int64_t kSixteenMegLimit = 0x00FFFFFF;
7042 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
7043 uint8_t* dtraceProbeSite;
7044 int64_t displacement = 0;
7045 uint32_t temp;
7046 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
7047 case x86_64::kNoFixUp:
7048 case x86_64::kGOTNoFixUp:
7049 case x86_64::kFollowOn:
7050 case x86_64::kGroupSubordinate:
7051 // do nothing
7052 break;
7053 case x86_64::kPointerWeakImport:
7054 case x86_64::kPointer:
7055 {
7056 if ( &ref->getTarget() != NULL ) {
7057 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
7058 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal) {
7059 if ( !fOptions.makeClassicDyldInfo()
7060 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
7061 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
7062 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
7063 }
7064 else {
7065 // external relocation ==> pointer contains addend
7066 LittleEndian::set64(*fixUp, ref->getTargetOffset());
7067 }
7068 }
7069 else {
7070 // internal relocation
7071 // pointer contains target address
7072 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
7073 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
7074 }
7075 }
7076 }
7077 break;
7078 case x86_64::kPointer32:
7079 {
7080 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
7081 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
7082 // external relocation
7083 throwf("32-bit pointer to dylib or weak symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
7084 }
7085 else {
7086 // internal relocation
7087 // pointer contains target address
7088 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
7089 displacement = ref->getTarget().getAddress() + ref->getTargetOffset();
7090 switch ( fOptions.outputKind() ) {
7091 case Options::kObjectFile:
7092 case Options::kPreload:
7093 case Options::kDyld:
7094 case Options::kDynamicLibrary:
7095 case Options::kDynamicBundle:
7096 case Options::kKextBundle:
7097 throwf("32-bit pointer to symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
7098 case Options::kDynamicExecutable:
7099 // <rdar://problem/5855588> allow x86_64 main executables to use 32-bit pointers if program loads in load 2GB
7100 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
7101 throw "32-bit pointer out of range";
7102 break;
7103 case Options::kStaticExecutable:
7104 // <rdar://problem/5855588> allow x86_64 mach_kernel to truncate pointers
7105 break;
7106 }
7107 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
7108 }
7109 }
7110 break;
7111 case x86_64::kPointerDiff32:
7112 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
7113 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
7114 throw "32-bit pointer difference out of range";
7115 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
7116 break;
7117 case x86_64::kPointerDiff:
7118 LittleEndian::set64(*fixUp,
7119 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7120 break;
7121 case x86_64::kPointerDiff24:
7122 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
7123 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
7124 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
7125 temp = LittleEndian::get32(*((uint32_t*)fixUp));
7126 temp &= 0xFF000000;
7127 temp |= (displacement & 0x00FFFFFF);
7128 LittleEndian::set32(*((uint32_t*)fixUp), temp);
7129 break;
7130 case x86_64::kSectionOffset24:
7131 displacement = ref->getTarget().getSectionOffset();
7132 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
7133 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
7134 temp = LittleEndian::get32(*((uint32_t*)fixUp));
7135 temp &= 0xFF000000;
7136 temp |= (displacement & 0x00FFFFFF);
7137 LittleEndian::set32(*((uint32_t*)fixUp), temp);
7138 break;
7139 case x86_64::kPCRel32GOTLoad:
7140 case x86_64::kPCRel32GOTLoadWeakImport:
7141 // if GOT entry was optimized away, change movq instruction to a leaq
7142 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
7143 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
7144 uint8_t* opcodes = (uint8_t*)fixUp;
7145 if ( opcodes[-2] != 0x8B )
7146 throw "GOT load reloc does not point to a movq instruction";
7147 opcodes[-2] = 0x8D;
7148 }
7149 // fall into general rel32 case
7150 case x86_64::kBranchPCRel32WeakImport:
7151 case x86_64::kBranchPCRel32:
7152 case x86_64::kBranchPCRel8:
7153 case x86_64::kPCRel32:
7154 case x86_64::kPCRel32_1:
7155 case x86_64::kPCRel32_2:
7156 case x86_64::kPCRel32_4:
7157 case x86_64::kPCRel32GOT:
7158 case x86_64::kPCRel32GOTWeakImport:
7159 switch ( ref->getTarget().getDefinitionKind() ) {
7160 case ObjectFile::Atom::kRegularDefinition:
7161 case ObjectFile::Atom::kWeakDefinition:
7162 case ObjectFile::Atom::kTentativeDefinition:
7163 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7164 break;
7165 case ObjectFile::Atom::kAbsoluteSymbol:
7166 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7167 break;
7168 case ObjectFile::Atom::kExternalDefinition:
7169 case ObjectFile::Atom::kExternalWeakDefinition:
7170 if ( fOptions.outputKind() == Options::kKextBundle )
7171 displacement = 0;
7172 else
7173 throwf("codegen problem, can't use rel32 to external symbol %s", ref->getTarget().getDisplayName());
7174 break;
7175 }
7176 switch ( ref->getKind() ) {
7177 case x86_64::kPCRel32_1:
7178 displacement -= 1;
7179 break;
7180 case x86_64::kPCRel32_2:
7181 displacement -= 2;
7182 break;
7183 case x86_64::kPCRel32_4:
7184 displacement -= 4;
7185 break;
7186 case x86_64::kBranchPCRel8:
7187 displacement += 3;
7188 break;
7189 }
7190 if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
7191 if ( (displacement > 127) || (displacement < (-128)) ) {
7192 fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n",
7193 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
7194 throw "rel8 out of range";
7195 }
7196 *((int8_t*)fixUp) = (int8_t)displacement;
7197 }
7198 else {
7199 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
7200 fprintf(stderr, "reference out of range from %s (%llX) in %s to %s (%llX) in %s\n",
7201 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
7202 throw "rel32 out of range";
7203 }
7204 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
7205 }
7206 break;
7207 case x86_64::kImageOffset32:
7208 // offset of target atom from mach_header
7209 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
7210 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
7211 break;
7212 case x86_64::kDtraceProbeSite:
7213 // change call site to a NOP
7214 dtraceProbeSite = (uint8_t*)fixUp;
7215 dtraceProbeSite[-1] = 0x90; // 1-byte nop
7216 dtraceProbeSite[0] = 0x0F; // 4-byte nop
7217 dtraceProbeSite[1] = 0x1F;
7218 dtraceProbeSite[2] = 0x40;
7219 dtraceProbeSite[3] = 0x00;
7220 break;
7221 case x86_64::kDtraceIsEnabledSite:
7222 // change call site to a clear eax
7223 dtraceProbeSite = (uint8_t*)fixUp;
7224 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
7225 dtraceProbeSite[0] = 0x33;
7226 dtraceProbeSite[1] = 0xC0;
7227 dtraceProbeSite[2] = 0x90; // 1-byte nop
7228 dtraceProbeSite[3] = 0x90; // 1-byte nop
7229 break;
7230 case x86_64::kDtraceTypeReference:
7231 case x86_64::kDtraceProbe:
7232 // nothing to fix up
7233 break;
7234 }
7235 }
7236
7237 template <>
7238 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7239 {
7240 const int64_t twoGigLimit = 0x7FFFFFFF;
7241 bool external = this->makesExternalRelocatableReference(ref->getTarget());
7242 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
7243 int64_t displacement = 0;
7244 int32_t temp32;
7245 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
7246 case x86_64::kNoFixUp:
7247 case x86_64::kGOTNoFixUp:
7248 case x86_64::kFollowOn:
7249 case x86_64::kGroupSubordinate:
7250 // do nothing
7251 break;
7252 case x86_64::kPointer:
7253 case x86_64::kPointerWeakImport:
7254 {
7255 if ( external ) {
7256 // external relocation ==> pointer contains addend
7257 LittleEndian::set64(*fixUp, ref->getTargetOffset());
7258 }
7259 else {
7260 // internal relocation ==> pointer contains target address
7261 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
7262 }
7263 }
7264 break;
7265 case x86_64::kPointer32:
7266 {
7267 if ( external ) {
7268 // external relocation ==> pointer contains addend
7269 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset());
7270 }
7271 else {
7272 // internal relocation ==> pointer contains target address
7273 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTarget().getAddress() + ref->getTargetOffset());
7274 }
7275 }
7276 break;
7277 case x86_64::kPointerDiff32:
7278 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
7279 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7280 displacement += ref->getTarget().getAddress();
7281 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7282 displacement -= ref->getFromTarget().getAddress();
7283 LittleEndian::set32(*((uint32_t*)fixUp), displacement);
7284 break;
7285 case x86_64::kPointerDiff:
7286 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
7287 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7288 displacement += ref->getTarget().getAddress();
7289 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7290 displacement -= ref->getFromTarget().getAddress();
7291 LittleEndian::set64(*fixUp, displacement);
7292 break;
7293 case x86_64::kBranchPCRel32:
7294 case x86_64::kBranchPCRel32WeakImport:
7295 case x86_64::kDtraceProbeSite:
7296 case x86_64::kDtraceIsEnabledSite:
7297 case x86_64::kPCRel32:
7298 case x86_64::kPCRel32_1:
7299 case x86_64::kPCRel32_2:
7300 case x86_64::kPCRel32_4:
7301 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7302 temp32 = ref->getTargetOffset();
7303 if ( external ) {
7304 // extern relocation contains addend
7305 displacement = temp32;
7306 }
7307 else {
7308 // internal relocations contain delta to target address
7309 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7310 }
7311 switch ( ref->getKind() ) {
7312 case x86_64::kPCRel32_1:
7313 displacement -= 1;
7314 break;
7315 case x86_64::kPCRel32_2:
7316 displacement -= 2;
7317 break;
7318 case x86_64::kPCRel32_4:
7319 displacement -= 4;
7320 break;
7321 }
7322 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
7323 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
7324 throw "rel32 out of range";
7325 }
7326 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
7327 break;
7328 case x86_64::kBranchPCRel8:
7329 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7330 temp32 = ref->getTargetOffset();
7331 if ( external ) {
7332 // extern relocation contains addend
7333 displacement = temp32;
7334 }
7335 else {
7336 // internal relocations contain delta to target address
7337 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
7338 }
7339 if ( (displacement > 127) || (displacement < (-128)) ) {
7340 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
7341 throw "rel8 out of range";
7342 }
7343 *((int8_t*)fixUp) = (int8_t)displacement;
7344 break;
7345 case x86_64::kPCRel32GOT:
7346 case x86_64::kPCRel32GOTLoad:
7347 case x86_64::kPCRel32GOTWeakImport:
7348 case x86_64::kPCRel32GOTLoadWeakImport:
7349 // contains addend (usually zero)
7350 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
7351 break;
7352 case x86_64::kPointerDiff24:
7353 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
7354 case x86_64::kImageOffset32:
7355 throw "internal linker error, kImageOffset32 can't be encoded into object files";
7356 case x86_64::kSectionOffset24:
7357 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
7358 case x86_64::kDtraceTypeReference:
7359 case x86_64::kDtraceProbe:
7360 // nothing to fix up
7361 break;
7362 }
7363 }
7364
7365 template <>
7366 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7367 {
7368 fixUpReference_powerpc(ref, inAtom, buffer, true);
7369 }
7370
7371 template <>
7372 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7373 {
7374 fixUpReference_powerpc(ref, inAtom, buffer, true);
7375 }
7376
7377 template <>
7378 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7379 {
7380 fixUpReference_powerpc(ref, inAtom, buffer, false);
7381 }
7382
7383 template <>
7384 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7385 {
7386 fixUpReference_powerpc(ref, inAtom, buffer, false);
7387 }
7388
7389 //
7390 // ppc and ppc64 are mostly the same, so they share a template specialzation
7391 //
7392 template <typename A>
7393 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
7394 {
7395 uint32_t instruction;
7396 uint32_t newInstruction;
7397 int64_t displacement;
7398 uint64_t targetAddr = 0;
7399 uint64_t picBaseAddr;
7400 uint16_t instructionLowHalf;
7401 uint16_t instructionHighHalf;
7402 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
7403 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
7404 bool relocateableExternal = false;
7405 const int64_t picbase_twoGigLimit = 0x80000000;
7406
7407 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
7408 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
7409 if ( finalLinkedImage )
7410 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
7411 else
7412 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
7413 }
7414
7415 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
7416 case A::kNoFixUp:
7417 case A::kFollowOn:
7418 case A::kGroupSubordinate:
7419 // do nothing
7420 break;
7421 case A::kPointerWeakImport:
7422 case A::kPointer:
7423 {
7424 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
7425 if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers
7426 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
7427 switch (ref->getTarget().getDefinitionKind()) {
7428 case ObjectFile::Atom::kExternalDefinition:
7429 case ObjectFile::Atom::kExternalWeakDefinition:
7430 // prebound lazy pointer to another dylib ==> pointer contains zero
7431 P::setP(*fixUpPointer, 0);
7432 break;
7433 case ObjectFile::Atom::kTentativeDefinition:
7434 case ObjectFile::Atom::kRegularDefinition:
7435 case ObjectFile::Atom::kWeakDefinition:
7436 case ObjectFile::Atom::kAbsoluteSymbol:
7437 // prebound lazy pointer to withing this dylib ==> pointer contains address
7438 P::setP(*fixUpPointer, targetAddr);
7439 break;
7440 }
7441 }
7442 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
7443 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
7444 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
7445 P::setP(*fixUpPointer, targetAddr);
7446 else
7447 P::setP(*fixUpPointer, 0);
7448 }
7449 else if ( relocateableExternal ) {
7450 if ( fOptions.prebind() ) {
7451 switch (ref->getTarget().getDefinitionKind()) {
7452 case ObjectFile::Atom::kExternalDefinition:
7453 case ObjectFile::Atom::kExternalWeakDefinition:
7454 // prebound external relocation ==> pointer contains addend
7455 P::setP(*fixUpPointer, ref->getTargetOffset());
7456 break;
7457 case ObjectFile::Atom::kTentativeDefinition:
7458 case ObjectFile::Atom::kRegularDefinition:
7459 case ObjectFile::Atom::kWeakDefinition:
7460 // prebound external relocation to internal atom ==> pointer contains target address + addend
7461 P::setP(*fixUpPointer, targetAddr);
7462 break;
7463 case ObjectFile::Atom::kAbsoluteSymbol:
7464 break;
7465 }
7466 }
7467 else {
7468 // external relocation ==> pointer contains addend
7469 P::setP(*fixUpPointer, ref->getTargetOffset());
7470 }
7471 }
7472 else {
7473 // internal relocation
7474 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
7475 // pointer contains target address
7476 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
7477 P::setP(*fixUpPointer, targetAddr);
7478 }
7479 else {
7480 // pointer contains addend
7481 P::setP(*fixUpPointer, ref->getTargetOffset());
7482 }
7483 }
7484 }
7485 break;
7486 case A::kPointerDiff64:
7487 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7488 break;
7489 case A::kPointerDiff32:
7490 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7491 break;
7492 case A::kPointerDiff16:
7493 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7494 break;
7495 case A::kDtraceProbeSite:
7496 if ( finalLinkedImage ) {
7497 // change call site to a NOP
7498 BigEndian::set32(*fixUp, 0x60000000);
7499 }
7500 else {
7501 // set bl instuction to branch to address zero in .o file
7502 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7503 instruction = BigEndian::get32(*fixUp);
7504 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7505 BigEndian::set32(*fixUp, newInstruction);
7506 }
7507 break;
7508 case A::kDtraceIsEnabledSite:
7509 if ( finalLinkedImage ) {
7510 // change call site to a li r3,0
7511 BigEndian::set32(*fixUp, 0x38600000);
7512 }
7513 else {
7514 // set bl instuction to branch to address zero in .o file
7515 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7516 instruction = BigEndian::get32(*fixUp);
7517 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7518 BigEndian::set32(*fixUp, newInstruction);
7519 }
7520 break;
7521 case A::kBranch24WeakImport:
7522 case A::kBranch24:
7523 {
7524 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
7525 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7526 if ( relocateableExternal ) {
7527 // doing "ld -r" to an external symbol
7528 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7529 displacement -= ref->getTarget().getAddress();
7530 }
7531 else {
7532 const int64_t bl_eightMegLimit = 0x00FFFFFF;
7533 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
7534 //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
7535 throwf("bl out of range (%lld max is +/-16M) from %s at 0x%08llX in %s of %s to %s at 0x%08llX in %s of %s",
7536 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
7537 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
7538 }
7539 }
7540 instruction = BigEndian::get32(*fixUp);
7541 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7542 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7543 BigEndian::set32(*fixUp, newInstruction);
7544 }
7545 break;
7546 case A::kBranch14:
7547 {
7548 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7549 if ( relocateableExternal ) {
7550 // doing "ld -r" to an external symbol
7551 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7552 displacement -= ref->getTarget().getAddress();
7553 }
7554 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
7555 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
7556 //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
7557 throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
7558 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
7559 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
7560 }
7561
7562 //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
7563 instruction = BigEndian::get32(*fixUp);
7564 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
7565 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7566 BigEndian::set32(*fixUp, newInstruction);
7567 }
7568 break;
7569 case A::kPICBaseLow16:
7570 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7571 displacement = targetAddr - picBaseAddr;
7572 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7573 throw "32-bit pic-base out of range";
7574 instructionLowHalf = (displacement & 0xFFFF);
7575 instruction = BigEndian::get32(*fixUp);
7576 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7577 BigEndian::set32(*fixUp, newInstruction);
7578 break;
7579 case A::kPICBaseLow14:
7580 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7581 displacement = targetAddr - picBaseAddr;
7582 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7583 throw "32-bit pic-base out of range";
7584 if ( (displacement & 0x3) != 0 )
7585 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
7586 instructionLowHalf = (displacement & 0xFFFC);
7587 instruction = BigEndian::get32(*fixUp);
7588 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7589 BigEndian::set32(*fixUp, newInstruction);
7590 break;
7591 case A::kPICBaseHigh16:
7592 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7593 displacement = targetAddr - picBaseAddr;
7594 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7595 throw "32-bit pic-base out of range";
7596 instructionLowHalf = displacement >> 16;
7597 if ( (displacement & 0x00008000) != 0 )
7598 ++instructionLowHalf;
7599 instruction = BigEndian::get32(*fixUp);
7600 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7601 BigEndian::set32(*fixUp, newInstruction);
7602 break;
7603 case A::kAbsLow16:
7604 if ( relocateableExternal && !finalLinkedImage )
7605 targetAddr -= ref->getTarget().getAddress();
7606 instructionLowHalf = (targetAddr & 0xFFFF);
7607 instruction = BigEndian::get32(*fixUp);
7608 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7609 BigEndian::set32(*fixUp, newInstruction);
7610 break;
7611 case A::kAbsLow14:
7612 if ( relocateableExternal && !finalLinkedImage )
7613 targetAddr -= ref->getTarget().getAddress();
7614 if ( (targetAddr & 0x3) != 0 )
7615 throw "bad address for absolute lo14 instruction fix-up";
7616 instructionLowHalf = (targetAddr & 0xFFFF);
7617 instruction = BigEndian::get32(*fixUp);
7618 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7619 BigEndian::set32(*fixUp, newInstruction);
7620 break;
7621 case A::kAbsHigh16:
7622 if ( relocateableExternal ) {
7623 if ( finalLinkedImage ) {
7624 switch (ref->getTarget().getDefinitionKind()) {
7625 case ObjectFile::Atom::kExternalDefinition:
7626 case ObjectFile::Atom::kExternalWeakDefinition:
7627 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7628 break;
7629 case ObjectFile::Atom::kTentativeDefinition:
7630 case ObjectFile::Atom::kRegularDefinition:
7631 case ObjectFile::Atom::kWeakDefinition:
7632 // use target address
7633 break;
7634 case ObjectFile::Atom::kAbsoluteSymbol:
7635 targetAddr = ref->getTarget().getSectionOffset();
7636 break;
7637 }
7638 }
7639 else {
7640 targetAddr -= ref->getTarget().getAddress();
7641 }
7642 }
7643 instructionHighHalf = (targetAddr >> 16);
7644 instruction = BigEndian::get32(*fixUp);
7645 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
7646 BigEndian::set32(*fixUp, newInstruction);
7647 break;
7648 case A::kAbsHigh16AddLow:
7649 if ( relocateableExternal ) {
7650 if ( finalLinkedImage ) {
7651 switch (ref->getTarget().getDefinitionKind()) {
7652 case ObjectFile::Atom::kExternalDefinition:
7653 case ObjectFile::Atom::kExternalWeakDefinition:
7654 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7655 break;
7656 case ObjectFile::Atom::kTentativeDefinition:
7657 case ObjectFile::Atom::kRegularDefinition:
7658 case ObjectFile::Atom::kWeakDefinition:
7659 // use target address
7660 break;
7661 case ObjectFile::Atom::kAbsoluteSymbol:
7662 targetAddr = ref->getTarget().getSectionOffset();
7663 break;
7664 }
7665 }
7666 else {
7667 targetAddr -= ref->getTarget().getAddress();
7668 }
7669 }
7670 if ( targetAddr & 0x00008000 )
7671 targetAddr += 0x00010000;
7672 instruction = BigEndian::get32(*fixUp);
7673 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
7674 BigEndian::set32(*fixUp, newInstruction);
7675 break;
7676 case A::kDtraceTypeReference:
7677 case A::kDtraceProbe:
7678 // nothing to fix up
7679 break;
7680 }
7681 }
7682
7683 template <>
7684 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7685 {
7686 uint8_t kind = ref->getKind();
7687 switch ( (ppc::ReferenceKinds)kind ) {
7688 case ppc::kNoFixUp:
7689 case ppc::kFollowOn:
7690 case ppc::kGroupSubordinate:
7691 case ppc::kPointer:
7692 case ppc::kPointerWeakImport:
7693 case ppc::kPointerDiff16:
7694 case ppc::kPointerDiff32:
7695 case ppc::kPointerDiff64:
7696 case ppc::kDtraceProbe:
7697 case ppc::kDtraceProbeSite:
7698 case ppc::kDtraceIsEnabledSite:
7699 case ppc::kDtraceTypeReference:
7700 // these are never used to call external functions
7701 return false;
7702 case ppc::kBranch24:
7703 case ppc::kBranch24WeakImport:
7704 case ppc::kBranch14:
7705 // these are used to call external functions
7706 return true;
7707 case ppc::kPICBaseLow16:
7708 case ppc::kPICBaseLow14:
7709 case ppc::kPICBaseHigh16:
7710 case ppc::kAbsLow16:
7711 case ppc::kAbsLow14:
7712 case ppc::kAbsHigh16:
7713 case ppc::kAbsHigh16AddLow:
7714 // these are only used to call external functions
7715 // in -mlong-branch stubs
7716 switch ( ref->getTarget().getDefinitionKind() ) {
7717 case ObjectFile::Atom::kExternalDefinition:
7718 case ObjectFile::Atom::kExternalWeakDefinition:
7719 // if the .o file this atom came from has long-branch stubs,
7720 // then assume these instructions in a stub.
7721 // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
7722 return ( inAtom->getFile()->hasLongBranchStubs() );
7723 case ObjectFile::Atom::kTentativeDefinition:
7724 case ObjectFile::Atom::kRegularDefinition:
7725 case ObjectFile::Atom::kWeakDefinition:
7726 case ObjectFile::Atom::kAbsoluteSymbol:
7727 return false;
7728 }
7729 break;
7730 }
7731 return false;
7732 }
7733
7734 template <>
7735 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7736 {
7737 uint8_t kind = ref->getKind();
7738 switch ( (arm::ReferenceKinds)kind ) {
7739 case arm::kBranch24:
7740 case arm::kBranch24WeakImport:
7741 return true;
7742 case arm::kThumbBranch22:
7743 case arm::kThumbBranch22WeakImport:
7744 fHasThumbBranches = true;
7745 return true;
7746 case arm::kNoFixUp:
7747 case arm::kFollowOn:
7748 case arm::kGroupSubordinate:
7749 case arm::kPointer:
7750 case arm::kReadOnlyPointer:
7751 case arm::kPointerWeakImport:
7752 case arm::kPointerDiff:
7753 case arm::kDtraceProbe:
7754 case arm::kDtraceProbeSite:
7755 case arm::kDtraceIsEnabledSite:
7756 case arm::kDtraceTypeReference:
7757 case arm::kPointerDiff12:
7758 return false;
7759 }
7760 return false;
7761 }
7762
7763 template <>
7764 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7765 {
7766 uint8_t kind = ref->getKind();
7767 switch ( (ppc64::ReferenceKinds)kind ) {
7768 case ppc::kNoFixUp:
7769 case ppc::kFollowOn:
7770 case ppc::kGroupSubordinate:
7771 case ppc::kPointer:
7772 case ppc::kPointerWeakImport:
7773 case ppc::kPointerDiff16:
7774 case ppc::kPointerDiff32:
7775 case ppc::kPointerDiff64:
7776 case ppc::kPICBaseLow16:
7777 case ppc::kPICBaseLow14:
7778 case ppc::kPICBaseHigh16:
7779 case ppc::kAbsLow16:
7780 case ppc::kAbsLow14:
7781 case ppc::kAbsHigh16:
7782 case ppc::kAbsHigh16AddLow:
7783 case ppc::kDtraceProbe:
7784 case ppc::kDtraceProbeSite:
7785 case ppc::kDtraceIsEnabledSite:
7786 case ppc::kDtraceTypeReference:
7787 // these are never used to call external functions
7788 return false;
7789 case ppc::kBranch24:
7790 case ppc::kBranch24WeakImport:
7791 case ppc::kBranch14:
7792 // these are used to call external functions
7793 return true;
7794 }
7795 return false;
7796 }
7797
7798 template <>
7799 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7800 {
7801 uint8_t kind = ref->getKind();
7802 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
7803 }
7804
7805 template <>
7806 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7807 {
7808 uint8_t kind = ref->getKind();
7809 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
7810 }
7811
7812
7813 template <>
7814 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
7815 {
7816 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
7817 }
7818
7819 template <>
7820 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
7821 {
7822 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
7823 }
7824
7825 template <>
7826 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
7827 {
7828 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
7829 }
7830
7831 template <>
7832 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
7833 {
7834 switch ( kind ) {
7835 case x86_64::kPointerWeakImport:
7836 case x86_64::kBranchPCRel32WeakImport:
7837 case x86_64::kPCRel32GOTWeakImport:
7838 case x86_64::kPCRel32GOTLoadWeakImport:
7839 return true;
7840 }
7841 return false;
7842 }
7843
7844 template <>
7845 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
7846 {
7847 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
7848 kind == arm::kPointerWeakImport);
7849 }
7850
7851 template <>
7852 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
7853 {
7854 return false;
7855 }
7856
7857 template <>
7858 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
7859 {
7860 return false;
7861 }
7862
7863 template <>
7864 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
7865 {
7866 return false;
7867 }
7868
7869 template <>
7870 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
7871 {
7872 switch ( kind ) {
7873 case x86_64::kPCRel32GOT:
7874 case x86_64::kPCRel32GOTWeakImport:
7875 case x86_64::kPCRel32GOTLoad:
7876 case x86_64::kPCRel32GOTLoadWeakImport:
7877 case x86_64::kGOTNoFixUp:
7878 return true;
7879 }
7880 return false;
7881 }
7882
7883 template <>
7884 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
7885 {
7886 return false;
7887 }
7888
7889 template <>
7890 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
7891 {
7892 return false;
7893 }
7894
7895 template <>
7896 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
7897 {
7898 return false;
7899 }
7900
7901 template <>
7902 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
7903 {
7904 return false;
7905 }
7906
7907 template <>
7908 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
7909 {
7910 switch ( kind ) {
7911 case x86_64::kPCRel32GOTLoad:
7912 case x86_64::kPCRel32GOTLoadWeakImport:
7913 return true;
7914 }
7915 return false;
7916 }
7917
7918 template <>
7919 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
7920 {
7921 return false;
7922 }
7923
7924 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
7925 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
7926 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
7927 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
7928
7929
7930 template <typename A>
7931 void Writer<A>::optimizeDylibReferences()
7932 {
7933 //fprintf(stderr, "original ordinals table:\n");
7934 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7935 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7936 //}
7937 // find unused dylibs that can be removed
7938 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
7939 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
7940 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7941 ObjectFile::Reader* reader = it->first;
7942 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
7943 if ( aliasPos != fLibraryAliases.end() ) {
7944 // already noticed that this reader has same install name as another reader
7945 readerAliases[reader] = aliasPos->second;
7946 }
7947 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || reader->deadStrippable() || fOptions.deadStripDylibs()) ) {
7948 // this reader can be optimized away
7949 it->second = 0xFFFFFFFF;
7950 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
7951 if ( pos != fLibraryToLoadCommand.end() )
7952 pos->second->optimizeAway();
7953 }
7954 else {
7955 // mark this reader as using it ordinal
7956 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
7957 if ( pos == ordinalToReader.end() )
7958 ordinalToReader[it->second] = reader;
7959 else
7960 readerAliases[reader] = pos->second;
7961 }
7962 }
7963 // renumber ordinals (depends on iterator walking in ordinal order)
7964 // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
7965 uint32_t newOrdinal = 0;
7966 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7967 if ( it->first <= fLibraryToOrdinal.size() ) {
7968 if ( ! it->second->isLazyLoadedDylib() )
7969 fLibraryToOrdinal[it->second] = ++newOrdinal;
7970 }
7971 }
7972 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7973 if ( it->first <= fLibraryToOrdinal.size() ) {
7974 if ( it->second->isLazyLoadedDylib() ) {
7975 fLibraryToOrdinal[it->second] = ++newOrdinal;
7976 }
7977 }
7978 }
7979
7980 // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
7981 if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
7982 throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
7983
7984 // add aliases (e.g. -lm points to libSystem.dylib)
7985 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
7986 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
7987 }
7988
7989 //fprintf(stderr, "new ordinals table:\n");
7990 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7991 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7992 //}
7993 }
7994
7995
7996 template <>
7997 void Writer<arm>::scanForAbsoluteReferences()
7998 {
7999 // arm codegen never has absolute references. FIXME: Is this correct?
8000 }
8001
8002 template <>
8003 void Writer<x86_64>::scanForAbsoluteReferences()
8004 {
8005 // x86_64 codegen never has absolute references
8006 }
8007
8008 template <>
8009 void Writer<x86>::scanForAbsoluteReferences()
8010 {
8011 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
8012 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
8013 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8014 ObjectFile::Atom* atom = *it;
8015 if ( atom->getContentType() == ObjectFile::Atom::kStub )
8016 continue;
8017 if ( atom->getContentType() == ObjectFile::Atom::kStubHelper )
8018 continue;
8019 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8020 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8021 ObjectFile::Reference* ref = *rit;
8022 switch (ref->getKind()) {
8023 case x86::kAbsolute32:
8024 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
8025 return;
8026 }
8027 }
8028 }
8029 }
8030 }
8031
8032 template <>
8033 void Writer<ppc>::scanForAbsoluteReferences()
8034 {
8035 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
8036 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
8037 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8038 ObjectFile::Atom* atom = *it;
8039 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8040 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8041 ObjectFile::Reference* ref = *rit;
8042 switch (ref->getKind()) {
8043 case ppc::kAbsLow16:
8044 case ppc::kAbsLow14:
8045 case ppc::kAbsHigh16:
8046 case ppc::kAbsHigh16AddLow:
8047 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
8048 return;
8049 }
8050 }
8051 }
8052 }
8053 }
8054
8055
8056 // for ppc64 look for any -mdynamic-no-pic codegen
8057 template <>
8058 void Writer<ppc64>::scanForAbsoluteReferences()
8059 {
8060 // only do this for main executable
8061 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
8062 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8063 ObjectFile::Atom* atom = *it;
8064 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8065 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8066 ObjectFile::Reference* ref = *rit;
8067 switch (ref->getKind()) {
8068 case ppc64::kAbsLow16:
8069 case ppc64::kAbsLow14:
8070 case ppc64::kAbsHigh16:
8071 case ppc64::kAbsHigh16AddLow:
8072 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
8073 // shrink page-zero and add pad segment to compensate
8074 fPadSegmentInfo = new SegmentInfo(4096);
8075 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
8076 fPageZeroAtom->setSize(0x1000);
8077 return;
8078 }
8079 }
8080 }
8081 }
8082 }
8083
8084
8085 template <typename A>
8086 void Writer<A>::insertDummyStubs()
8087 {
8088 // only needed for x86
8089 }
8090
8091 template <>
8092 void Writer<x86>::insertDummyStubs()
8093 {
8094 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
8095 std::vector<class StubAtom<x86>*> betterStubs;
8096 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
8097 switch (betterStubs.size() % 64 ) {
8098 case 12:// stub would occupy 0x3C->0x41
8099 case 25:// stub would occupy 0x7D->0x82
8100 case 38:// stub would occupy 0xBE->0xC3
8101 case 51:// stub would occupy 0xFF->0x04
8102 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
8103 break;
8104 }
8105 betterStubs.push_back(*it);
8106 }
8107 // replace
8108 fAllSynthesizedStubs.clear();
8109 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
8110 }
8111
8112
8113 template <typename A>
8114 void Writer<A>::synthesizeKextGOT(const std::vector<class ObjectFile::Atom*>& existingAtoms,
8115 std::vector<class ObjectFile::Atom*>& newAtoms)
8116 {
8117 // walk every atom and reference
8118 for (std::vector<ObjectFile::Atom*>::const_iterator it=existingAtoms.begin(); it != existingAtoms.end(); it++) {
8119 const ObjectFile::Atom* atom = *it;
8120 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8121 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8122 ObjectFile::Reference* ref = *rit;
8123 switch ( ref->getTargetBinding()) {
8124 case ObjectFile::Reference::kUnboundByName:
8125 case ObjectFile::Reference::kDontBind:
8126 break;
8127 case ObjectFile::Reference::kBoundByName:
8128 case ObjectFile::Reference::kBoundDirectly:
8129 ObjectFile::Atom& target = ref->getTarget();
8130 // create GOT slots (non-lazy pointers) as needed
8131 if ( this->GOTReferenceKind(ref->getKind()) ) {
8132 bool useGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
8133 // if this GOT usage cannot be optimized away then make a GOT enry
8134 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
8135 useGOT = true;
8136 if ( useGOT ) {
8137 ObjectFile::Atom* nlp = NULL;
8138 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
8139 if ( pos == fGOTMap.end() ) {
8140 nlp = new NonLazyPointerAtom<A>(*this, target);
8141 fGOTMap[&target] = nlp;
8142 newAtoms.push_back(nlp);
8143 }
8144 else {
8145 nlp = pos->second;
8146 }
8147 // alter reference to use non lazy pointer instead
8148 ref->setTarget(*nlp, ref->getTargetOffset());
8149 }
8150 }
8151 // build map of which symbols need weak importing
8152 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
8153 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
8154 if ( this->weakImportReferenceKind(ref->getKind()) ) {
8155 fWeakImportMap[&target] = true;
8156 }
8157 }
8158 break;
8159 }
8160 }
8161 }
8162 }
8163
8164
8165 template <typename A>
8166 void Writer<A>::synthesizeStubs(const std::vector<class ObjectFile::Atom*>& existingAtoms,
8167 std::vector<class ObjectFile::Atom*>& newAtoms)
8168 {
8169 switch ( fOptions.outputKind() ) {
8170 case Options::kObjectFile:
8171 case Options::kPreload:
8172 // these output kinds never have stubs
8173 return;
8174 case Options::kKextBundle:
8175 // new kext need a synthesized GOT only
8176 synthesizeKextGOT(existingAtoms, newAtoms);
8177 return;
8178 case Options::kStaticExecutable:
8179 case Options::kDyld:
8180 case Options::kDynamicLibrary:
8181 case Options::kDynamicBundle:
8182 case Options::kDynamicExecutable:
8183 // try to synthesize stubs for these
8184 break;
8185 }
8186
8187 // walk every atom and reference
8188 for (std::vector<ObjectFile::Atom*>::const_iterator it=existingAtoms.begin(); it != existingAtoms.end(); it++) {
8189 ObjectFile::Atom* atom = *it;
8190 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8191 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8192 ObjectFile::Reference* ref = *rit;
8193 switch ( ref->getTargetBinding()) {
8194 case ObjectFile::Reference::kUnboundByName:
8195 case ObjectFile::Reference::kDontBind:
8196 break;
8197 case ObjectFile::Reference::kBoundByName:
8198 case ObjectFile::Reference::kBoundDirectly:
8199 ObjectFile::Atom& target = ref->getTarget();
8200 // build map of which symbols need weak importing
8201 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
8202 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
8203 bool weakImport = this->weakImportReferenceKind(ref->getKind());
8204 // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
8205 // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
8206 // in dylibs that are weakly linked.
8207 if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
8208 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
8209 pos = fLibraryToLoadCommand.find(target.getFile());
8210 if ( pos != fLibraryToLoadCommand.end() ) {
8211 if ( pos->second->linkedWeak() )
8212 weakImport = true;
8213 }
8214 }
8215 // <rdar://problem/6186838> -weak_library no longer forces uses to be weak_import
8216 if ( fForcedWeakImportReaders.count(target.getFile()) != 0 ) {
8217 fWeakImportMap[&target] = true;
8218 weakImport = true;
8219 }
8220
8221 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
8222 if ( pos == fWeakImportMap.end() ) {
8223 // target not in fWeakImportMap, so add
8224 fWeakImportMap[&target] = weakImport;
8225 }
8226 else {
8227 // target in fWeakImportMap, check for weakness mismatch
8228 if ( pos->second != weakImport ) {
8229 // found mismatch
8230 switch ( fOptions.weakReferenceMismatchTreatment() ) {
8231 case Options::kWeakReferenceMismatchError:
8232 throwf("mismatching weak references for symbol: %s", target.getName());
8233 case Options::kWeakReferenceMismatchWeak:
8234 pos->second = true;
8235 break;
8236 case Options::kWeakReferenceMismatchNonWeak:
8237 pos->second = false;
8238 break;
8239 }
8240 }
8241 }
8242 // update if we use a weak_import or a strong import from this dylib
8243 if ( fWeakImportMap[&target] )
8244 fDylibReadersWithWeakImports.insert(target.getFile());
8245 else
8246 fDylibReadersWithNonWeakImports.insert(target.getFile());
8247 }
8248 // create stubs as needed
8249 if ( this->stubableReference(atom, ref)
8250 && (ref->getTargetOffset() == 0)
8251 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
8252 ObjectFile::Atom* stub = NULL;
8253 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
8254 if ( pos == fStubsMap.end() ) {
8255 bool forLazyDylib = false;
8256 switch ( target.getDefinitionKind() ) {
8257 case ObjectFile::Atom::kRegularDefinition:
8258 case ObjectFile::Atom::kWeakDefinition:
8259 case ObjectFile::Atom::kAbsoluteSymbol:
8260 case ObjectFile::Atom::kTentativeDefinition:
8261 break;
8262 case ObjectFile::Atom::kExternalDefinition:
8263 case ObjectFile::Atom::kExternalWeakDefinition:
8264 if ( target.getFile()->isLazyLoadedDylib() )
8265 forLazyDylib = true;
8266 break;
8267 }
8268 // just-in-time, create GOT slot to dyld_stub_binder
8269 if ( fOptions.makeCompressedDyldInfo() && (fFastStubGOTAtom == NULL) ) {
8270 if ( fDyldCompressedHelperAtom == NULL )
8271 throw "missing symbol dyld_stub_binder";
8272 fFastStubGOTAtom = new NonLazyPointerAtom<A>(*this, *fDyldCompressedHelperAtom);
8273 }
8274 stub = new StubAtom<A>(*this, target, forLazyDylib);
8275 fStubsMap[&target] = stub;
8276 }
8277 else {
8278 stub = pos->second;
8279 }
8280 // alter reference to use stub instead
8281 ref->setTarget(*stub, 0);
8282 }
8283 else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
8284 throwf("illegal reference to %s in lazy loaded dylib from %s in %s",
8285 target.getDisplayName(), atom->getDisplayName(),
8286 atom->getFile()->getPath());
8287 }
8288 // create GOT slots (non-lazy pointers) as needed
8289 else if ( this->GOTReferenceKind(ref->getKind()) ) {
8290 //
8291 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
8292 bool useGOT;
8293 if ( fBiggerThanTwoGigs ) {
8294 // in big images use GOT for all zero fill atoms
8295 // this is just a heuristic and may need to be re-examined
8296 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
8297 }
8298 else {
8299 // < 2GB image so remove all GOT entries that we can
8300 useGOT = mustUseGOT;
8301 }
8302 // if this GOT usage cannot be optimized away then make a GOT enry
8303 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
8304 useGOT = true;
8305 if ( useGOT ) {
8306 ObjectFile::Atom* nlp = NULL;
8307 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
8308 if ( pos == fGOTMap.end() ) {
8309 nlp = new NonLazyPointerAtom<A>(*this, target);
8310 fGOTMap[&target] = nlp;
8311 }
8312 else {
8313 nlp = pos->second;
8314 }
8315 // alter reference to use non lazy pointer instead
8316 ref->setTarget(*nlp, ref->getTargetOffset());
8317 }
8318 }
8319 }
8320 }
8321 }
8322
8323 // sort stubs
8324 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
8325 // add dummy self-modifying stubs (x86 only)
8326 if ( ! fOptions.makeCompressedDyldInfo() )
8327 this->insertDummyStubs();
8328 // set ordinals so sorting is preserved
8329 uint32_t sortOrder = 0;
8330 for (typename std::vector<StubAtom<A>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++)
8331 (*it)->setSortingOrdinal(sortOrder++);
8332 std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter());
8333
8334 // sort lazy pointers
8335 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
8336 sortOrder = 0;
8337 for (typename std::vector<LazyPointerAtom<A>*>::iterator it=fAllSynthesizedLazyPointers.begin(); it != fAllSynthesizedLazyPointers.end(); it++)
8338 (*it)->setSortingOrdinal(sortOrder++);
8339 std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
8340
8341 // sort non-lazy pointers
8342 std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter());
8343 sortOrder = 0;
8344 for (typename std::vector<NonLazyPointerAtom<A>*>::iterator it=fAllSynthesizedNonLazyPointers.begin(); it != fAllSynthesizedNonLazyPointers.end(); it++)
8345 (*it)->setSortingOrdinal(sortOrder++);
8346 std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter());
8347
8348 // tell linker about all synthesized atoms
8349 newAtoms.insert(newAtoms.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
8350 newAtoms.insert(newAtoms.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
8351 newAtoms.insert(newAtoms.end(), fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
8352 newAtoms.insert(newAtoms.end(), fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
8353 newAtoms.insert(newAtoms.end(), fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8354
8355 }
8356
8357 template <typename A>
8358 void Writer<A>::createSplitSegContent()
8359 {
8360 // build LC_SEGMENT_SPLIT_INFO once all atoms exist
8361 if ( fSplitCodeToDataContentAtom != NULL ) {
8362 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8363 ObjectFile::Atom* atom = *it;
8364 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8365 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8366 ObjectFile::Reference* ref = *rit;
8367 switch ( ref->getTargetBinding()) {
8368 case ObjectFile::Reference::kUnboundByName:
8369 case ObjectFile::Reference::kDontBind:
8370 break;
8371 case ObjectFile::Reference::kBoundByName:
8372 case ObjectFile::Reference::kBoundDirectly:
8373 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
8374 this->addCrossSegmentRef(atom, ref);
8375 }
8376 break;
8377 }
8378 }
8379 }
8380 // bad codegen may cause LC_SEGMENT_SPLIT_INFO to be removed
8381 adjustLoadCommandsAndPadding();
8382 }
8383
8384 }
8385
8386
8387 template <typename A>
8388 void Writer<A>::synthesizeUnwindInfoTable()
8389 {
8390 if ( fUnwindInfoAtom != NULL ) {
8391 // walk every atom and gets its unwind info
8392 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8393 ObjectFile::Atom* atom = *it;
8394 if ( atom->beginUnwind() == atom->endUnwind() ) {
8395 // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
8396 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
8397 fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL, NULL);
8398 }
8399 else {
8400 // atom has unwind
8401 for ( ObjectFile::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
8402 fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getFDE(), atom->getLSDA(), atom->getPersonalityPointer());
8403 }
8404 }
8405 }
8406 }
8407 }
8408
8409
8410 template <typename A>
8411 void Writer<A>::partitionIntoSections()
8412 {
8413 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
8414
8415 // for every atom, set its sectionInfo object and section offset
8416 // build up fSegmentInfos along the way
8417 ObjectFile::Section* curSection = (ObjectFile::Section*)(-1);
8418 SectionInfo* currentSectionInfo = NULL;
8419 SegmentInfo* currentSegmentInfo = NULL;
8420 SectionInfo* cstringSectionInfo = NULL;
8421 unsigned int sectionIndex = 1;
8422 fSegmentInfos.reserve(8);
8423 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
8424 ObjectFile::Atom* atom = (*fAllAtoms)[i];
8425 if ( ((atom->getSection() != curSection) || (curSection==NULL))
8426 && ((currentSectionInfo == NULL)
8427 || (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)
8428 || (strcmp(atom->getSegment().getName(),currentSectionInfo->fSegmentName) != 0)) ) {
8429 if ( oneSegmentCommand ) {
8430 if ( currentSegmentInfo == NULL ) {
8431 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8432 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8433 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8434 this->fSegmentInfos.push_back(currentSegmentInfo);
8435 }
8436 currentSectionInfo = new SectionInfo();
8437 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8438 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8439 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8440 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8441 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
8442 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8443 currentSectionInfo->setIndex(sectionIndex++);
8444 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8445 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
8446 cstringSectionInfo = currentSectionInfo;
8447 }
8448 else {
8449 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
8450 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8451 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
8452 uint32_t initprot = 0;
8453 if ( atom->getSegment().isContentReadable() )
8454 initprot |= VM_PROT_READ;
8455 if ( atom->getSegment().isContentWritable() )
8456 initprot |= VM_PROT_WRITE;
8457 if ( atom->getSegment().isContentExecutable() )
8458 initprot |= VM_PROT_EXECUTE;
8459 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
8460 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
8461 currentSegmentInfo->fInitProtection = initprot;
8462 if ( initprot == 0 )
8463 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
8464 else if ( fOptions.architecture() == CPU_TYPE_ARM )
8465 currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init
8466 else
8467 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8468 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
8469 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
8470 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
8471 currentSegmentInfo->fInitProtection = it->init;
8472 currentSegmentInfo->fMaxProtection = it->max;
8473 }
8474 }
8475 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
8476 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
8477 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
8478 currentSegmentInfo->fIndependentAddress = true;
8479 if ( (fOptions.outputKind() == Options::kPreload) && (strcmp(currentSegmentInfo->fName, "__LINKEDIT")==0) )
8480 currentSegmentInfo->fHasLoadCommand = false;
8481 if ( strcmp(currentSegmentInfo->fName, "__HEADER")==0 )
8482 currentSegmentInfo->fHasLoadCommand = false;
8483 this->fSegmentInfos.push_back(currentSegmentInfo);
8484 }
8485 currentSectionInfo = new SectionInfo();
8486 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
8487 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8488 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8489 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8490 // check for -sectalign override
8491 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
8492 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
8493 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
8494 currentSectionInfo->fAlignment = it->alignment;
8495 }
8496 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8497 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
8498 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8499 currentSectionInfo->setIndex(sectionIndex++);
8500 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8501 }
8502 //fprintf(stderr, "new section %s for atom %s\n", atom->getSectionName(), atom->getDisplayName());
8503 if ( strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0 ) {
8504 fLoadCommandsSection = currentSectionInfo;
8505 fLoadCommandsSegment = currentSegmentInfo;
8506 }
8507 switch ( atom->getContentType() ) {
8508 case ObjectFile::Atom::kLazyPointer:
8509 currentSectionInfo->fAllLazyPointers = true;
8510 fSymbolTableCommands->needDynamicTable();
8511 break;
8512 case ObjectFile::Atom::kNonLazyPointer:
8513 currentSectionInfo->fAllNonLazyPointers = true;
8514 fSymbolTableCommands->needDynamicTable();
8515 break;
8516 case ObjectFile::Atom::kLazyDylibPointer:
8517 currentSectionInfo->fAllLazyDylibPointers = true;
8518 break;
8519 case ObjectFile::Atom::kStubHelper:
8520 currentSectionInfo->fAllStubHelpers = true;
8521 break;
8522 case ObjectFile::Atom::kCFIType:
8523 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
8524 break;
8525 case ObjectFile::Atom::kStub:
8526 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
8527 currentSectionInfo->fAllSelfModifyingStubs = true;
8528 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
8529 }
8530 else {
8531 currentSectionInfo->fAllStubs = true;
8532 }
8533 fSymbolTableCommands->needDynamicTable();
8534 break;
8535 default:
8536 break;
8537 }
8538 curSection = atom->getSection();
8539 }
8540 // any non-zero fill atoms make whole section marked not-zero-fill
8541 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
8542 currentSectionInfo->fAllZeroFill = false;
8543 // change section object to be Writer's SectionInfo object
8544 atom->setSection(currentSectionInfo);
8545 // section alignment is that of a contained atom with the greatest alignment
8546 uint8_t atomAlign = atom->getAlignment().powerOf2;
8547 if ( currentSectionInfo->fAlignment < atomAlign )
8548 currentSectionInfo->fAlignment = atomAlign;
8549 // calculate section offset for this atom
8550 uint64_t offset = currentSectionInfo->fSize;
8551 uint64_t alignment = 1 << atomAlign;
8552 uint64_t currentModulus = (offset % alignment);
8553 uint64_t requiredModulus = atom->getAlignment().modulus;
8554 if ( currentModulus != requiredModulus ) {
8555 if ( requiredModulus > currentModulus )
8556 offset += requiredModulus-currentModulus;
8557 else
8558 offset += requiredModulus+alignment-currentModulus;
8559 }
8560 atom->setSectionOffset(offset);
8561 uint64_t curAtomSize = atom->getSize();
8562 currentSectionInfo->fSize = offset + curAtomSize;
8563 // add atom to section vector
8564 currentSectionInfo->fAtoms.push_back(atom);
8565 //fprintf(stderr, " adding atom %p %s size=0x%0llX to section %p %s from %s\n", atom, atom->getDisplayName(), atom->getSize(),
8566 // currentSectionInfo, currentSectionInfo->fSectionName, atom->getFile()->getPath());
8567 // update largest size
8568 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
8569 fLargestAtomSize = curAtomSize;
8570 }
8571 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
8572 // when merging cstring sections in .o files, all strings need to use the max alignment
8573 uint64_t offset = 0;
8574 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
8575 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
8576 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
8577 ObjectFile::Atom* atom = *it;
8578 atom->setSectionOffset(offset);
8579 offset += atom->getSize();
8580 }
8581 cstringSectionInfo->fSize = offset;
8582 }
8583 }
8584
8585
8586 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
8587 class TargetAndOffsetComparor
8588 {
8589 public:
8590 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
8591 {
8592 if ( left.atom != right.atom )
8593 return ( left.atom < right.atom );
8594 return ( left.offset < right.offset );
8595 }
8596 };
8597
8598 template <>
8599 bool Writer<ppc>::addBranchIslands()
8600 {
8601 return this->createBranchIslands();
8602 }
8603
8604 template <>
8605 bool Writer<ppc64>::addBranchIslands()
8606 {
8607 return this->createBranchIslands();
8608 }
8609
8610 template <>
8611 bool Writer<x86>::addBranchIslands()
8612 {
8613 // x86 branches can reach entire 4G address space, so no need for branch islands
8614 return false;
8615 }
8616
8617 template <>
8618 bool Writer<x86_64>::addBranchIslands()
8619 {
8620 // x86 branches can reach entire 4G size of largest image
8621 return false;
8622 }
8623
8624 template <>
8625 bool Writer<arm>::addBranchIslands()
8626 {
8627 return this->createBranchIslands();
8628 }
8629
8630 template <>
8631 bool Writer<ppc>::isBranchThatMightNeedIsland(uint8_t kind)
8632 {
8633 switch (kind) {
8634 case ppc::kBranch24:
8635 case ppc::kBranch24WeakImport:
8636 return true;
8637 }
8638 return false;
8639 }
8640
8641 template <>
8642 bool Writer<ppc64>::isBranchThatMightNeedIsland(uint8_t kind)
8643 {
8644 switch (kind) {
8645 case ppc64::kBranch24:
8646 case ppc64::kBranch24WeakImport:
8647 return true;
8648 }
8649 return false;
8650 }
8651
8652 template <>
8653 bool Writer<arm>::isBranchThatMightNeedIsland(uint8_t kind)
8654 {
8655 switch (kind) {
8656 case arm::kBranch24:
8657 case arm::kBranch24WeakImport:
8658 case arm::kThumbBranch22:
8659 case arm::kThumbBranch22WeakImport:
8660 return true;
8661 }
8662 return false;
8663 }
8664
8665 template <>
8666 uint32_t Writer<ppc>::textSizeWhenMightNeedBranchIslands()
8667 {
8668 return 16000000;
8669 }
8670
8671 template <>
8672 uint32_t Writer<ppc64>::textSizeWhenMightNeedBranchIslands()
8673 {
8674 return 16000000;
8675 }
8676
8677 template <>
8678 uint32_t Writer<arm>::textSizeWhenMightNeedBranchIslands()
8679 {
8680 if ( fHasThumbBranches == false )
8681 return 32000000; // ARM can branch +/- 32MB
8682 else if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 )
8683 return 16000000; // thumb2 can branch +/- 16MB
8684 else
8685 return 4000000; // thumb1 can branch +/- 4MB
8686 }
8687
8688 template <>
8689 uint32_t Writer<ppc>::maxDistanceBetweenIslands()
8690 {
8691 return 14*1024*1024;
8692 }
8693
8694 template <>
8695 uint32_t Writer<ppc64>::maxDistanceBetweenIslands()
8696 {
8697 return 14*1024*1024;
8698 }
8699
8700 template <>
8701 uint32_t Writer<arm>::maxDistanceBetweenIslands()
8702 {
8703 if ( fHasThumbBranches == false )
8704 return 30*1024*1024;
8705 else if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 )
8706 return 14*1024*1024;
8707 else
8708 return 3500000;
8709 }
8710
8711
8712 //
8713 // PowerPC can do PC relative branches as far as +/-16MB.
8714 // If a branch target is >16MB then we insert one or more
8715 // "branch islands" between the branch and its target that
8716 // allows island hopping to the target.
8717 //
8718 // Branch Island Algorithm
8719 //
8720 // If the __TEXT segment < 16MB, then no branch islands needed
8721 // Otherwise, every 14MB into the __TEXT segment a region is
8722 // added which can contain branch islands. Every out-of-range
8723 // bl instruction is checked. If it crosses a region, an island
8724 // is added to that region with the same target and the bl is
8725 // adjusted to target the island instead.
8726 //
8727 // In theory, if too many islands are added to one region, it
8728 // could grow the __TEXT enough that other previously in-range
8729 // bl branches could be pushed out of range. We reduce the
8730 // probability this could happen by placing the ranges every
8731 // 14MB which means the region would have to be 2MB (512,000 islands)
8732 // before any branches could be pushed out of range.
8733 //
8734 template <typename A>
8735 bool Writer<A>::createBranchIslands()
8736 {
8737 bool log = false;
8738 bool result = false;
8739 // Can only possibly need branch islands if __TEXT segment > 16M
8740 if ( fLoadCommandsSegment->fSize > textSizeWhenMightNeedBranchIslands() ) {
8741 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
8742 const uint32_t kBetweenRegions = maxDistanceBetweenIslands(); // place regions of islands every 14MB in __text section
8743 SectionInfo* textSection = NULL;
8744 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
8745 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
8746 textSection = *it;
8747 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
8748 break;
8749 }
8750 }
8751 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
8752 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
8753 AtomToIsland regionsMap[kIslandRegionsCount];
8754 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
8755 unsigned int islandCount = 0;
8756 if (log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
8757
8758 // create islands for branch references that are out of range
8759 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8760 ObjectFile::Atom* atom = *it;
8761 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8762 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8763 ObjectFile::Reference* ref = *rit;
8764 if ( this->isBranchThatMightNeedIsland(ref->getKind()) ) {
8765 ObjectFile::Atom& target = ref->getTarget();
8766 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
8767 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
8768 int64_t displacement = dstAddr - srcAddr;
8769 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
8770 const int64_t kBranchLimit = kBetweenRegions;
8771 if ( displacement > kBranchLimit ) {
8772 // create forward branch chain
8773 ObjectFile::Atom* nextTarget = &target;
8774 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
8775 AtomToIsland* region = &regionsMap[i];
8776 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
8777 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
8778 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8779 if ( pos == region->end() ) {
8780 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, *finalTargetAndOffset.atom, finalTargetAndOffset.offset);
8781 island->setSection(textSection);
8782 (*region)[finalTargetAndOffset] = island;
8783 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8784 regionsIslands[i].push_back(island);
8785 ++islandCount;
8786 nextTarget = island;
8787 }
8788 else {
8789 nextTarget = pos->second;
8790 }
8791 }
8792 }
8793 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
8794 ref->setTarget(*nextTarget, 0);
8795 }
8796 else if ( displacement < (-kBranchLimit) ) {
8797 // create back branching chain
8798 ObjectFile::Atom* prevTarget = &target;
8799 for (int i=0; i < kIslandRegionsCount ; ++i) {
8800 AtomToIsland* region = &regionsMap[i];
8801 int64_t islandRegionAddr = kBetweenRegions * (i+1);
8802 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
8803 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8804 if ( pos == region->end() ) {
8805 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, *finalTargetAndOffset.atom, finalTargetAndOffset.offset);
8806 island->setSection(textSection);
8807 (*region)[finalTargetAndOffset] = island;
8808 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8809 regionsIslands[i].push_back(island);
8810 ++islandCount;
8811 prevTarget = island;
8812 }
8813 else {
8814 prevTarget = pos->second;
8815 }
8816 }
8817 }
8818 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
8819 ref->setTarget(*prevTarget, 0);
8820 }
8821 }
8822 }
8823 }
8824
8825 // insert islands into __text section and adjust section offsets
8826 if ( islandCount > 0 ) {
8827 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
8828 std::vector<ObjectFile::Atom*> newAtomList;
8829 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
8830 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
8831 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
8832 int regionIndex = 0;
8833 uint64_t atomSlide = 0;
8834 uint64_t sectionOffset = 0;
8835 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
8836 ObjectFile::Atom* atom = *it;
8837 if ( (atom->getAddress()+atom->getSize()) > islandRegionAddr ) {
8838 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
8839 sectionOffset = islandStartOffset;
8840 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
8841 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8842 ObjectFile::Atom* islandAtom = *rit;
8843 newAtomList.push_back(islandAtom);
8844 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8845 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8846 islandAtom->setSectionOffset(sectionOffset);
8847 if ( log ) fprintf(stderr, "assigning __text offset 0x%08llx to %s\n", sectionOffset, islandAtom->getDisplayName());
8848 sectionOffset += islandAtom->getSize();
8849 }
8850 ++regionIndex;
8851 islandRegionAddr += kBetweenRegions;
8852 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
8853 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
8854 }
8855 newAtomList.push_back(atom);
8856 if ( atomSlide != 0 )
8857 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
8858 }
8859 sectionOffset = textSection->fSize+atomSlide;
8860 // put any remaining islands at end of __text section
8861 if ( regionIndex < kIslandRegionsCount ) {
8862 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
8863 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8864 ObjectFile::Atom* islandAtom = *rit;
8865 newAtomList.push_back(islandAtom);
8866 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8867 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8868 islandAtom->setSectionOffset(sectionOffset);
8869 if ( log ) fprintf(stderr, "assigning __text offset 0x%08llx to %s\n", sectionOffset, islandAtom->getDisplayName());
8870 sectionOffset += islandAtom->getSize();
8871 }
8872 }
8873
8874 textSection->fAtoms = newAtomList;
8875 textSection->fSize = sectionOffset;
8876 result = true;
8877 }
8878
8879 }
8880 return result;
8881 }
8882
8883
8884 template <typename A>
8885 void Writer<A>::adjustLoadCommandsAndPadding()
8886 {
8887 fSegmentCommands->computeSize();
8888
8889 // recompute load command section offsets
8890 uint64_t offset = 0;
8891 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
8892 const unsigned int atomCount = loadCommandAtoms.size();
8893 for (unsigned int i=0; i < atomCount; ++i) {
8894 ObjectFile::Atom* atom = loadCommandAtoms[i];
8895 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
8896 offset = ( (offset+alignment-1) & (-alignment) );
8897 atom->setSectionOffset(offset);
8898 uint32_t atomSize = atom->getSize();
8899 if ( atomSize > fLargestAtomSize )
8900 fLargestAtomSize = atomSize;
8901 offset += atomSize;
8902 fLoadCommandsSection->fSize = offset;
8903 }
8904 const uint32_t sizeOfLoadCommandsPlusHeader = offset + sizeof(macho_header<typename A::P>);
8905
8906 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
8907 const int sectionCount = sectionInfos.size();
8908 uint32_t totalSizeOfTEXTLessHeaderAndLoadCommands = 0;
8909 for(int j=0; j < sectionCount; ++j) {
8910 SectionInfo* curSection = sectionInfos[j];
8911 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8912 break;
8913 totalSizeOfTEXTLessHeaderAndLoadCommands += curSection->fSize;
8914 }
8915 uint64_t paddingSize = 0;
8916 if ( fOptions.outputKind() == Options::kDyld ) {
8917 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
8918 paddingSize = 4096 - (totalSizeOfTEXTLessHeaderAndLoadCommands % 4096);
8919 }
8920 else if ( fOptions.outputKind() == Options::kObjectFile ) {
8921 // mach-o .o files need no padding between load commands and first section
8922 // but leave enough room that the object file could be signed
8923 paddingSize = 32;
8924 }
8925 else if ( fOptions.outputKind() == Options::kPreload ) {
8926 // mach-o MH_PRELOAD files need no padding between load commands and first section
8927 paddingSize = 0;
8928 }
8929 else {
8930 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
8931 uint64_t addr = 0;
8932 for(int j=sectionCount-1; j >=0; --j) {
8933 SectionInfo* curSection = sectionInfos[j];
8934 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
8935 addr -= (fLoadCommandsSection->fSize+fMachHeaderAtom->getSize());
8936 paddingSize = addr % fOptions.segmentAlignment();
8937 break;
8938 }
8939 addr -= curSection->fSize;
8940 addr = addr & (0 - (1 << curSection->fAlignment));
8941 }
8942
8943 // if command line requires more padding than this
8944 uint32_t minPad = fOptions.minimumHeaderPad();
8945 if ( fOptions.maxMminimumHeaderPad() ) {
8946 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
8947 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
8948 if ( fOptions.outputKind() == Options::kDynamicLibrary )
8949 altMin += MAXPATHLEN;
8950 if ( altMin > minPad )
8951 minPad = altMin;
8952 }
8953 if ( paddingSize < minPad ) {
8954 int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment();
8955 paddingSize += extraPages * fOptions.segmentAlignment();
8956 }
8957
8958 if ( fOptions.makeEncryptable() ) {
8959 // load commands must be on a separate non-encrypted page
8960 int loadCommandsPage = (sizeOfLoadCommandsPlusHeader + minPad)/fOptions.segmentAlignment();
8961 int textPage = (sizeOfLoadCommandsPlusHeader + paddingSize)/fOptions.segmentAlignment();
8962 if ( loadCommandsPage == textPage ) {
8963 paddingSize += fOptions.segmentAlignment();
8964 textPage += 1;
8965 }
8966
8967 //paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
8968 fEncryptionLoadCommand->setStartEncryptionOffset(textPage*fOptions.segmentAlignment());
8969 }
8970 }
8971
8972 // adjust atom size and update section size
8973 fHeaderPadding->setSize(paddingSize);
8974 for(int j=0; j < sectionCount; ++j) {
8975 SectionInfo* curSection = sectionInfos[j];
8976 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8977 curSection->fSize = paddingSize;
8978 }
8979 }
8980
8981 static uint64_t segmentAlign(uint64_t addr, uint64_t alignment)
8982 {
8983 return ((addr+alignment-1) & (-alignment));
8984 }
8985
8986 // assign file offsets and logical address to all segments
8987 template <typename A>
8988 void Writer<A>::assignFileOffsets()
8989 {
8990 const bool virtualSectionOccupyAddressSpace = ((fOptions.outputKind() != Options::kObjectFile)
8991 && (fOptions.outputKind() != Options::kPreload));
8992 bool haveFixedSegments = false;
8993 uint64_t fileOffset = 0;
8994 uint64_t nextContiguousAddress = fOptions.baseAddress();
8995 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
8996 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
8997
8998 // process segments with fixed addresses (-segaddr)
8999 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
9000 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9001 SegmentInfo* curSegment = *segit;
9002 if ( strcmp(curSegment->fName, it->name) == 0 ) {
9003 curSegment->fBaseAddress = it->address;
9004 curSegment->fFixedAddress = true;
9005 break;
9006 }
9007 }
9008 }
9009
9010 // process segments with fixed addresses (-seg_page_size)
9011 for (std::vector<Options::SegmentSize>::iterator it = fOptions.customSegmentSizes().begin(); it != fOptions.customSegmentSizes().end(); ++it) {
9012 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9013 SegmentInfo* curSegment = *segit;
9014 if ( strcmp(curSegment->fName, it->name) == 0 ) {
9015 curSegment->fPageSize = it->size;
9016 break;
9017 }
9018 }
9019 }
9020
9021 // Run through the segments and each segment's sections to assign addresses
9022 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9023 SegmentInfo* curSegment = *segit;
9024
9025 if ( fOptions.splitSeg() ) {
9026 if ( curSegment->fInitProtection & VM_PROT_WRITE )
9027 nextContiguousAddress = nextWritableAddress;
9028 else
9029 nextContiguousAddress = nextReadOnlyAddress;
9030 }
9031
9032 if ( fOptions.outputKind() == Options::kPreload ) {
9033 if ( strcmp(curSegment->fName, "__HEADER") == 0 )
9034 nextContiguousAddress = 0;
9035 else if ( strcmp(curSegment->fName, "__TEXT") == 0 )
9036 nextContiguousAddress = fOptions.baseAddress();
9037 }
9038
9039 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
9040 curSegment->fFileOffset = fileOffset;
9041
9042 // Set the segment base address
9043 if ( curSegment->fFixedAddress )
9044 haveFixedSegments = true;
9045 else
9046 curSegment->fBaseAddress = segmentAlign(nextContiguousAddress, curSegment->fPageSize);
9047
9048 // We've set the segment address, now run through each section.
9049 uint64_t address = curSegment->fBaseAddress;
9050 SectionInfo* firstZeroFillSection = NULL;
9051 SectionInfo* prevSection = NULL;
9052
9053 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
9054
9055 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
9056 SectionInfo* curSection = *it;
9057
9058 // adjust section address based on alignment
9059 uint64_t alignment = 1 << curSection->fAlignment;
9060 if ( curSection->fAtoms.size() == 1 ) {
9061 // if there is only one atom in section, use modulus for even better layout
9062 ObjectFile::Alignment atomAlign = curSection->fAtoms[0]->getAlignment();
9063 uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
9064 uint64_t currentModulus = (address % atomAlignP2);
9065 if ( currentModulus != atomAlign.modulus ) {
9066 if ( atomAlign.modulus > currentModulus )
9067 address += atomAlign.modulus-currentModulus;
9068 else
9069 address += atomAlign.modulus+atomAlignP2-currentModulus;
9070 }
9071 }
9072 else {
9073 address = ( (address+alignment-1) & (-alignment) );
9074 }
9075 // adjust file offset to match address
9076 if ( prevSection != NULL ) {
9077 if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection )
9078 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
9079 else
9080 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
9081 }
9082
9083 // update section info
9084 curSection->fFileOffset = fileOffset;
9085 curSection->setBaseAddress(address);
9086 //fprintf(stderr, "%s %s addr=0x%llX, fileoffset=0x%llX, size=0x%llX\n", curSegment->fName, curSection->fSectionName, address, fileOffset, curSection->fSize);
9087
9088 // keep track of trailing zero fill sections
9089 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
9090 firstZeroFillSection = curSection;
9091 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && (fOptions.outputKind() != Options::kObjectFile) )
9092 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
9093
9094 // update running pointers
9095 if ( virtualSectionOccupyAddressSpace || !curSection->fVirtualSection )
9096 address += curSection->fSize;
9097 fileOffset += curSection->fSize;
9098
9099 // sanity check size of 32-bit binaries
9100 if ( address > maxAddress() )
9101 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
9102
9103 // update segment info
9104 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
9105 curSegment->fSize = curSegment->fFileSize;
9106 prevSection = curSection;
9107 }
9108
9109 if ( fOptions.outputKind() == Options::kObjectFile ) {
9110 // don't page align .o files
9111 }
9112 else {
9113 // optimize trailing zero-fill sections to not occupy disk space
9114 if ( firstZeroFillSection != NULL ) {
9115 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
9116 fileOffset = firstZeroFillSection->fFileOffset;
9117 }
9118 // page align segment size
9119 curSegment->fFileSize = segmentAlign(curSegment->fFileSize, curSegment->fPageSize);
9120 curSegment->fSize = segmentAlign(curSegment->fSize, curSegment->fPageSize);
9121 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
9122 nextContiguousAddress = segmentAlign(curSegment->fBaseAddress+curSegment->fSize, curSegment->fPageSize);
9123 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
9124 if ( curSegment->fInitProtection & VM_PROT_WRITE )
9125 nextWritableAddress = nextContiguousAddress;
9126 else
9127 nextReadOnlyAddress = nextContiguousAddress;
9128 }
9129 }
9130 //fprintf(stderr, "end of seg %s, fileoffset=0x%llX, nextContiguousAddress=0x%llX\n", curSegment->fName, fileOffset, nextContiguousAddress);
9131 }
9132
9133 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
9134 if ( haveFixedSegments ) {
9135 int segCount = fSegmentInfos.size();
9136 for(int i=0; i < segCount; ++i) {
9137 SegmentInfo* segment1 = fSegmentInfos[i];
9138
9139 for(int j=0; j < segCount; ++j) {
9140 if ( i != j ) {
9141 SegmentInfo* segment2 = fSegmentInfos[j];
9142
9143 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
9144 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
9145 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9146 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9147 }
9148 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
9149 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
9150 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9151 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9152 }
9153 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
9154 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9155 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9156 }
9157 }
9158 }
9159 }
9160 }
9161
9162 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
9163 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9164 SegmentInfo* curSegment = *segit;
9165 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
9166 if ( fFirstWritableSegment == NULL )
9167 fFirstWritableSegment = curSegment;
9168 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
9169 fWritableSegmentPastFirst4GB = true;
9170 }
9171 }
9172
9173 // record size of encrypted part of __TEXT segment
9174 if ( fOptions.makeEncryptable() ) {
9175 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9176 SegmentInfo* curSegment = *segit;
9177 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
9178 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
9179 break;
9180 }
9181 }
9182 }
9183
9184 }
9185
9186 template <typename A>
9187 void Writer<A>::adjustLinkEditSections()
9188 {
9189 // link edit content is always in last segment
9190 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
9191 unsigned int firstLinkEditSectionIndex = 0;
9192 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
9193 ++firstLinkEditSectionIndex;
9194
9195 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
9196 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
9197 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
9198 if ( fPadSegmentInfo != NULL ) {
9199 // insert __4GBFILL segment into segments vector before LINKEDIT
9200 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
9201 if ( *it == lastSeg ) {
9202 fSegmentInfos.insert(it, fPadSegmentInfo);
9203 break;
9204 }
9205 }
9206 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
9207 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
9208 fPadSegmentInfo->fBaseAddress = address;
9209 // adjust LINKEDIT to start at zeroPageSize
9210 address = fOptions.zeroPageSize();
9211 lastSeg->fBaseAddress = fOptions.zeroPageSize();
9212 }
9213 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
9214 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
9215 // adjust section address based on alignment
9216 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
9217 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
9218 address += pad;
9219 fileOffset += pad; // adjust file offset to match address
9220 lastSeg->fSections[i]->setBaseAddress(address);
9221 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
9222 lastSeg->fSections[i]->setBaseAddress(0);
9223 lastSeg->fSections[i]->fFileOffset = fileOffset;
9224 uint64_t sectionOffset = 0;
9225 for (unsigned int j=0; j < atoms.size(); ++j) {
9226 ObjectFile::Atom* atom = atoms[j];
9227 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
9228 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
9229 atom->setSectionOffset(sectionOffset);
9230 uint64_t size = atom->getSize();
9231 sectionOffset += size;
9232 if ( size > fLargestAtomSize )
9233 fLargestAtomSize = size;
9234 }
9235 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
9236 lastSeg->fSections[i]->fSize = sectionOffset;
9237 fileOffset += sectionOffset;
9238 address += sectionOffset;
9239 }
9240 if ( fOptions.outputKind() == Options::kObjectFile ) {
9241 //lastSeg->fBaseAddress = 0;
9242 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
9243 //lastSeg->fFileOffset = 0;
9244 //lastSeg->fFileSize =
9245 }
9246 else {
9247 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
9248 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
9249 }
9250 }
9251
9252
9253 template <typename A>
9254 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
9255 {
9256 switch ( fWriter.fOptions.outputKind() ) {
9257 case Options::kDynamicExecutable:
9258 case Options::kStaticExecutable:
9259 return ObjectFile::Atom::scopeGlobal;
9260 case Options::kDynamicLibrary:
9261 case Options::kDynamicBundle:
9262 case Options::kDyld:
9263 case Options::kObjectFile:
9264 case Options::kPreload:
9265 case Options::kKextBundle:
9266 return ObjectFile::Atom::scopeLinkageUnit;
9267 }
9268 throw "unknown header type";
9269 }
9270
9271 template <typename A>
9272 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
9273 {
9274 switch ( fWriter.fOptions.outputKind() ) {
9275 case Options::kDynamicExecutable:
9276 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
9277 case Options::kStaticExecutable:
9278 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
9279 case Options::kDynamicLibrary:
9280 case Options::kDynamicBundle:
9281 case Options::kDyld:
9282 return ObjectFile::Atom::kSymbolTableIn;
9283 case Options::kObjectFile:
9284 case Options::kPreload:
9285 case Options::kKextBundle:
9286 return ObjectFile::Atom::kSymbolTableNotIn;
9287 }
9288 throw "unknown header type";
9289 }
9290
9291 template <typename A>
9292 const char* MachHeaderAtom<A>::getName() const
9293 {
9294 switch ( fWriter.fOptions.outputKind() ) {
9295 case Options::kDynamicExecutable:
9296 case Options::kStaticExecutable:
9297 return "__mh_execute_header";
9298 case Options::kDynamicLibrary:
9299 return "__mh_dylib_header";
9300 case Options::kDynamicBundle:
9301 return "__mh_bundle_header";
9302 case Options::kObjectFile:
9303 case Options::kPreload:
9304 case Options::kKextBundle:
9305 return NULL;
9306 case Options::kDyld:
9307 return "__mh_dylinker_header";
9308 }
9309 throw "unknown header type";
9310 }
9311
9312 template <typename A>
9313 const char* MachHeaderAtom<A>::getDisplayName() const
9314 {
9315 switch ( fWriter.fOptions.outputKind() ) {
9316 case Options::kDynamicExecutable:
9317 case Options::kStaticExecutable:
9318 case Options::kDynamicLibrary:
9319 case Options::kDynamicBundle:
9320 case Options::kDyld:
9321 return this->getName();
9322 case Options::kObjectFile:
9323 case Options::kPreload:
9324 case Options::kKextBundle:
9325 return "mach header";
9326 }
9327 throw "unknown header type";
9328 }
9329
9330 template <typename A>
9331 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
9332 {
9333 // get file type
9334 uint32_t fileType = 0;
9335 switch ( fWriter.fOptions.outputKind() ) {
9336 case Options::kDynamicExecutable:
9337 case Options::kStaticExecutable:
9338 fileType = MH_EXECUTE;
9339 break;
9340 case Options::kDynamicLibrary:
9341 fileType = MH_DYLIB;
9342 break;
9343 case Options::kDynamicBundle:
9344 fileType = MH_BUNDLE;
9345 break;
9346 case Options::kObjectFile:
9347 fileType = MH_OBJECT;
9348 break;
9349 case Options::kDyld:
9350 fileType = MH_DYLINKER;
9351 break;
9352 case Options::kPreload:
9353 fileType = MH_PRELOAD;
9354 break;
9355 case Options::kKextBundle:
9356 fileType = MH_KEXT_BUNDLE;
9357 break;
9358 }
9359
9360 // get flags
9361 uint32_t flags = 0;
9362 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
9363 if ( fWriter.fCanScatter )
9364 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
9365 }
9366 else {
9367 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
9368 flags |= MH_NOUNDEFS;
9369 }
9370 else if ( fWriter.fOptions.outputKind() == Options::kPreload ) {
9371 flags |= MH_NOUNDEFS;
9372 if ( fWriter.fOptions.positionIndependentExecutable() )
9373 flags |= MH_PIE;
9374 }
9375 else {
9376 flags = MH_DYLDLINK;
9377 if ( fWriter.fOptions.bindAtLoad() )
9378 flags |= MH_BINDATLOAD;
9379 switch ( fWriter.fOptions.nameSpace() ) {
9380 case Options::kTwoLevelNameSpace:
9381 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
9382 break;
9383 case Options::kFlatNameSpace:
9384 break;
9385 case Options::kForceFlatNameSpace:
9386 flags |= MH_FORCE_FLAT;
9387 break;
9388 }
9389 bool hasWeakDefines = fWriter.fHasWeakExports;
9390 if ( fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->size() != 0 ) {
9391 for(std::set<const ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
9392 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
9393 if ( fWriter.shouldExport(**it) ) {
9394 hasWeakDefines = true;
9395 break;
9396 }
9397 }
9398 }
9399 if ( hasWeakDefines )
9400 flags |= MH_WEAK_DEFINES;
9401 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
9402 flags |= MH_BINDS_TO_WEAK;
9403 if ( fWriter.fOptions.prebind() )
9404 flags |= MH_PREBOUND;
9405 if ( fWriter.fOptions.splitSeg() )
9406 flags |= MH_SPLIT_SEGS;
9407 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
9408 flags |= MH_NO_REEXPORTED_DYLIBS;
9409 if ( fWriter.fOptions.positionIndependentExecutable() )
9410 flags |= MH_PIE;
9411 if ( fWriter.fOptions.markAutoDeadStripDylib() )
9412 flags |= MH_DEAD_STRIPPABLE_DYLIB;
9413 }
9414 if ( fWriter.fOptions.hasExecutableStack() )
9415 flags |= MH_ALLOW_STACK_EXECUTION;
9416 if ( fWriter.fOptions.readerOptions().fRootSafe )
9417 flags |= MH_ROOT_SAFE;
9418 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
9419 flags |= MH_SETUID_SAFE;
9420 }
9421
9422 // get commands info
9423 uint32_t commandsSize = 0;
9424 uint32_t commandsCount = 0;
9425
9426 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
9427 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
9428 ObjectFile::Atom* atom = *it;
9429 commandsSize += atom->getSize();
9430 // segment and symbol table atoms can contain more than one load command
9431 if ( atom == fWriter.fSegmentCommands )
9432 commandsCount += fWriter.fSegmentCommands->commandCount();
9433 else if ( atom == fWriter.fSymbolTableCommands )
9434 commandsCount += fWriter.fSymbolTableCommands->commandCount();
9435 else if ( atom->getSize() != 0 )
9436 ++commandsCount;
9437 }
9438
9439 // fill out mach_header
9440 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
9441 setHeaderInfo(*mh);
9442 mh->set_filetype(fileType);
9443 mh->set_ncmds(commandsCount);
9444 mh->set_sizeofcmds(commandsSize);
9445 mh->set_flags(flags);
9446 }
9447
9448 template <>
9449 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
9450 {
9451 header.set_magic(MH_MAGIC);
9452 header.set_cputype(CPU_TYPE_POWERPC);
9453 header.set_cpusubtype(fWriter.fCpuConstraint);
9454 }
9455
9456 template <>
9457 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
9458 {
9459 header.set_magic(MH_MAGIC_64);
9460 header.set_cputype(CPU_TYPE_POWERPC64);
9461 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9462 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
9463 else
9464 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
9465 header.set_reserved(0);
9466 }
9467
9468 template <>
9469 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
9470 {
9471 header.set_magic(MH_MAGIC);
9472 header.set_cputype(CPU_TYPE_I386);
9473 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
9474 }
9475
9476 template <>
9477 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
9478 {
9479 header.set_magic(MH_MAGIC_64);
9480 header.set_cputype(CPU_TYPE_X86_64);
9481 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9482 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
9483 else
9484 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
9485 header.set_reserved(0);
9486 }
9487
9488 template <>
9489 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
9490 {
9491 header.set_magic(MH_MAGIC);
9492 header.set_cputype(CPU_TYPE_ARM);
9493 header.set_cpusubtype(fWriter.fCpuConstraint);
9494 }
9495
9496 template <typename A>
9497 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
9498 : WriterAtom<A>(writer, Segment::fgStackSegment)
9499 {
9500 if ( stackGrowsDown() )
9501 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
9502 else
9503 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
9504 }
9505
9506
9507 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
9508 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
9509 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
9510 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
9511 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
9512
9513 template <typename A>
9514 void SegmentLoadCommandsAtom<A>::computeSize()
9515 {
9516 uint64_t size = 0;
9517 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9518 int segCount = 0;
9519 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9520 SegmentInfo* seg = *it;
9521 if ( seg->fHasLoadCommand ) {
9522 ++segCount;
9523 size += sizeof(macho_segment_command<P>);
9524 std::vector<SectionInfo*>& sectionInfos = seg->fSections;
9525 const int sectionCount = sectionInfos.size();
9526 for(int j=0; j < sectionCount; ++j) {
9527 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
9528 size += sizeof(macho_section<P>);
9529 }
9530 }
9531 }
9532 fSize = size;
9533 fCommandCount = segCount;
9534 if ( fWriter.fPadSegmentInfo != NULL ) {
9535 ++fCommandCount;
9536 fSize += sizeof(macho_segment_command<P>);
9537 }
9538 }
9539
9540 template <>
9541 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
9542 {
9543 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9544 }
9545
9546 template <>
9547 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
9548 {
9549 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9550 }
9551
9552 template <>
9553 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
9554 {
9555 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9556 }
9557
9558 template <>
9559 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
9560 {
9561 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9562 }
9563
9564 template <>
9565 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
9566 {
9567 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9568 }
9569
9570 template <typename A>
9571 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9572 {
9573 uint64_t size = this->getSize();
9574 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
9575 bzero(buffer, size);
9576 uint8_t* p = buffer;
9577 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9578 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9579 SegmentInfo* segInfo = *it;
9580 if ( ! segInfo->fHasLoadCommand )
9581 continue;
9582 const int sectionCount = segInfo->fSections.size();
9583 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
9584 cmd->set_cmd(macho_segment_command<P>::CMD);
9585 cmd->set_segname(segInfo->fName);
9586 cmd->set_vmaddr(segInfo->fBaseAddress);
9587 cmd->set_vmsize(oneSegment ? 0 : segInfo->fSize);
9588 cmd->set_fileoff(segInfo->fFileOffset);
9589 cmd->set_filesize(oneSegment ? 0 : segInfo->fFileSize);
9590 cmd->set_maxprot(segInfo->fMaxProtection);
9591 cmd->set_initprot(segInfo->fInitProtection);
9592 // add sections array
9593 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
9594 unsigned int sectionsEmitted = 0;
9595 for (int j=0; j < sectionCount; ++j) {
9596 SectionInfo* sectInfo = segInfo->fSections[j];
9597 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
9598 macho_section<P>* sect = &sections[sectionsEmitted++];
9599 if ( oneSegment ) {
9600 // .o file segment does not cover load commands, so recalc at first real section
9601 if ( sectionsEmitted == 1 ) {
9602 cmd->set_vmaddr(sectInfo->getBaseAddress());
9603 cmd->set_fileoff(sectInfo->fFileOffset);
9604 }
9605 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
9606 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
9607 }
9608 sect->set_sectname(sectInfo->fSectionName);
9609 sect->set_segname(sectInfo->fSegmentName);
9610 sect->set_addr(sectInfo->getBaseAddress());
9611 sect->set_size(sectInfo->fSize);
9612 sect->set_offset(sectInfo->fFileOffset);
9613 sect->set_align(sectInfo->fAlignment);
9614 if ( sectInfo->fRelocCount != 0 ) {
9615 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
9616 sect->set_nreloc(sectInfo->fRelocCount);
9617 }
9618 if ( sectInfo->fAllZeroFill ) {
9619 sect->set_flags(S_ZEROFILL);
9620 sect->set_offset(0);
9621 }
9622 else if ( sectInfo->fAllLazyPointers ) {
9623 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
9624 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9625 }
9626 else if ( sectInfo->fAllLazyDylibPointers ) {
9627 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
9628 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9629 }
9630 else if ( sectInfo->fAllNonLazyPointers ) {
9631 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
9632 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9633 }
9634 else if ( sectInfo->fAllStubs ) {
9635 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9636 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9637 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9638 if ( sectInfo->fHasTextLocalRelocs )
9639 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9640 }
9641 else if ( sectInfo->fAllSelfModifyingStubs ) {
9642 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
9643 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9644 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9645 }
9646 else if ( sectInfo->fAllStubHelpers ) {
9647 sect->set_flags(S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9648 if ( sectInfo->fHasTextLocalRelocs )
9649 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9650 }
9651 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCStringType ) {
9652 sect->set_flags(S_CSTRING_LITERALS);
9653 }
9654 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCFIType ) {
9655 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
9656 }
9657 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9658 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
9659 }
9660 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9661 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
9662 }
9663 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9664 sect->set_flags(S_COALESCED);
9665 }
9666 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9667 sect->set_flags(S_COALESCED);
9668 }
9669 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9670 sect->set_flags(S_INTERPOSING);
9671 }
9672 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9673 sect->set_flags(S_4BYTE_LITERALS);
9674 }
9675 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9676 sect->set_flags(S_8BYTE_LITERALS);
9677 }
9678 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9679 sect->set_flags(S_16BYTE_LITERALS);
9680 }
9681 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9682 sect->set_flags(S_LITERAL_POINTERS);
9683 }
9684 else if ( (strcmp(sectInfo->fSectionName, "__objc_selrefs") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9685 sect->set_flags(S_LITERAL_POINTERS);
9686 }
9687 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9688 sect->set_flags(S_LITERAL_POINTERS);
9689 }
9690 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9691 sect->set_flags(S_DTRACE_DOF);
9692 }
9693 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9694 sect->set_flags(S_DTRACE_DOF);
9695 }
9696 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9697 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9698 if ( sectInfo->fHasTextLocalRelocs )
9699 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9700 if ( sectInfo->fHasTextExternalRelocs )
9701 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
9702 }
9703 //fprintf(stderr, "section %s flags=0x%08X\n", sectInfo->fSectionName, sect->flags());
9704 }
9705 }
9706 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
9707 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
9708 cmd->set_nsects(sectionsEmitted);
9709 }
9710 }
9711
9712
9713 template <typename A>
9714 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
9715 : LoadCommandAtom<A>(writer), fNeedsDynamicSymbolTable(false)
9716 {
9717 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
9718 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
9719 switch ( fWriter.fOptions.outputKind() ) {
9720 case Options::kDynamicExecutable:
9721 case Options::kDynamicLibrary:
9722 case Options::kDynamicBundle:
9723 case Options::kDyld:
9724 case Options::kKextBundle:
9725 fNeedsDynamicSymbolTable = true;
9726 break;
9727 case Options::kObjectFile:
9728 case Options::kStaticExecutable:
9729 fNeedsDynamicSymbolTable = false;
9730 case Options::kPreload:
9731 fNeedsDynamicSymbolTable = fWriter.fOptions.positionIndependentExecutable();
9732 break;
9733 }
9734 writer.fSymbolTableCommands = this;
9735 }
9736
9737
9738
9739 template <typename A>
9740 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
9741 {
9742 fNeedsDynamicSymbolTable = true;
9743 }
9744
9745
9746 template <typename A>
9747 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
9748 {
9749 if ( fNeedsDynamicSymbolTable )
9750 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
9751 else
9752 return this->alignedSize(sizeof(macho_symtab_command<P>));
9753 }
9754
9755 template <typename A>
9756 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9757 {
9758 // build LC_SYMTAB command
9759 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
9760 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
9761 symbolTableCmd->set_cmd(LC_SYMTAB);
9762 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
9763 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
9764 symbolTableCmd->set_symoff(fWriter.fSymbolTableCount == 0 ? 0 : fWriter.fSymbolTableAtom->getFileOffset());
9765 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getSize() == 0 ? 0 : fWriter.fStringsAtom->getFileOffset());
9766 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
9767
9768 // build LC_DYSYMTAB command
9769 if ( fNeedsDynamicSymbolTable ) {
9770 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
9771 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
9772 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
9773 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
9774 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
9775 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
9776 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
9777 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
9778 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
9779 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
9780 if ( fWriter.fModuleInfoAtom != NULL ) {
9781 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
9782 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
9783 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
9784 dynamicSymbolTableCmd->set_nmodtab(1);
9785 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
9786 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
9787 }
9788 dynamicSymbolTableCmd->set_indirectsymoff((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->getFileOffset());
9789 dynamicSymbolTableCmd->set_nindirectsyms((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->fTable.size());
9790 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
9791 if ( fWriter.fExternalRelocationsAtom != 0 ) {
9792 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
9793 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
9794 }
9795 if ( fWriter.fLocalRelocationsAtom != 0 ) {
9796 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
9797 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
9798 }
9799 }
9800 }
9801 }
9802
9803
9804 template <typename A>
9805 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
9806 {
9807 return fNeedsDynamicSymbolTable ? 2 : 1;
9808 }
9809
9810 template <typename A>
9811 uint64_t DyldLoadCommandsAtom<A>::getSize() const
9812 {
9813 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
9814 }
9815
9816 template <typename A>
9817 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9818 {
9819 uint64_t size = this->getSize();
9820 bzero(buffer, size);
9821 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
9822 if ( fWriter.fOptions.outputKind() == Options::kDyld )
9823 cmd->set_cmd(LC_ID_DYLINKER);
9824 else
9825 cmd->set_cmd(LC_LOAD_DYLINKER);
9826 cmd->set_cmdsize(this->getSize());
9827 cmd->set_name_offset();
9828 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
9829 }
9830
9831 template <typename A>
9832 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
9833 {
9834 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
9835 }
9836
9837 template <typename A>
9838 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9839 {
9840 uint64_t size = this->getSize();
9841
9842 bzero(buffer, size);
9843 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
9844 cmd->set_cmd(LC_SUB_CLIENT);
9845 cmd->set_cmdsize(size);
9846 cmd->set_client_offset();
9847 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
9848
9849 }
9850
9851 template <typename A>
9852 uint64_t DylibLoadCommandsAtom<A>::getSize() const
9853 {
9854 if ( fOptimizedAway ) {
9855 return 0;
9856 }
9857 else {
9858 const char* path = fInfo.reader->getInstallPath();
9859 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
9860 }
9861 }
9862
9863 template <typename A>
9864 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9865 {
9866 if ( fOptimizedAway )
9867 return;
9868 uint64_t size = this->getSize();
9869 bzero(buffer, size);
9870 const char* path = fInfo.reader->getInstallPath();
9871 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9872 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
9873 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
9874 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
9875 if ( fInfo.options.fLazyLoad )
9876 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
9877 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
9878 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
9879 else if ( fInfo.options.fReExport && fWriter.fOptions.useSimplifiedDylibReExports() )
9880 cmd->set_cmd(LC_REEXPORT_DYLIB);
9881 else
9882 cmd->set_cmd(LC_LOAD_DYLIB);
9883 cmd->set_cmdsize(this->getSize());
9884 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
9885 cmd->set_current_version(fInfo.reader->getCurrentVersion());
9886 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
9887 cmd->set_name_offset();
9888 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
9889 }
9890
9891
9892
9893 template <typename A>
9894 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
9895 {
9896 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
9897 }
9898
9899 template <typename A>
9900 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9901 {
9902 uint64_t size = this->getSize();
9903 bzero(buffer, size);
9904 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9905 cmd->set_cmd(LC_ID_DYLIB);
9906 cmd->set_cmdsize(this->getSize());
9907 cmd->set_name_offset();
9908 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
9909 cmd->set_current_version(fWriter.fOptions.currentVersion());
9910 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
9911 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
9912 }
9913
9914
9915 template <typename A>
9916 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9917 {
9918 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9919 if (fWriter.fEntryPoint->isThumb())
9920 initAddr |= 1ULL;
9921 bzero(buffer, sizeof(macho_routines_command<P>));
9922 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
9923 cmd->set_cmd(macho_routines_command<P>::CMD);
9924 cmd->set_cmdsize(this->getSize());
9925 cmd->set_init_address(initAddr);
9926 }
9927
9928
9929 template <typename A>
9930 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
9931 {
9932 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
9933 }
9934
9935 template <typename A>
9936 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9937 {
9938 uint64_t size = this->getSize();
9939 bzero(buffer, size);
9940 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
9941 cmd->set_cmd(LC_SUB_UMBRELLA);
9942 cmd->set_cmdsize(this->getSize());
9943 cmd->set_sub_umbrella_offset();
9944 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
9945 }
9946
9947 template <typename A>
9948 void UUIDLoadCommandAtom<A>::generate()
9949 {
9950 switch ( fWriter.fOptions.getUUIDMode() ) {
9951 case Options::kUUIDNone:
9952 fEmit = false;
9953 break;
9954 case Options::kUUIDRandom:
9955 ::uuid_generate_random(fUUID);
9956 fEmit = true;
9957 break;
9958 case Options::kUUIDContent:
9959 bzero(fUUID, 16);
9960 fEmit = true;
9961 break;
9962 }
9963 }
9964
9965 template <typename A>
9966 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
9967 {
9968 memcpy(fUUID, uuid, 16);
9969 }
9970
9971 template <typename A>
9972 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
9973 {
9974 if (fEmit) {
9975 uint64_t size = this->getSize();
9976 bzero(buffer, size);
9977 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
9978 cmd->set_cmd(LC_UUID);
9979 cmd->set_cmdsize(this->getSize());
9980 cmd->set_uuid((uint8_t*)fUUID);
9981 }
9982 }
9983
9984
9985 template <typename A>
9986 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
9987 {
9988 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
9989 }
9990
9991 template <typename A>
9992 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9993 {
9994 uint64_t size = this->getSize();
9995 bzero(buffer, size);
9996 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
9997 cmd->set_cmd(LC_SUB_LIBRARY);
9998 cmd->set_cmdsize(this->getSize());
9999 cmd->set_sub_library_offset();
10000 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
10001 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
10002 }
10003
10004 template <typename A>
10005 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
10006 {
10007 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
10008 }
10009
10010 template <typename A>
10011 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10012 {
10013 uint64_t size = this->getSize();
10014 bzero(buffer, size);
10015 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
10016 cmd->set_cmd(LC_SUB_FRAMEWORK);
10017 cmd->set_cmdsize(this->getSize());
10018 cmd->set_umbrella_offset();
10019 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
10020 }
10021
10022 template <>
10023 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
10024 {
10025 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
10026 }
10027
10028 template <>
10029 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
10030 {
10031 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
10032 }
10033
10034 template <>
10035 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
10036 {
10037 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
10038 }
10039
10040 template <>
10041 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
10042 {
10043 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
10044 }
10045
10046 // We should be picking it up from a header
10047 template <>
10048 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
10049 {
10050 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
10051 }
10052
10053 template <>
10054 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
10055 {
10056 uint64_t size = this->getSize();
10057 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
10058 bzero(buffer, size);
10059 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
10060 cmd->set_cmd(LC_UNIXTHREAD);
10061 cmd->set_cmdsize(size);
10062 cmd->set_flavor(1); // PPC_THREAD_STATE
10063 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
10064 cmd->set_thread_register(0, start);
10065 if ( fWriter.fOptions.hasCustomStack() )
10066 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
10067 }
10068
10069
10070 template <>
10071 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
10072 {
10073 uint64_t size = this->getSize();
10074 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
10075 bzero(buffer, size);
10076 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
10077 cmd->set_cmd(LC_UNIXTHREAD);
10078 cmd->set_cmdsize(size);
10079 cmd->set_flavor(5); // PPC_THREAD_STATE64
10080 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
10081 cmd->set_thread_register(0, start);
10082 if ( fWriter.fOptions.hasCustomStack() )
10083 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
10084 }
10085
10086 template <>
10087 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
10088 {
10089 uint64_t size = this->getSize();
10090 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
10091 bzero(buffer, size);
10092 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
10093 cmd->set_cmd(LC_UNIXTHREAD);
10094 cmd->set_cmdsize(size);
10095 cmd->set_flavor(1); // i386_THREAD_STATE
10096 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
10097 cmd->set_thread_register(10, start);
10098 if ( fWriter.fOptions.hasCustomStack() )
10099 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
10100 }
10101
10102 template <>
10103 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
10104 {
10105 uint64_t size = this->getSize();
10106 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
10107 bzero(buffer, size);
10108 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
10109 cmd->set_cmd(LC_UNIXTHREAD);
10110 cmd->set_cmdsize(size);
10111 cmd->set_flavor(x86_THREAD_STATE64);
10112 cmd->set_count(x86_THREAD_STATE64_COUNT);
10113 cmd->set_thread_register(16, start); // rip
10114 if ( fWriter.fOptions.hasCustomStack() )
10115 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
10116 }
10117
10118 template <>
10119 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
10120 {
10121 uint64_t size = this->getSize();
10122 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
10123 if ( fWriter.fEntryPoint->isThumb() )
10124 start |= 1ULL;
10125 bzero(buffer, size);
10126 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
10127 cmd->set_cmd(LC_UNIXTHREAD);
10128 cmd->set_cmdsize(size);
10129 cmd->set_flavor(1);
10130 cmd->set_count(17);
10131 cmd->set_thread_register(15, start); // pc
10132 if ( fWriter.fOptions.hasCustomStack() )
10133 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
10134 }
10135
10136 template <typename A>
10137 uint64_t RPathLoadCommandsAtom<A>::getSize() const
10138 {
10139 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
10140 }
10141
10142 template <typename A>
10143 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10144 {
10145 uint64_t size = this->getSize();
10146 bzero(buffer, size);
10147 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
10148 cmd->set_cmd(LC_RPATH);
10149 cmd->set_cmdsize(this->getSize());
10150 cmd->set_path_offset();
10151 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
10152 }
10153
10154
10155
10156 template <typename A>
10157 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10158 {
10159 uint64_t size = this->getSize();
10160 bzero(buffer, size);
10161 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
10162 cmd->set_cmd(LC_ENCRYPTION_INFO);
10163 cmd->set_cmdsize(this->getSize());
10164 cmd->set_cryptoff(fStartOffset);
10165 cmd->set_cryptsize(fEndOffset-fStartOffset);
10166 cmd->set_cryptid(0);
10167 }
10168
10169
10170
10171 template <typename A>
10172 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
10173 {
10174 bzero(buffer, fSize);
10175 }
10176
10177 template <typename A>
10178 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
10179 {
10180 fSize = newSize;
10181 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
10182 if ( fWriter.fLargestAtomSize < newSize )
10183 fWriter.fLargestAtomSize = newSize;
10184 }
10185
10186 template <typename A>
10187 void UnwindInfoAtom<A>::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
10188 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsdaRef,
10189 ObjectFile::Atom* personalityPointer)
10190 {
10191 Info info;
10192 info.func = func;
10193 if ( fdeRef != NULL )
10194 info.fde = &fdeRef->getTarget();
10195 else
10196 info.fde = NULL;
10197 if ( lsdaRef != NULL ) {
10198 info.lsda = &lsdaRef->getTarget();
10199 info.lsdaOffset = lsdaRef->getTargetOffset();
10200 }
10201 else {
10202 info.lsda = NULL;
10203 info.lsdaOffset = 0;
10204 }
10205 info.personalityPointer = personalityPointer;
10206 info.encoding = encoding;
10207 fInfos.push_back(info);
10208 //fprintf(stderr, "addUnwindInfo() encoding=0x%08X, lsda=%p, lsdaOffset=%d, person=%p, func=%s\n",
10209 // encoding, info.lsda, info.lsdaOffset, personalityPointer, func->getDisplayName());
10210 }
10211
10212 template <>
10213 bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10214 {
10215 return ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
10216 }
10217
10218 template <>
10219 bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10220 {
10221 return ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
10222 }
10223
10224 template <typename A>
10225 bool UnwindInfoAtom<A>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10226 {
10227 return false;
10228 }
10229
10230
10231 template <typename A>
10232 void UnwindInfoAtom<A>::compressDuplicates(std::vector<Info>& uniqueInfos)
10233 {
10234 // build new list removing entries where next function has same encoding
10235 uniqueInfos.reserve(fInfos.size());
10236 Info last;
10237 last.func = NULL;
10238 last.lsda = NULL;
10239 last.lsdaOffset = 0;
10240 last.personalityPointer = NULL;
10241 last.encoding = 0xFFFFFFFF;
10242 for(typename std::vector<Info>::iterator it=fInfos.begin(); it != fInfos.end(); ++it) {
10243 Info& newInfo = *it;
10244 bool newNeedsDwarf = encodingMeansUseDwarf(newInfo.encoding);
10245 // remove infos which have same encoding and personalityPointer as last one
10246 if ( newNeedsDwarf || (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer)
10247 || (newInfo.lsda != NULL) || (last.lsda != NULL) ) {
10248 uniqueInfos.push_back(newInfo);
10249 }
10250 last = newInfo;
10251 }
10252 //fprintf(stderr, "compressDuplicates() fInfos.size()=%lu, uniqueInfos.size()=%lu\n", fInfos.size(), uniqueInfos.size());
10253 }
10254
10255 template <typename A>
10256 void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings)
10257 {
10258 // scan infos to get frequency counts for each encoding
10259 std::map<uint32_t, unsigned int> encodingsUsed;
10260 unsigned int mostCommonEncodingUsageCount = 0;
10261 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10262 // never put dwarf into common table
10263 if ( encodingMeansUseDwarf(it->encoding) )
10264 continue;
10265 std::map<uint32_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
10266 if ( pos == encodingsUsed.end() ) {
10267 encodingsUsed[it->encoding] = 1;
10268 }
10269 else {
10270 encodingsUsed[it->encoding] += 1;
10271 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
10272 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
10273 }
10274 }
10275 // put the most common encodings into the common table, but at most 127 of them
10276 for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
10277 for (std::map<uint32_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
10278 if ( euit->second == usages ) {
10279 unsigned int size = commonEncodings.size();
10280 if ( size < 127 ) {
10281 commonEncodings[euit->first] = size;
10282 }
10283 }
10284 }
10285 }
10286 }
10287
10288 template <typename A>
10289 void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap)
10290 {
10291 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10292 lsdaIndexOffsetMap[it->func] = fLSDAIndex.size() * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10293 if ( it->lsda != NULL ) {
10294 LSDAEntry entry;
10295 entry.func = it->func;
10296 entry.lsda = it->lsda;
10297 entry.lsdaOffset = it->lsdaOffset;
10298 fLSDAIndex.push_back(entry);
10299 }
10300 }
10301 }
10302
10303 template <typename A>
10304 void UnwindInfoAtom<A>::makePersonalityIndex(std::vector<Info>& uniqueInfos)
10305 {
10306 for(typename std::vector<Info>::iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10307 if ( it->personalityPointer != NULL ) {
10308 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fPersonalityIndexMap.find(it->personalityPointer);
10309 if ( pos == fPersonalityIndexMap.end() ) {
10310 const uint32_t nextIndex = fPersonalityIndexMap.size() + 1;
10311 fPersonalityIndexMap[it->personalityPointer] = nextIndex;
10312 }
10313 uint32_t personalityIndex = fPersonalityIndexMap[it->personalityPointer];
10314 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
10315 }
10316 }
10317 }
10318
10319 template <typename A>
10320 unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize,
10321 unsigned int endIndex, uint8_t*& pageEnd)
10322 {
10323 const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10324 const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
10325 uint8_t* pageStart = pageEnd
10326 - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
10327 - sizeof(unwind_info_regular_second_level_page_header);
10328 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
10329 page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
10330 page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
10331 page->set_entryCount(entriesToAdd);
10332 macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
10333 for (unsigned int i=0; i < entriesToAdd; ++i) {
10334 const Info& info = uniqueInfos[endIndex-entriesToAdd+i];
10335 entryTable[i].set_functionOffset(0);
10336 entryTable[i].set_encoding(info.encoding);
10337 RegFixUp fixup;
10338 fixup.contentPointer = (uint8_t*)(&entryTable[i]);
10339 fixup.func = info.func;
10340 fixup.fde = ( encodingMeansUseDwarf(info.encoding) ? info.fde : NULL );
10341 fRegFixUps.push_back(fixup);
10342 }
10343 //fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
10344 pageEnd = pageStart;
10345 return endIndex - entriesToAdd;
10346 }
10347
10348
10349 template <typename A>
10350 unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
10351 const std::map<uint32_t,unsigned int> commonEncodings,
10352 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
10353 {
10354 const bool log = false;
10355 if (log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
10356 // first pass calculates how many compressed entries we could fit in this sized page
10357 // keep adding entries to page until:
10358 // 1) encoding table plus entry table plus header exceed page size
10359 // 2) the file offset delta from the first to last function > 24 bits
10360 // 3) custom encoding index reachs 255
10361 // 4) run out of uniqueInfos to encode
10362 std::map<uint32_t, unsigned int> pageSpecificEncodings;
10363 uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
10364 std::vector<uint8_t> encodingIndexes;
10365 int index = endIndex-1;
10366 int entryCount = 0;
10367 uint64_t lastEntryAddress = uniqueInfos[index].func->getAddress();
10368 bool canDo = true;
10369 while ( canDo && (index >= 0) ) {
10370 const Info& info = uniqueInfos[index--];
10371 // compute encoding index
10372 unsigned int encodingIndex;
10373 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10374 if ( pos != commonEncodings.end() ) {
10375 encodingIndex = pos->second;
10376 }
10377 else {
10378 // no commmon entry, so add one on this page
10379 uint32_t encoding = info.encoding;
10380 if ( encodingMeansUseDwarf(encoding) ) {
10381 // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
10382 encoding += (index+1);
10383 }
10384 std::map<uint32_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
10385 if ( ppos != pageSpecificEncodings.end() ) {
10386 encodingIndex = pos->second;
10387 }
10388 else {
10389 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
10390 if ( encodingIndex <= 255 ) {
10391 pageSpecificEncodings[encoding] = encodingIndex;
10392 }
10393 else {
10394 canDo = false; // case 3)
10395 if (log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
10396 entryCount, pageSpecificEncodings.size());
10397 }
10398 }
10399 }
10400 if ( canDo )
10401 encodingIndexes.push_back(encodingIndex);
10402 // compute function offset
10403 uint32_t funcOffsetWithInPage = lastEntryAddress - info.func->getAddress();
10404 if ( funcOffsetWithInPage > 0x00FFFF00 ) {
10405 // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
10406 canDo = false; // case 2)
10407 if (log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
10408 }
10409 else {
10410 ++entryCount;
10411 }
10412 // check room for entry
10413 if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
10414 canDo = false; // case 1)
10415 --entryCount;
10416 if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
10417 }
10418 //if (log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
10419 }
10420
10421 // check for cases where it would be better to use a regular (non-compressed) page
10422 const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
10423 + pageSpecificEncodings.size()*sizeof(uint32_t)
10424 + entryCount*sizeof(uint32_t);
10425 if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
10426 const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10427 if ( entryCount < regularEntriesPerPage ) {
10428 return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
10429 }
10430 }
10431
10432 // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
10433 uint32_t pad = 0;
10434 if ( compressPageUsed == (pageSize-4) )
10435 pad = 4;
10436
10437 // second pass fills in page
10438 uint8_t* pageStart = pageEnd - compressPageUsed - pad;
10439 macho_unwind_info_compressed_second_level_page_header<P>* page = (macho_unwind_info_compressed_second_level_page_header<P>*)pageStart;
10440 page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
10441 page->set_entryPageOffset(sizeof(macho_unwind_info_compressed_second_level_page_header<P>));
10442 page->set_entryCount(entryCount);
10443 page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
10444 page->set_encodingsCount(pageSpecificEncodings.size());
10445 uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
10446 // fill in entry table
10447 uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
10448 ObjectFile::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
10449 for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
10450 const Info& info = uniqueInfos[i];
10451 uint8_t encodingIndex;
10452 if ( encodingMeansUseDwarf(info.encoding) ) {
10453 // dwarf entries are always in page specific encodings
10454 encodingIndex = pageSpecificEncodings[info.encoding+i];
10455 }
10456 else {
10457 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10458 if ( pos != commonEncodings.end() )
10459 encodingIndex = pos->second;
10460 else
10461 encodingIndex = pageSpecificEncodings[info.encoding];
10462 }
10463 uint32_t entryIndex = i - endIndex + entryCount;
10464 A::P::E::set32(entiresArray[entryIndex], encodingIndex << 24);
10465 CompressedFixUp funcStartFixUp;
10466 funcStartFixUp.contentPointer = (uint8_t*)(&entiresArray[entryIndex]);
10467 funcStartFixUp.func = info.func;
10468 funcStartFixUp.fromFunc = firstFunc;
10469 fCompressedFixUps.push_back(funcStartFixUp);
10470 if ( encodingMeansUseDwarf(info.encoding) ) {
10471 CompressedEncodingFixUp dwarfStartFixup;
10472 dwarfStartFixup.contentPointer = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]);
10473 dwarfStartFixup.fde = info.fde;
10474 fCompressedEncodingFixUps.push_back(dwarfStartFixup);
10475 }
10476 }
10477 // fill in encodings table
10478 for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
10479 A::P::E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
10480 }
10481
10482 if (log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
10483
10484 // update pageEnd;
10485 pageEnd = pageStart;
10486 return endIndex-entryCount; // endIndex for next page
10487 }
10488
10489 template <> void UnwindInfoAtom<ppc>::generate() { }
10490 template <> void UnwindInfoAtom<ppc64>::generate() { }
10491 template <> void UnwindInfoAtom<arm>::generate() { }
10492
10493
10494 template <typename A>
10495 void UnwindInfoAtom<A>::generate()
10496 {
10497 // only generate table if there are functions with unwind info
10498 if ( fInfos.size() > 0 ) {
10499 // find offset of end of __unwind_info section
10500 SectionInfo* unwindSectionInfo = (SectionInfo*)this->getSection();
10501
10502 // build new list that has proper offsetInImage and remove entries where next function has same encoding
10503 std::vector<Info> uniqueInfos;
10504 this->compressDuplicates(uniqueInfos);
10505
10506 // build personality index, update encodings with personality index
10507 this->makePersonalityIndex(uniqueInfos);
10508 if ( fPersonalityIndexMap.size() > 3 )
10509 throw "too many personality routines for compact unwind to encode";
10510
10511 // put the most common encodings into the common table, but at most 127 of them
10512 std::map<uint32_t, unsigned int> commonEncodings;
10513 this->findCommonEncoding(uniqueInfos, commonEncodings);
10514
10515 // build lsda index
10516 std::map<ObjectFile::Atom*, uint32_t> lsdaIndexOffsetMap;
10517 this->makeLsdaIndex(uniqueInfos, lsdaIndexOffsetMap);
10518
10519 // calculate worst case size for all unwind info pages when allocating buffer
10520 const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10521 const unsigned int pageCount = ((uniqueInfos.size() - 1)/entriesPerRegularPage) + 1;
10522 fPagesContentForDelete = (uint8_t*)calloc(pageCount,4096);
10523 fPagesSize = 0;
10524 if ( fPagesContentForDelete == NULL )
10525 throw "could not allocate space for compact unwind info";
10526 ObjectFile::Atom* secondLevelFirstFuncs[pageCount*3];
10527 uint8_t* secondLevelPagesStarts[pageCount*3];
10528
10529 // make last second level page smaller so that all other second level pages can be page aligned
10530 uint32_t maxLastPageSize = unwindSectionInfo->fFileOffset % 4096;
10531 uint32_t tailPad = 0;
10532 if ( maxLastPageSize < 128 ) {
10533 tailPad = maxLastPageSize;
10534 maxLastPageSize = 4096;
10535 }
10536
10537 // fill in pages in reverse order
10538 unsigned int endIndex = uniqueInfos.size();
10539 unsigned int secondLevelPageCount = 0;
10540 uint8_t* pageEnd = &fPagesContentForDelete[pageCount*4096];
10541 uint32_t pageSize = maxLastPageSize;
10542 while ( endIndex > 0 ) {
10543 endIndex = makeCompressedSecondLevelPage(uniqueInfos, commonEncodings, pageSize, endIndex, pageEnd);
10544 secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
10545 secondLevelFirstFuncs[secondLevelPageCount] = uniqueInfos[endIndex].func;
10546 ++secondLevelPageCount;
10547 pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
10548 }
10549 fPagesContent = pageEnd;
10550 fPagesSize = &fPagesContentForDelete[pageCount*4096] - pageEnd;
10551
10552 // calculate section layout
10553 const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
10554 const uint32_t commonEncodingsArrayCount = commonEncodings.size();
10555 const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
10556 const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
10557 const uint32_t personalityArrayCount = fPersonalityIndexMap.size();
10558 const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
10559 const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
10560 const uint32_t indexCount = secondLevelPageCount+1;
10561 const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
10562 const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
10563 const uint32_t lsdaIndexArrayCount = fLSDAIndex.size();
10564 const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10565 const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
10566
10567
10568 // allocate and fill in section header
10569 fHeaderSize = headerEndSectionOffset;
10570 fHeaderContent = new uint8_t[fHeaderSize];
10571 bzero(fHeaderContent, fHeaderSize);
10572 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)fHeaderContent;
10573 sectionHeader->set_version(UNWIND_SECTION_VERSION);
10574 sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
10575 sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
10576 sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
10577 sectionHeader->set_personalityArrayCount(personalityArrayCount);
10578 sectionHeader->set_indexSectionOffset(indexSectionOffset);
10579 sectionHeader->set_indexCount(indexCount);
10580
10581 // copy common encodings
10582 uint32_t* commonEncodingsTable = (uint32_t*)&fHeaderContent[commonEncodingsArraySectionOffset];
10583 for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
10584 A::P::E::set32(commonEncodingsTable[it->second], it->first);
10585
10586 // make references for personality entries
10587 uint32_t* personalityArray = (uint32_t*)&fHeaderContent[sectionHeader->personalityArraySectionOffset()];
10588 for (std::map<ObjectFile::Atom*, unsigned int>::iterator it=fPersonalityIndexMap.begin(); it != fPersonalityIndexMap.end(); ++it) {
10589 uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - fHeaderContent;
10590 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->first));
10591 }
10592
10593 // build first level index and references
10594 macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&fHeaderContent[indexSectionOffset];
10595 for (unsigned int i=0; i < secondLevelPageCount; ++i) {
10596 unsigned int reverseIndex = secondLevelPageCount - 1 - i;
10597 indexTable[i].set_functionOffset(0);
10598 indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-fPagesContent+headerEndSectionOffset);
10599 indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
10600 uint32_t refOffset = (uint8_t*)&indexTable[i] - fHeaderContent;
10601 fReferences.push_back(new WriterReference<A>(refOffset, A::kImageOffset32, secondLevelFirstFuncs[reverseIndex]));
10602 }
10603 indexTable[secondLevelPageCount].set_functionOffset(0);
10604 indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
10605 indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
10606 fReferences.push_back(new WriterReference<A>((uint8_t*)&indexTable[secondLevelPageCount] - fHeaderContent, A::kImageOffset32,
10607 fInfos.back().func, fInfos.back().func->getSize()+1));
10608
10609 // build lsda references
10610 uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
10611 for (typename std::vector<LSDAEntry>::iterator it = fLSDAIndex.begin(); it != fLSDAIndex.end(); ++it) {
10612 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset, A::kImageOffset32, it->func));
10613 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset+4, A::kImageOffset32, it->lsda, it->lsdaOffset));
10614 lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
10615 }
10616
10617 // make references for regular second level entries
10618 for (typename std::vector<RegFixUp>::iterator it = fRegFixUps.begin(); it != fRegFixUps.end(); ++it) {
10619 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10620 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->func));
10621 if ( it->fde != NULL )
10622 fReferences.push_back(new WriterReference<A>(offset+4, A::kSectionOffset24, it->fde));
10623 }
10624 // make references for compressed second level entries
10625 for (typename std::vector<CompressedFixUp>::iterator it = fCompressedFixUps.begin(); it != fCompressedFixUps.end(); ++it) {
10626 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10627 fReferences.push_back(new WriterReference<A>(offset, A::kPointerDiff24, it->func, 0, it->fromFunc, 0));
10628 }
10629 for (typename std::vector<CompressedEncodingFixUp>::iterator it = fCompressedEncodingFixUps.begin(); it != fCompressedEncodingFixUps.end(); ++it) {
10630 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10631 fReferences.push_back(new WriterReference<A>(offset, A::kSectionOffset24, it->fde));
10632 }
10633
10634 // update section record with new size
10635 unwindSectionInfo->fSize = this->getSize();
10636
10637 // alter alignment so this section lays out so second level tables are page aligned
10638 if ( secondLevelPageCount > 2 )
10639 fAlignment = ObjectFile::Alignment(12, (unwindSectionInfo->fFileOffset - this->getSize()) % 4096);
10640 }
10641
10642 }
10643
10644
10645
10646
10647 template <typename A>
10648 void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10649 {
10650 memcpy(buffer, fHeaderContent, fHeaderSize);
10651 memcpy(&buffer[fHeaderSize], fPagesContent, fPagesSize);
10652 }
10653
10654
10655
10656 template <typename A>
10657 uint64_t LinkEditAtom<A>::getFileOffset() const
10658 {
10659 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
10660 }
10661
10662
10663 template <typename A>
10664 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
10665 {
10666 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
10667 }
10668
10669 template <typename A>
10670 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10671 {
10672 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
10673 }
10674
10675
10676 template <typename A>
10677 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
10678 {
10679 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
10680 }
10681
10682 template <typename A>
10683 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10684 {
10685 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
10686 }
10687
10688
10689
10690 template <typename A>
10691 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
10692 {
10693 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
10694 }
10695
10696 template <typename A>
10697 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10698 {
10699 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
10700 }
10701
10702 template <typename A>
10703 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
10704 {
10705 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
10706 }
10707
10708 template <typename A>
10709 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10710 {
10711 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
10712 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
10713 }
10714
10715
10716
10717 template <typename A>
10718 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
10719 {
10720 return fTable.size() * sizeof(uint32_t);
10721 }
10722
10723 template <typename A>
10724 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10725 {
10726 uint64_t size = this->getSize();
10727 bzero(buffer, size);
10728 const uint32_t indirectTableSize = fTable.size();
10729 uint32_t* indirectTable = (uint32_t*)buffer;
10730 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
10731 if ( it->indirectIndex < indirectTableSize )
10732 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
10733 else
10734 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
10735 }
10736 }
10737
10738
10739
10740 template <typename A>
10741 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
10742 {
10743 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
10744 + sizeof(macho_dylib_module<P>)
10745 + this->getReferencesCount()*sizeof(uint32_t);
10746 }
10747
10748 template <typename A>
10749 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
10750 {
10751 return this->getFileOffset();
10752 }
10753
10754 template <typename A>
10755 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
10756 {
10757 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
10758 }
10759
10760 template <typename A>
10761 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
10762 {
10763 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
10764 }
10765
10766 template <typename A>
10767 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
10768 {
10769 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
10770 }
10771
10772 template <typename A>
10773 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10774 {
10775 uint64_t size = this->getSize();
10776 bzero(buffer, size);
10777 // create toc. The symbols are already sorted, they are all in the smae module
10778 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
10779 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
10780 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
10781 p->set_module_index(0);
10782 }
10783 // create module table (one entry)
10784 pint_t objcModuleSectionStart = 0;
10785 pint_t objcModuleSectionSize = 0;
10786 uint16_t numInits = 0;
10787 uint16_t numTerms = 0;
10788 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
10789 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
10790 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
10791 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
10792 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10793 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
10794 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10795 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
10796 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10797 }
10798 }
10799 else if ( strcmp((*segit)->fName, "__OBJC") == 0 ) {
10800 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10801 SectionInfo* sectInfo = (*sectit);
10802 if ( strcmp(sectInfo->fSectionName, "__module_info") == 0 ) {
10803 objcModuleSectionStart = sectInfo->getBaseAddress();
10804 objcModuleSectionSize = sectInfo->fSize;
10805 }
10806 }
10807 }
10808 }
10809 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
10810 module->set_module_name(fModuleNameOffset);
10811 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
10812 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
10813 module->set_irefsym(0);
10814 module->set_nrefsym(this->getReferencesCount());
10815 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
10816 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
10817 module->set_iextrel(0);
10818 module->set_nextrel(fWriter.fExternalRelocs.size());
10819 module->set_iinit_iterm(0,0);
10820 module->set_ninit_nterm(numInits,numTerms);
10821 module->set_objc_module_info_addr(objcModuleSectionStart);
10822 module->set_objc_module_info_size(objcModuleSectionSize);
10823 // create reference table
10824 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
10825 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
10826 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
10827 ref->set_flags(REFERENCE_FLAG_DEFINED);
10828 }
10829 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
10830 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
10831 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
10832 if ( pos != fWriter.fStubsMap.end() )
10833 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
10834 else
10835 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
10836 }
10837 }
10838
10839
10840
10841 template <typename A>
10842 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
10843 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
10844 {
10845 fCurrentBuffer = new char[kBufferSize];
10846 // burn first byte of string pool (so zero is never a valid string offset)
10847 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
10848 // make offset 1 always point to an empty string
10849 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
10850 }
10851
10852 template <typename A>
10853 uint64_t StringsLinkEditAtom<A>::getSize() const
10854 {
10855 // align size
10856 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
10857 }
10858
10859 template <typename A>
10860 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10861 {
10862 uint64_t offset = 0;
10863 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
10864 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
10865 offset += kBufferSize;
10866 }
10867 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
10868 // zero fill end to align
10869 offset += fCurrentBufferUsed;
10870 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
10871 buffer[offset++] = 0;
10872 }
10873
10874 template <typename A>
10875 int32_t StringsLinkEditAtom<A>::add(const char* name)
10876 {
10877 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
10878 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
10879 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
10880 fCurrentBufferUsed += lenNeeded;
10881 }
10882 else {
10883 int copied = kBufferSize-fCurrentBufferUsed-1;
10884 // change trailing '\0' that strlcpy added to real char
10885 fCurrentBuffer[kBufferSize-1] = name[copied];
10886 // alloc next buffer
10887 fFullBuffers.push_back(fCurrentBuffer);
10888 fCurrentBuffer = new char[kBufferSize];
10889 fCurrentBufferUsed = 0;
10890 // append rest of string
10891 this->add(&name[copied+1]);
10892 }
10893 return offset;
10894 }
10895
10896
10897 template <typename A>
10898 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
10899 {
10900 StringToOffset::iterator pos = fUniqueStrings.find(name);
10901 if ( pos != fUniqueStrings.end() ) {
10902 return pos->second;
10903 }
10904 else {
10905 int32_t offset = this->add(name);
10906 fUniqueStrings[name] = offset;
10907 return offset;
10908 }
10909 }
10910
10911
10912 template <typename A>
10913 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
10914 {
10915 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
10916 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
10917 // check for out of bounds
10918 if ( index > maxIndex )
10919 return "";
10920 // check for index in fCurrentBuffer
10921 if ( index > currentBufferStartIndex )
10922 return &fCurrentBuffer[index-currentBufferStartIndex];
10923 // otherwise index is in a full buffer
10924 uint32_t fullBufferIndex = index/kBufferSize;
10925 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
10926 }
10927
10928
10929
10930 template <typename A>
10931 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target,
10932 ObjectFile::Atom& finalTarget, uint32_t finalTargetOffset)
10933 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fFinalTarget(finalTarget), fFinalTargetOffset(finalTargetOffset)
10934 {
10935 if ( finalTargetOffset == 0 ) {
10936 if ( islandRegion == 0 )
10937 asprintf((char**)&fName, "%s$island", name);
10938 else
10939 asprintf((char**)&fName, "%s$island$%d", name, islandRegion+1);
10940 }
10941 else {
10942 asprintf((char**)&fName, "%s_plus_%d$island$%d", name, finalTargetOffset, islandRegion);
10943 }
10944
10945 if ( finalTarget.isThumb() ) {
10946 if ( writer.fOptions.preferSubArchitecture() && writer.fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
10947 fIslandKind = kBranchIslandToThumb2;
10948 }
10949 else {
10950 fIslandKind = kBranchIslandToThumb1;
10951 }
10952 }
10953 else {
10954 fIslandKind = kBranchIslandToARM;
10955 }
10956 }
10957
10958
10959 template <>
10960 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
10961 {
10962 int64_t displacement;
10963 const int64_t bl_sixteenMegLimit = 0x00FFFFFF;
10964 if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
10965 displacement = getFinalTargetAdress() - this->getAddress();
10966 if ( (displacement > bl_sixteenMegLimit) && (displacement < (-bl_sixteenMegLimit)) ) {
10967 displacement = fTarget.getAddress() - this->getAddress();
10968 }
10969 }
10970 else {
10971 displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress();
10972 }
10973 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10974 OSWriteBigInt32(buffer, 0, branchInstruction);
10975 }
10976
10977 template <>
10978 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
10979 {
10980 int64_t displacement;
10981 const int64_t bl_sixteenMegLimit = 0x00FFFFFF;
10982 if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
10983 displacement = getFinalTargetAdress() - this->getAddress();
10984 if ( (displacement > bl_sixteenMegLimit) && (displacement < (-bl_sixteenMegLimit)) ) {
10985 displacement = fTarget.getAddress() - this->getAddress();
10986 }
10987 }
10988 else {
10989 displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress();
10990 }
10991 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10992 OSWriteBigInt32(buffer, 0, branchInstruction);
10993 }
10994
10995 template <>
10996 void BranchIslandAtom<arm>::copyRawContent(uint8_t buffer[]) const
10997 {
10998 const bool log = false;
10999 switch ( fIslandKind ) {
11000 case kBranchIslandToARM:
11001 {
11002 int64_t displacement;
11003 // an ARM branch can branch farther than a thumb branch. The branch
11004 // island generation was conservative and put islands every thumb
11005 // branch distance apart. Check to see if this is a an island
11006 // hopping branch that could be optimized to go directly to target.
11007 if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
11008 displacement = getFinalTargetAdress() - this->getAddress() - 8;
11009 if ( (displacement < 33554428LL) && (displacement > (-33554432LL)) ) {
11010 // can skip branch island and jump straight to target
11011 if (log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", fName, getFinalTargetAdress(), this->getAddress());
11012 }
11013 else {
11014 // ultimate target is too far, jump to island
11015 displacement = fTarget.getAddress() - this->getAddress() - 8;
11016 if (log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", fName, fTarget.getAddress());
11017 }
11018 }
11019 else {
11020 // target of island is ultimate target
11021 displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress() - 8;
11022 if (log) fprintf(stderr, "%s: jump to target at 0x%08llX\n", fName, fTarget.getAddress());
11023 }
11024 uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF;
11025 int32_t branchInstruction = 0xEA000000 | imm24;
11026 OSWriteLittleInt32(buffer, 0, branchInstruction);
11027 }
11028 break;
11029 case kBranchIslandToThumb2:
11030 {
11031 int64_t displacement;
11032 // an ARM branch can branch farther than a thumb branch. The branch
11033 // island generation was conservative and put islands every thumb
11034 // branch distance apart. Check to see if this is a an island
11035 // hopping branch that could be optimized to go directly to target.
11036 if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
11037 displacement = getFinalTargetAdress() - this->getAddress() - 4;
11038 if ( (displacement < 16777214) && (displacement > (-16777216LL)) ) {
11039 // can skip branch island and jump straight to target
11040 if (log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", fName, getFinalTargetAdress(), this->getAddress());
11041 }
11042 else {
11043 // ultimate target is too far, jump to island
11044 displacement = fTarget.getAddress() - this->getAddress() - 4;
11045 if (log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", fName, fTarget.getAddress());
11046 }
11047 }
11048 else {
11049 // target of island is ultimate target
11050 displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress() - 4;
11051 if (log) fprintf(stderr, "%s: jump to target at 0x%08llX\n", fName, fTarget.getAddress());
11052 }
11053 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
11054 throwf("internal branch island error: thumb2 b/bx out of range (%lld max is +/-16M) from %s to %s in %s",
11055 displacement, this->getDisplayName(),
11056 fTarget.getDisplayName(), fTarget.getFile()->getPath());
11057 }
11058 // The instruction is really two instructions:
11059 // The lower 16 bits are the first instruction, which contains the high
11060 // 11 bits of the displacement.
11061 // The upper 16 bits are the second instruction, which contains the low
11062 // 11 bits of the displacement, as well as differentiating bl and blx.
11063 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
11064 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
11065 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
11066 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
11067 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
11068 uint32_t j1 = (i1 == s);
11069 uint32_t j2 = (i2 == s);
11070 uint32_t opcode = 0x9000F000;
11071 uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
11072 uint32_t firstDisp = (s << 10) | imm10;
11073 uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp;
11074 //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
11075 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
11076 OSWriteLittleInt32(buffer, 0, newInstruction);
11077 }
11078 break;
11079 case kBranchIslandToThumb1:
11080 {
11081 // There is no large displacement thumb1 branch instruction.
11082 // Instead use ARM instructions that can jump to thumb.
11083 // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
11084 int64_t displacement = getFinalTargetAdress() - (this->getAddress() + 12);
11085 if ( fFinalTarget.isThumb() )
11086 displacement |= 1;
11087 if (log) fprintf(stderr, "%s: 4 ARM instruction jump to final target at 0x%08llX\n", fName, getFinalTargetAdress());
11088 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 4
11089 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
11090 OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); // bx ip
11091 OSWriteLittleInt32(&buffer[12], 0, displacement); // .long target-this
11092 }
11093 break;
11094 };
11095 }
11096
11097 template <>
11098 uint64_t BranchIslandAtom<ppc>::getSize() const
11099 {
11100 return 4;
11101 }
11102
11103 template <>
11104 uint64_t BranchIslandAtom<ppc64>::getSize() const
11105 {
11106 return 4;
11107 }
11108
11109 template <>
11110 uint64_t BranchIslandAtom<arm>::getSize() const
11111 {
11112 switch ( fIslandKind ) {
11113 case kBranchIslandToARM:
11114 return 4;
11115 case kBranchIslandToThumb1:
11116 return 16;
11117 case kBranchIslandToThumb2:
11118 return 4;
11119 };
11120 throw "internal error: no ARM branch island kind";
11121 }
11122
11123
11124
11125 template <typename A>
11126 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
11127 {
11128 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
11129 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
11130 else
11131 return 0; // a zero size causes the load command to be suppressed
11132 }
11133
11134 template <typename A>
11135 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
11136 {
11137 uint64_t size = this->getSize();
11138 if ( size > 0 ) {
11139 bzero(buffer, size);
11140 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
11141 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
11142 cmd->set_cmdsize(size);
11143 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
11144 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
11145 }
11146 }
11147
11148
11149 template <typename A>
11150 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
11151 {
11152 return fEncodedData.size();
11153 }
11154
11155 template <typename A>
11156 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
11157 {
11158 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
11159 }
11160
11161
11162 template <typename A>
11163 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
11164 {
11165 pint_t addr = fWriter.fOptions.baseAddress();
11166 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
11167 pint_t nextAddr = it->atom->getAddress() + it->offset;
11168 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
11169 uint64_t delta = nextAddr - addr;
11170 if ( delta == 0 )
11171 throw "double split seg info for same address";
11172 // uleb128 encode
11173 uint8_t byte;
11174 do {
11175 byte = delta & 0x7F;
11176 delta &= ~0x7F;
11177 if ( delta != 0 )
11178 byte |= 0x80;
11179 fEncodedData.push_back(byte);
11180 delta = delta >> 7;
11181 }
11182 while( byte >= 0x80 );
11183 addr = nextAddr;
11184 }
11185 }
11186
11187 template <typename A>
11188 void SegmentSplitInfoContentAtom<A>::encode()
11189 {
11190 if ( ! fCantEncode ) {
11191 fEncodedData.reserve(8192);
11192
11193 if ( fKind1Locations.size() != 0 ) {
11194 fEncodedData.push_back(1);
11195 //fprintf(stderr, "type 1:\n");
11196 this->uleb128EncodeAddresses(fKind1Locations);
11197 fEncodedData.push_back(0);
11198 }
11199
11200 if ( fKind2Locations.size() != 0 ) {
11201 fEncodedData.push_back(2);
11202 //fprintf(stderr, "type 2:\n");
11203 this->uleb128EncodeAddresses(fKind2Locations);
11204 fEncodedData.push_back(0);
11205 }
11206
11207 if ( fKind3Locations.size() != 0 ) {
11208 fEncodedData.push_back(3);
11209 //fprintf(stderr, "type 3:\n");
11210 this->uleb128EncodeAddresses(fKind3Locations);
11211 fEncodedData.push_back(0);
11212 }
11213
11214 if ( fKind4Locations.size() != 0 ) {
11215 fEncodedData.push_back(4);
11216 //fprintf(stderr, "type 4:\n");
11217 this->uleb128EncodeAddresses(fKind4Locations);
11218 fEncodedData.push_back(0);
11219 }
11220
11221 // always add zero byte to mark end
11222 fEncodedData.push_back(0);
11223
11224 // add zeros to end to align size
11225 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
11226 fEncodedData.push_back(0);
11227 }
11228 }
11229
11230
11231 template <typename A>
11232 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
11233 : WriterAtom<A>(writer, getInfoSegment())
11234 {
11235 fContent[0] = 0;
11236 uint32_t value = 0;
11237 // struct objc_image_info {
11238 // uint32_t version; // initially 0
11239 // uint32_t flags;
11240 // };
11241 // #define OBJC_IMAGE_SUPPORTS_GC 2
11242 // #define OBJC_IMAGE_GC_ONLY 4
11243 //
11244 if ( objcReplacementClasses )
11245 value = 1;
11246 switch ( objcConstraint ) {
11247 case ObjectFile::Reader::kObjcNone:
11248 case ObjectFile::Reader::kObjcRetainRelease:
11249 break;
11250 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
11251 value |= 2;
11252 break;
11253 case ObjectFile::Reader::kObjcGC:
11254 value |= 6;
11255 break;
11256 }
11257 A::P::E::set32(fContent[1], value);
11258 }
11259
11260 template <typename A>
11261 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
11262 {
11263 memcpy(buffer, &fContent[0], 8);
11264 }
11265
11266
11267 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
11268 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
11269 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
11270 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
11271 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
11272 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
11273
11274 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
11275 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
11276 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
11277 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
11278 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
11279
11280
11281
11282
11283 template <typename A>
11284 void DyldInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
11285 {
11286 // build LC_DYLD_INFO command
11287 macho_dyld_info_command<P>* cmd = (macho_dyld_info_command<P>*)buffer;
11288 bzero(cmd, sizeof(macho_dyld_info_command<P>));
11289
11290 cmd->set_cmd( fWriter.fOptions.makeClassicDyldInfo() ? LC_DYLD_INFO : LC_DYLD_INFO_ONLY);
11291 cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
11292 if ( (fWriter.fCompressedRebaseInfoAtom != NULL) && (fWriter.fCompressedRebaseInfoAtom->getSize() != 0) ) {
11293 cmd->set_rebase_off(fWriter.fCompressedRebaseInfoAtom->getFileOffset());
11294 cmd->set_rebase_size(fWriter.fCompressedRebaseInfoAtom->getSize());
11295 }
11296 if ( (fWriter.fCompressedBindingInfoAtom != NULL) && (fWriter.fCompressedBindingInfoAtom->getSize() != 0) ) {
11297 cmd->set_bind_off(fWriter.fCompressedBindingInfoAtom->getFileOffset());
11298 cmd->set_bind_size(fWriter.fCompressedBindingInfoAtom->getSize());
11299 }
11300 if ( (fWriter.fCompressedWeakBindingInfoAtom != NULL) && (fWriter.fCompressedWeakBindingInfoAtom->getSize() != 0) ) {
11301 cmd->set_weak_bind_off(fWriter.fCompressedWeakBindingInfoAtom->getFileOffset());
11302 cmd->set_weak_bind_size(fWriter.fCompressedWeakBindingInfoAtom->getSize());
11303 }
11304 if ( (fWriter.fCompressedLazyBindingInfoAtom != NULL) && (fWriter.fCompressedLazyBindingInfoAtom->getSize() != 0) ) {
11305 cmd->set_lazy_bind_off(fWriter.fCompressedLazyBindingInfoAtom->getFileOffset());
11306 cmd->set_lazy_bind_size(fWriter.fCompressedLazyBindingInfoAtom->getSize());
11307 }
11308 if ( (fWriter.fCompressedExportInfoAtom != NULL) && (fWriter.fCompressedExportInfoAtom->getSize() != 0) ) {
11309 cmd->set_export_off(fWriter.fCompressedExportInfoAtom->getFileOffset());
11310 cmd->set_export_size(fWriter.fCompressedExportInfoAtom->getSize());
11311 }
11312 }
11313
11314
11315 struct rebase_tmp
11316 {
11317 rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
11318 uint8_t opcode;
11319 uint64_t operand1;
11320 uint64_t operand2;
11321 };
11322
11323
11324 template <typename A>
11325 void CompressedRebaseInfoLinkEditAtom<A>::encode()
11326 {
11327 // sort rebase info by type, then address
11328 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11329 std::vector<RebaseInfo>& info = fWriter.fRebaseInfo;
11330 std::sort(info.begin(), info.end());
11331
11332 // convert to temp encoding that can be more easily optimized
11333 std::vector<rebase_tmp> mid;
11334 const SegmentInfo* currentSegment = NULL;
11335 unsigned int segIndex = 0;
11336 uint8_t type = 0;
11337 uint64_t address = (uint64_t)(-1);
11338 for (std::vector<RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11339 if ( type != it->fType ) {
11340 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->fType));
11341 type = it->fType;
11342 }
11343 if ( address != it->fAddress ) {
11344 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11345 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= it->fAddress) ) {
11346 segIndex = 0;
11347 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11348 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11349 currentSegment = *segit;
11350 break;
11351 }
11352 ++segIndex;
11353 }
11354 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11355 }
11356 else {
11357 mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11358 }
11359 address = it->fAddress;
11360 }
11361 mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
11362 address += sizeof(pint_t);
11363 }
11364 mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
11365
11366 // optimize phase 1, compress packed runs of pointers
11367 rebase_tmp* dst = &mid[0];
11368 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11369 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
11370 *dst = *src++;
11371 while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
11372 dst->operand1 += src->operand1;
11373 ++src;
11374 }
11375 --src;
11376 ++dst;
11377 }
11378 else {
11379 *dst++ = *src;
11380 }
11381 }
11382 dst->opcode = REBASE_OPCODE_DONE;
11383
11384 // optimize phase 2, combine rebase/add pairs
11385 dst = &mid[0];
11386 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11387 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
11388 && (src->operand1 == 1)
11389 && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
11390 dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
11391 dst->operand1 = src[1].operand1;
11392 ++src;
11393 ++dst;
11394 }
11395 else {
11396 *dst++ = *src;
11397 }
11398 }
11399 dst->opcode = REBASE_OPCODE_DONE;
11400
11401 // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
11402 // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
11403 dst = &mid[0];
11404 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11405 uint64_t delta = src->operand1;
11406 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11407 && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11408 && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11409 && (src[1].operand1 == delta)
11410 && (src[2].operand1 == delta) ) {
11411 // found at least three in a row, this is worth compressing
11412 dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
11413 dst->operand1 = 1;
11414 dst->operand2 = delta;
11415 ++src;
11416 while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11417 && (src->operand1 == delta) ) {
11418 dst->operand1++;
11419 ++src;
11420 }
11421 --src;
11422 ++dst;
11423 }
11424 else {
11425 *dst++ = *src;
11426 }
11427 }
11428 dst->opcode = REBASE_OPCODE_DONE;
11429
11430 // optimize phase 4, use immediate encodings
11431 for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11432 if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB)
11433 && (p->operand1 < (15*sizeof(pint_t)))
11434 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11435 p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
11436 p->operand1 = p->operand1/sizeof(pint_t);
11437 }
11438 else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
11439 p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
11440 }
11441 }
11442
11443 // convert to compressed encoding
11444 const static bool log = false;
11445 fEncodedData.reserve(info.size()*2);
11446 bool done = false;
11447 for (std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11448 switch ( it->opcode ) {
11449 case REBASE_OPCODE_DONE:
11450 if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
11451 done = true;
11452 break;
11453 case REBASE_OPCODE_SET_TYPE_IMM:
11454 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11455 fEncodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
11456 break;
11457 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11458 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11459 fEncodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11460 fEncodedData.append_uleb128(it->operand2);
11461 break;
11462 case REBASE_OPCODE_ADD_ADDR_ULEB:
11463 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11464 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
11465 fEncodedData.append_uleb128(it->operand1);
11466 break;
11467 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
11468 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11469 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
11470 break;
11471 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
11472 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
11473 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
11474 break;
11475 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
11476 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
11477 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
11478 fEncodedData.append_uleb128(it->operand1);
11479 break;
11480 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
11481 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11482 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
11483 fEncodedData.append_uleb128(it->operand1);
11484 break;
11485 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
11486 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11487 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
11488 fEncodedData.append_uleb128(it->operand1);
11489 fEncodedData.append_uleb128(it->operand2);
11490 break;
11491 }
11492 }
11493
11494
11495 // align to pointer size
11496 fEncodedData.pad_to_size(sizeof(pint_t));
11497
11498 if (log) fprintf(stderr, "total rebase info size = %ld\n", fEncodedData.size());
11499 }
11500
11501
11502 struct binding_tmp
11503 {
11504 binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
11505 : opcode(op), operand1(p1), operand2(p2), name(s) {}
11506 uint8_t opcode;
11507 uint64_t operand1;
11508 uint64_t operand2;
11509 const char* name;
11510 };
11511
11512
11513
11514 template <typename A>
11515 void CompressedBindingInfoLinkEditAtom<A>::encode()
11516 {
11517 // sort by library, symbol, type, then address
11518 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11519 std::vector<BindingInfo>& info = fWriter.fBindingInfo;
11520 std::sort(info.begin(), info.end());
11521
11522 // convert to temp encoding that can be more easily optimized
11523 std::vector<binding_tmp> mid;
11524 const SegmentInfo* currentSegment = NULL;
11525 unsigned int segIndex = 0;
11526 int ordinal = 0x80000000;
11527 const char* symbolName = NULL;
11528 uint8_t type = 0;
11529 uint64_t address = (uint64_t)(-1);
11530 int64_t addend = 0;
11531 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11532 if ( ordinal != it->fLibraryOrdinal ) {
11533 if ( it->fLibraryOrdinal <= 0 ) {
11534 // special lookups are encoded as negative numbers in BindingInfo
11535 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->fLibraryOrdinal));
11536 }
11537 else {
11538 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->fLibraryOrdinal));
11539 }
11540 ordinal = it->fLibraryOrdinal;
11541 }
11542 if ( symbolName != it->fSymbolName ) {
11543 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11544 symbolName = it->fSymbolName;
11545 }
11546 if ( type != it->fType ) {
11547 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11548 type = it->fType;
11549 }
11550 if ( address != it->fAddress ) {
11551 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11552 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress)
11553 || (it->fAddress < address) ) {
11554 segIndex = 0;
11555 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11556 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11557 currentSegment = *segit;
11558 break;
11559 }
11560 ++segIndex;
11561 }
11562 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11563 }
11564 else {
11565 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11566 }
11567 address = it->fAddress;
11568 }
11569 if ( addend != it->fAddend ) {
11570 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11571 addend = it->fAddend;
11572 }
11573 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11574 address += sizeof(pint_t);
11575 }
11576 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11577
11578
11579 // optimize phase 1, combine bind/add pairs
11580 binding_tmp* dst = &mid[0];
11581 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11582 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11583 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11584 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11585 dst->operand1 = src[1].operand1;
11586 ++src;
11587 ++dst;
11588 }
11589 else {
11590 *dst++ = *src;
11591 }
11592 }
11593 dst->opcode = BIND_OPCODE_DONE;
11594
11595 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11596 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11597 dst = &mid[0];
11598 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11599 uint64_t delta = src->operand1;
11600 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11601 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11602 && (src[1].operand1 == delta) ) {
11603 // found at least two in a row, this is worth compressing
11604 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11605 dst->operand1 = 1;
11606 dst->operand2 = delta;
11607 ++src;
11608 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11609 && (src->operand1 == delta) ) {
11610 dst->operand1++;
11611 ++src;
11612 }
11613 --src;
11614 ++dst;
11615 }
11616 else {
11617 *dst++ = *src;
11618 }
11619 }
11620 dst->opcode = BIND_OPCODE_DONE;
11621
11622 // optimize phase 3, use immediate encodings
11623 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11624 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11625 && (p->operand1 < (15*sizeof(pint_t)))
11626 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11627 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11628 p->operand1 = p->operand1/sizeof(pint_t);
11629 }
11630 else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
11631 p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
11632 }
11633 }
11634 dst->opcode = BIND_OPCODE_DONE;
11635
11636 // convert to compressed encoding
11637 const static bool log = false;
11638 fEncodedData.reserve(info.size()*2);
11639 bool done = false;
11640 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11641 switch ( it->opcode ) {
11642 case BIND_OPCODE_DONE:
11643 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11644 done = true;
11645 break;
11646 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11647 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11648 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11649 break;
11650 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11651 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11652 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11653 fEncodedData.append_uleb128(it->operand1);
11654 break;
11655 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11656 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11657 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11658 break;
11659 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11660 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11661 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11662 fEncodedData.append_string(it->name);
11663 break;
11664 case BIND_OPCODE_SET_TYPE_IMM:
11665 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11666 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11667 break;
11668 case BIND_OPCODE_SET_ADDEND_SLEB:
11669 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11670 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11671 fEncodedData.append_sleb128(it->operand1);
11672 break;
11673 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11674 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11675 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11676 fEncodedData.append_uleb128(it->operand2);
11677 break;
11678 case BIND_OPCODE_ADD_ADDR_ULEB:
11679 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11680 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11681 fEncodedData.append_uleb128(it->operand1);
11682 break;
11683 case BIND_OPCODE_DO_BIND:
11684 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11685 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11686 break;
11687 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11688 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11689 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11690 fEncodedData.append_uleb128(it->operand1);
11691 break;
11692 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11693 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11694 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11695 break;
11696 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11697 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11698 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11699 fEncodedData.append_uleb128(it->operand1);
11700 fEncodedData.append_uleb128(it->operand2);
11701 break;
11702 }
11703 }
11704
11705 // align to pointer size
11706 fEncodedData.pad_to_size(sizeof(pint_t));
11707
11708 if (log) fprintf(stderr, "total binding info size = %ld\n", fEncodedData.size());
11709
11710 }
11711
11712
11713
11714 struct WeakBindingSorter
11715 {
11716 bool operator()(const BindingInfo& left, const BindingInfo& right)
11717 {
11718 // sort by symbol, type, address
11719 if ( left.fSymbolName != right.fSymbolName )
11720 return ( strcmp(left.fSymbolName, right.fSymbolName) < 0 );
11721 if ( left.fType != right.fType )
11722 return (left.fType < right.fType);
11723 return (left.fAddress < right.fAddress);
11724 }
11725 };
11726
11727
11728
11729 template <typename A>
11730 void CompressedWeakBindingInfoLinkEditAtom<A>::encode()
11731 {
11732 // add regular atoms that override a dylib's weak definitions
11733 for(std::set<const class ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
11734 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
11735 if ( fWriter.shouldExport(**it) )
11736 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, (*it)->getName(), true, 0, 0));
11737 }
11738
11739 // add all exported weak definitions
11740 for(std::vector<class ObjectFile::Atom*>::iterator it = fWriter.fAllAtoms->begin(); it != fWriter.fAllAtoms->end(); ++it) {
11741 ObjectFile::Atom* atom = *it;
11742 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) && fWriter.shouldExport(*atom) ) {
11743 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, atom->getName(), false, 0, 0));
11744 }
11745 }
11746
11747 // sort by symbol, type, address
11748 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11749 std::vector<BindingInfo>& info = fWriter.fWeakBindingInfo;
11750 if ( info.size() == 0 )
11751 return;
11752 std::sort(info.begin(), info.end(), WeakBindingSorter());
11753
11754 // convert to temp encoding that can be more easily optimized
11755 std::vector<binding_tmp> mid;
11756 mid.reserve(info.size());
11757 const SegmentInfo* currentSegment = NULL;
11758 unsigned int segIndex = 0;
11759 const char* symbolName = NULL;
11760 uint8_t type = 0;
11761 uint64_t address = (uint64_t)(-1);
11762 int64_t addend = 0;
11763 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11764 if ( symbolName != it->fSymbolName ) {
11765 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11766 symbolName = it->fSymbolName;
11767 }
11768 if ( it->fType != 0 ) {
11769 if ( type != it->fType ) {
11770 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11771 type = it->fType;
11772 }
11773 if ( address != it->fAddress ) {
11774 // non weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
11775 // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
11776 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11777 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress) ) {
11778 segIndex = 0;
11779 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11780 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11781 currentSegment = *segit;
11782 break;
11783 }
11784 ++segIndex;
11785 }
11786 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11787 }
11788 else {
11789 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11790 }
11791 address = it->fAddress;
11792 }
11793 if ( addend != it->fAddend ) {
11794 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11795 addend = it->fAddend;
11796 }
11797 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11798 address += sizeof(pint_t);
11799 }
11800 }
11801 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11802
11803
11804 // optimize phase 1, combine bind/add pairs
11805 binding_tmp* dst = &mid[0];
11806 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11807 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11808 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11809 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11810 dst->operand1 = src[1].operand1;
11811 ++src;
11812 ++dst;
11813 }
11814 else {
11815 *dst++ = *src;
11816 }
11817 }
11818 dst->opcode = BIND_OPCODE_DONE;
11819
11820 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11821 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11822 dst = &mid[0];
11823 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11824 uint64_t delta = src->operand1;
11825 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11826 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11827 && (src[1].operand1 == delta) ) {
11828 // found at least two in a row, this is worth compressing
11829 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11830 dst->operand1 = 1;
11831 dst->operand2 = delta;
11832 ++src;
11833 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11834 && (src->operand1 == delta) ) {
11835 dst->operand1++;
11836 ++src;
11837 }
11838 --src;
11839 ++dst;
11840 }
11841 else {
11842 *dst++ = *src;
11843 }
11844 }
11845 dst->opcode = BIND_OPCODE_DONE;
11846
11847 // optimize phase 3, use immediate encodings
11848 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11849 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11850 && (p->operand1 < (15*sizeof(pint_t)))
11851 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11852 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11853 p->operand1 = p->operand1/sizeof(pint_t);
11854 }
11855 }
11856 dst->opcode = BIND_OPCODE_DONE;
11857
11858
11859 // convert to compressed encoding
11860 const static bool log = false;
11861 fEncodedData.reserve(info.size()*2);
11862 bool done = false;
11863 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11864 switch ( it->opcode ) {
11865 case BIND_OPCODE_DONE:
11866 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11867 fEncodedData.append_byte(BIND_OPCODE_DONE);
11868 done = true;
11869 break;
11870 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11871 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11872 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11873 break;
11874 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11875 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11876 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11877 fEncodedData.append_uleb128(it->operand1);
11878 break;
11879 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11880 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11881 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11882 break;
11883 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11884 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11885 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11886 fEncodedData.append_string(it->name);
11887 break;
11888 case BIND_OPCODE_SET_TYPE_IMM:
11889 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11890 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11891 break;
11892 case BIND_OPCODE_SET_ADDEND_SLEB:
11893 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11894 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11895 fEncodedData.append_sleb128(it->operand1);
11896 break;
11897 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11898 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11899 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11900 fEncodedData.append_uleb128(it->operand2);
11901 break;
11902 case BIND_OPCODE_ADD_ADDR_ULEB:
11903 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11904 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11905 fEncodedData.append_uleb128(it->operand1);
11906 break;
11907 case BIND_OPCODE_DO_BIND:
11908 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11909 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11910 break;
11911 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11912 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11913 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11914 fEncodedData.append_uleb128(it->operand1);
11915 break;
11916 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11917 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11918 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11919 break;
11920 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11921 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11922 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11923 fEncodedData.append_uleb128(it->operand1);
11924 fEncodedData.append_uleb128(it->operand2);
11925 break;
11926 }
11927 }
11928
11929 // align to pointer size
11930 fEncodedData.pad_to_size(sizeof(pint_t));
11931
11932 if (log) fprintf(stderr, "total weak binding info size = %ld\n", fEncodedData.size());
11933
11934 }
11935
11936 template <typename A>
11937 void CompressedLazyBindingInfoLinkEditAtom<A>::encode()
11938 {
11939 // stream all lazy bindings and record start offsets
11940 const SegmentInfo* currentSegment = NULL;
11941 uint8_t segIndex = 0;
11942 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11943 std::vector<class LazyPointerAtom<A>*>& allLazys = fWriter.fAllSynthesizedLazyPointers;
11944 for (typename std::vector<class LazyPointerAtom<A>*>::iterator it = allLazys.begin(); it != allLazys.end(); ++it) {
11945 LazyPointerAtom<A>* lazyPointerAtom = *it;
11946 ObjectFile::Atom* lazyPointerTargetAtom = lazyPointerAtom->getTarget();
11947
11948 // skip lazy pointers that are bound non-lazily because they are coalesced
11949 if ( ! fWriter.targetRequiresWeakBinding(*lazyPointerTargetAtom) ) {
11950 // record start offset for use by stub helper
11951 lazyPointerAtom->setLazyBindingInfoOffset(fEncodedData.size());
11952
11953 // write address to bind
11954 pint_t address = lazyPointerAtom->getAddress();
11955 if ( (currentSegment == NULL) || (address < currentSegment->fBaseAddress)
11956 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= address) ) {
11957 segIndex = 0;
11958 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11959 if ( ((*segit)->fBaseAddress <= address) && (address < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11960 currentSegment = *segit;
11961 break;
11962 }
11963 ++segIndex;
11964 }
11965 }
11966 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
11967 fEncodedData.append_uleb128(lazyPointerAtom->getAddress() - currentSegment->fBaseAddress);
11968
11969 // write ordinal
11970 int ordinal = fWriter.compressedOrdinalForImortedAtom(lazyPointerTargetAtom);
11971 if ( ordinal <= 0 ) {
11972 // special lookups are encoded as negative numbers in BindingInfo
11973 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (ordinal & BIND_IMMEDIATE_MASK) );
11974 }
11975 else if ( ordinal <= 15 ) {
11976 // small ordinals are encoded in opcode
11977 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
11978 }
11979 else {
11980 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11981 fEncodedData.append_uleb128(ordinal);
11982 }
11983 // write symbol name
11984 bool weak_import = fWriter.fWeakImportMap[lazyPointerTargetAtom];
11985 if ( weak_import )
11986 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | BIND_SYMBOL_FLAGS_WEAK_IMPORT);
11987 else
11988 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
11989 fEncodedData.append_string(lazyPointerTargetAtom->getName());
11990 // write do bind
11991 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11992 fEncodedData.append_byte(BIND_OPCODE_DONE);
11993 }
11994 }
11995 // align to pointer size
11996 fEncodedData.pad_to_size(sizeof(pint_t));
11997
11998 //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", fEncodedData.size(), allLazys.size());
11999 }
12000
12001 struct TrieEntriesSorter
12002 {
12003 TrieEntriesSorter(Options& o) : fOptions(o) {}
12004
12005 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
12006 {
12007 unsigned int leftOrder;
12008 unsigned int rightOrder;
12009 fOptions.exportedSymbolOrder(left.name, &leftOrder);
12010 fOptions.exportedSymbolOrder(right.name, &rightOrder);
12011 if ( leftOrder != rightOrder )
12012 return (leftOrder < rightOrder);
12013 else
12014 return (left.address < right.address);
12015 }
12016 private:
12017 Options& fOptions;
12018 };
12019
12020
12021 template <typename A>
12022 void CompressedExportInfoLinkEditAtom<A>::encode()
12023 {
12024 // make vector of mach_o::trie::Entry for all exported symbols
12025 std::vector<class ObjectFile::Atom*>& exports = fWriter.fExportedAtoms;
12026 uint64_t imageBaseAddress = fWriter.fMachHeaderAtom->getAddress();
12027 std::vector<mach_o::trie::Entry> entries;
12028 entries.reserve(exports.size());
12029 for (std::vector<ObjectFile::Atom*>::iterator it = exports.begin(); it != exports.end(); ++it) {
12030 ObjectFile::Atom* atom = *it;
12031 uint64_t flags = 0;
12032 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
12033 flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
12034 uint64_t address = atom->getAddress() - imageBaseAddress;
12035 if ( atom->isThumb() )
12036 address |= 1;
12037 mach_o::trie::Entry entry;
12038 entry.name = atom->getName();
12039 entry.flags = flags;
12040 entry.address = address;
12041 entries.push_back(entry);
12042 }
12043
12044 // sort vector by -exported_symbols_order, and any others by address
12045 std::sort(entries.begin(), entries.end(), TrieEntriesSorter(fWriter.fOptions));
12046
12047 // create trie
12048 mach_o::trie::makeTrie(entries, fEncodedData.bytes());
12049
12050 // align to pointer size
12051 fEncodedData.pad_to_size(sizeof(pint_t));
12052 }
12053
12054
12055
12056
12057
12058 }; // namespace executable
12059 }; // namespace mach_o
12060
12061
12062 #endif // __EXECUTABLE_MACH_O__