1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __EXECUTABLE_MACH_O__
26 #define __EXECUTABLE_MACH_O__
32 #include <uuid/uuid.h>
33 #include <mach/i386/thread_status.h>
34 #include <mach/ppc/thread_status.h>
35 #include <CommonCrypto/CommonDigest.h>
41 #include <ext/hash_map>
43 #include "ObjectFile.h"
44 #include "ExecutableFile.h"
47 #include "MachOFileAbstraction.hpp"
48 #include "MachOTrie.hpp"
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()
67 namespace executable {
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;
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 {
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;
129 uint32_t fRelocCount;
130 uint32_t fRelocOffset;
131 uint32_t fIndirectSymbolOffset;
133 bool fAllLazyPointers;
134 bool fAllLazyDylibPointers;
135 bool fAllNonLazyPointers;
137 bool fAllSelfModifyingStubs;
138 bool fAllStubHelpers;
140 bool fVirtualSection;
141 bool fHasTextLocalRelocs;
142 bool fHasTextExternalRelocs;
145 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
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;
154 uint32_t fInitProtection;
155 uint32_t fMaxProtection;
156 uint64_t fFileOffset;
158 uint64_t fBaseAddress;
162 bool fIndependentAddress;
163 bool fHasLoadCommand;
168 RebaseInfo(uint8_t t, uint64_t addr) : fType(t), fAddress(addr) {}
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 );
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) {}
190 const char* fSymbolName;
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 );
210 std::vector<uint8_t> fData;
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]; }
217 void append_uleb128(uint64_t value) {
224 fData.push_back(byte);
226 } while( byte >= 0x80 );
229 void append_sleb128(int64_t value) {
230 bool isNeg = ( value < 0 );
237 more = ( (value != -1) || ((byte & 0x40) == 0) );
239 more = ( (value != 0) || ((byte & 0x40) != 0) );
242 fData.push_back(byte);
247 void append_string(const char* str) {
248 for (const char* s = str; *s != '\0'; ++s)
250 fData.push_back('\0');
253 void append_byte(uint8_t byte) {
254 fData.push_back(byte);
257 static unsigned int uleb128_size(uint64_t value) {
262 } while ( value != 0 );
266 void pad_to_size(unsigned int alignment) {
267 while ( (fData.size() % alignment) != 0 )
273 template <typename A>
274 class Writer : public ExecutableFile::Writer
277 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
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; }
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);
306 typedef typename A::P P;
307 typedef typename A::P::uint_t pint_t;
309 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
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();
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;
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;
387 struct DirectLibrary {
388 class ObjectFile::Reader* fLibrary;
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>;
435 const char* fFilePath;
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;
510 bool fWritableSegmentPastFirst4GB;
511 bool fNoReExportedDylibs;
512 bool fBiggerThanTwoGigs;
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;
524 class Segment : public ObjectFile::Segment
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; }
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;
548 const bool fReadable;
549 const bool fWritable;
550 const bool fExecutable;
551 const bool fFixedAddress;
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);
565 template <typename A>
566 class WriterAtom : public ObjectFile::Atom
569 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
570 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
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) { }
594 virtual ~WriterAtom() {}
595 typedef typename A::P P;
596 typedef typename A::P::E E;
598 static Segment& headerSegment(Writer<A>& writer) { return (writer.fOptions.outputKind()==Options::kPreload)
599 ? Segment::fgHeaderSegment : Segment::fgTextSegment; }
601 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
607 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
610 template <typename A>
611 class PageZeroAtom : public WriterAtom<A>
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; }
623 using WriterAtom<A>::fWriter;
624 typedef typename A::P P;
629 template <typename A>
630 class DsoHandleAtom : public WriterAtom<A>
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 {}
644 template <typename A>
645 class MachHeaderAtom : public WriterAtom<A>
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;
659 using WriterAtom<A>::fWriter;
660 typedef typename A::P P;
661 void setHeaderInfo(macho_header<typename A::P>& header) const;
664 template <typename A>
665 class CustomStackAtom : public WriterAtom<A>
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); }
675 using WriterAtom<A>::fWriter;
676 typedef typename A::P P;
677 static bool stackGrowsDown();
680 template <typename A>
681 class LoadCommandAtom : public WriterAtom<A>
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);
691 static uint32_t fgCurrentOrdinal;
694 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
696 template <typename A>
697 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
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;
709 unsigned int commandCount() { return fCommandCount; }
711 using WriterAtom<A>::fWriter;
712 typedef typename A::P P;
713 unsigned int fCommandCount;
718 template <typename A>
719 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
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();
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;
736 template <typename A>
737 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
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;
746 using WriterAtom<A>::fWriter;
747 typedef typename A::P P;
749 uint32_t fBufferSize;
752 template <typename A>
753 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
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;
761 using WriterAtom<A>::fWriter;
762 typedef typename A::P P;
765 template <typename A>
766 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
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;
774 using WriterAtom<A>::fWriter;
775 typedef typename A::P P;
778 template <typename A>
779 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
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;
788 using WriterAtom<A>::fWriter;
789 typedef typename A::P P;
790 const char* clientString;
793 template <typename A>
794 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
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; }
806 using WriterAtom<A>::fWriter;
807 typedef typename A::P P;
808 ExecutableFile::DyLibUsed fInfo;
812 template <typename A>
813 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
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;
821 using WriterAtom<A>::fWriter;
822 typedef typename A::P P;
825 template <typename A>
826 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
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;
834 using WriterAtom<A>::fWriter;
835 typedef typename A::P P;
838 template <typename A>
839 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
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;
848 typedef typename A::P P;
852 template <typename A>
853 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
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;
862 using WriterAtom<A>::fWriter;
863 typedef typename A::P P;
864 const char* fNameStart;
868 template <typename A>
869 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
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;
878 using WriterAtom<A>::fWriter;
879 typedef typename A::P P;
883 template <typename A>
884 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
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; }
896 using WriterAtom<A>::fWriter;
897 typedef typename A::P P;
903 template <typename A>
904 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
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;
913 using WriterAtom<A>::fWriter;
914 typedef typename A::P P;
918 template <typename A>
919 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
922 EncryptionLoadCommandsAtom(Writer<A>& writer)
923 : LoadCommandAtom<A>(writer), fStartOffset(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; }
931 using WriterAtom<A>::fWriter;
932 typedef typename A::P P;
933 uint32_t fStartOffset;
937 template <typename A>
938 class DyldInfoLoadCommandsAtom : public LoadCommandAtom<A>
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;
947 using WriterAtom<A>::fWriter;
948 typedef typename A::P P;
952 template <typename A>
953 class LoadCommandsPaddingAtom : public WriterAtom<A>
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;
963 void setSize(uint64_t newSize);
965 using WriterAtom<A>::fWriter;
966 typedef typename A::P P;
970 template <typename A>
971 class UnwindInfoAtom : public WriterAtom<A>
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;
986 void addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
987 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsda,
988 ObjectFile::Atom* personalityPointer);
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; };
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,
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);
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;
1029 template <typename A>
1030 class LinkEditAtom : public WriterAtom<A>
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; }
1039 static uint32_t fgCurrentOrdinal;
1041 typedef typename A::P P;
1044 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
1046 template <typename A>
1047 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
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;
1056 using WriterAtom<A>::fWriter;
1057 typedef typename A::P P;
1060 template <typename A>
1061 class CompressedInfoLinkEditAtom : public LinkEditAtom<A>
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()); }
1068 typedef typename A::P::uint_t pint_t;
1069 ByteStream fEncodedData;
1071 using WriterAtom<A>::fWriter;
1072 typedef typename A::P P;
1077 template <typename A>
1078 class CompressedRebaseInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
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"; }
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;
1092 template <typename A>
1093 class CompressedBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
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"; }
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;
1107 template <typename A>
1108 class CompressedWeakBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
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"; }
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;
1122 template <typename A>
1123 class CompressedLazyBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
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"; }
1131 std::vector<uint32_t> fStarts;
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;
1140 template <typename A>
1141 class CompressedExportInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
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"; }
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;
1158 edge(const char* s, struct node* n) : fSubString(s), fChild(n) { }
1160 const char* fSubString;
1161 struct node* fChild;
1167 node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false),
1168 fHaveExportInfo(false), fTrieOffset(0) {}
1170 const char* fCummulativeString;
1171 std::vector<edge> fChildren;
1175 bool fHaveExportInfo;
1176 uint32_t fTrieOffset;
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) {
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);
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]);
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);
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;
1221 void addOrderedNodes(const char* name, std::vector<node*>& orderedNodes) {
1223 orderedNodes.push_back(this);
1224 //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
1227 const char* partialStr = &name[strlen(fCummulativeString)];
1228 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++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);
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);
1249 ++nodeSize; // byte for count of chidren
1250 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1252 nodeSize += strlen(e.fSubString) + 1 + ByteStream::uleb128_size(e.fChild->fTrieOffset);
1254 bool result = (fTrieOffset != offset);
1255 fTrieOffset = offset;
1256 //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
1258 // return true if fTrieOffset was changed
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);
1273 // write number of children
1274 out.append_byte(fChildren.size());
1276 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1278 out.append_string(e.fSubString);
1279 out.append_uleb128(e.fChild->fTrieOffset);
1286 struct node fStartNode;
1289 template <typename A>
1290 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
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;
1299 using WriterAtom<A>::fWriter;
1300 typedef typename A::P P;
1303 template <typename A>
1304 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
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;
1313 using WriterAtom<A>::fWriter;
1314 typedef typename A::P P;
1317 template <typename A>
1318 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
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;
1327 using WriterAtom<A>::fWriter;
1328 typedef typename A::P P;
1331 struct IndirectEntry {
1332 uint32_t indirectIndex;
1333 uint32_t symbolIndex;
1337 template <typename A>
1338 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
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)); }
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;
1363 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
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;
1373 template <typename A>
1374 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
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;
1383 std::vector<IndirectEntry> fTable;
1386 using WriterAtom<A>::fWriter;
1387 typedef typename A::P P;
1390 template <typename A>
1391 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
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;
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;
1407 using WriterAtom<A>::fWriter;
1408 typedef typename A::P P;
1409 typedef typename A::P::uint_t pint_t;
1410 uint32_t fModuleNameOffset;
1417 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
1420 template <typename A>
1421 class StringsLinkEditAtom : public LinkEditAtom<A>
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;
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;
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;
1441 std::vector<char*> fFullBuffers;
1442 char* fCurrentBuffer;
1443 uint32_t fCurrentBufferUsed;
1444 StringToOffset fUniqueStrings;
1449 template <typename A>
1450 class UndefinedSymbolProxyAtom : public WriterAtom<A>
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"; }
1461 using WriterAtom<A>::fWriter;
1462 typedef typename A::P P;
1466 template <typename A>
1467 class BranchIslandAtom : public WriterAtom<A>
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; }
1482 using WriterAtom<A>::fWriter;
1483 enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1 };
1485 ObjectFile::Atom& fTarget;
1486 ObjectFile::Atom& fFinalTarget;
1487 uint32_t fFinalTargetOffset;
1488 IslandKind fIslandKind;
1491 template <typename A>
1492 class StubAtom : public WriterAtom<A>
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; }
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 };
1513 ObjectFile::Atom& fTarget;
1514 std::vector<ObjectFile::Reference*> fReferences;
1517 uint32_t fSortingOrdinal;
1521 template <typename A>
1522 class FastStubHelperHelperAtom : public WriterAtom<A>
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; }
1537 using WriterAtom<A>::fWriter;
1538 std::vector<ObjectFile::Reference*> fReferences;
1541 template <typename A>
1542 class HybridStubHelperHelperAtom : public WriterAtom<A>
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; }
1557 using WriterAtom<A>::fWriter;
1558 std::vector<ObjectFile::Reference*> fReferences;
1561 template <typename A>
1562 class StubHelperAtom : public WriterAtom<A>
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);
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; }
1581 static const char* stubName(const char* importName);
1582 using WriterAtom<A>::fWriter;
1584 ObjectFile::Atom& fTarget;
1585 LazyPointerAtom<A>& fLazyPointerAtom;
1586 std::vector<ObjectFile::Reference*> fReferences;
1589 template <typename A>
1590 class ClassicStubHelperAtom : public StubHelperAtom<A>
1593 ClassicStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1594 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1596 virtual uint64_t getSize() const;
1597 virtual void copyRawContent(uint8_t buffer[]) const;
1601 template <typename A>
1602 class HybridStubHelperAtom : public StubHelperAtom<A>
1605 HybridStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1606 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1608 virtual uint64_t getSize() const;
1609 virtual void copyRawContent(uint8_t buffer[]) const;
1610 static class HybridStubHelperHelperAtom<A>* fgHelperHelperAtom;
1612 template <typename A> class HybridStubHelperHelperAtom<A>* HybridStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1614 template <typename A>
1615 class FastStubHelperAtom : public StubHelperAtom<A>
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;
1624 template <typename A> FastStubHelperHelperAtom<A>* FastStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1628 template <typename A>
1629 class LazyPointerAtom : public WriterAtom<A>
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; }
1647 using WriterAtom<A>::fWriter;
1648 static const char* lazyPointerName(const char* importName);
1650 ObjectFile::Atom& fTarget;
1651 ObjectFile::Atom& fExternalTarget;
1652 std::vector<ObjectFile::Reference*> fReferences;
1655 uint32_t fLazyBindingOffset;
1656 uint32_t fSortingOrdinal;
1660 template <typename A>
1661 class NonLazyPointerAtom : public WriterAtom<A>
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; }
1678 using WriterAtom<A>::fWriter;
1679 static const char* nonlazyPointerName(const char* importName);
1681 ObjectFile::Atom* fTarget;
1682 std::vector<ObjectFile::Reference*> fReferences;
1683 uint32_t fSortingOrdinal;
1687 template <typename A>
1688 class ObjCInfoAtom : public WriterAtom<A>
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;
1699 Segment& getInfoSegment() const;
1700 uint32_t fContent[2];
1704 template <typename A>
1705 class WriterReference : public ObjectFile::Reference
1708 typedef typename A::ReferenceKinds Kinds;
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) {}
1718 virtual ~WriterReference() {}
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 = ⌖ fTargetOffset = offset; }
1730 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ }
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; }
1738 uint32_t fFixUpOffsetInSrc;
1739 ObjectFile::Atom* fTarget;
1740 const char* fTargetName;
1741 uint32_t fTargetOffset;
1742 ObjectFile::Atom* fFromTarget;
1743 uint32_t fFromTargetOffset;
1747 template <typename A>
1748 const char* StubHelperAtom<A>::stubName(const char* name)
1751 asprintf(&buf, "%s$stubHelper", name);
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)
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));
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));
1775 uint64_t ClassicStubHelperAtom<x86_64>::getSize() const
1781 void ClassicStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1783 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1790 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1799 FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(Writer<x86_64>& writer)
1800 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
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));
1807 uint64_t FastStubHelperHelperAtom<x86_64>::getSize() const
1813 void FastStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1815 buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
1822 buffer[7] = 0x41; // pushq %r11
1824 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1830 buffer[15] = 0x90; // nop
1835 HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(Writer<x86_64>& writer)
1836 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
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));
1847 uint64_t HybridStubHelperHelperAtom<x86_64>::getSize() const
1853 void HybridStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1855 buffer[0] = 0x48; // cmpl $0x00,_fast_lazy_bind
1863 buffer[8] = 0x74; // je 16
1865 buffer[10] = 0x4C; // leaq imageCache(%rip),%r11
1872 buffer[17] = 0x41; // pushq %r11
1874 buffer[19] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1880 buffer[25] = 0x48; // addq $8,%rsp
1884 buffer[29] = 0xE9; // jmp dyld_stub_binding_helper
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)
1897 if ( fgHelperHelperAtom == NULL ) {
1898 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(fWriter);
1899 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
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));
1906 uint64_t HybridStubHelperAtom<x86_64>::getSize() const
1912 void HybridStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1914 buffer[0] = 0x68; // pushq $lazy-info-offset
1919 buffer[5] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1926 buffer[12] = 0xE9; // jmp helper-helper
1931 buffer[17] = 0x90; // nop
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.
1936 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1937 memcpy(&buffer[1], &offset, 4);
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)
1945 if ( fgHelperHelperAtom == NULL ) {
1946 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(fWriter);
1947 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1949 fReferences.push_back(new WriterReference<x86_64>(6, x86_64::kPCRel32, fgHelperHelperAtom));
1953 uint64_t FastStubHelperAtom<x86_64>::getSize() const
1959 void FastStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1961 buffer[0] = 0x68; // pushq $lazy-info-offset
1966 buffer[5] = 0xE9; // jmp helperhelper
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.
1975 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1976 memcpy(&buffer[1], &offset, 4);
1980 FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(Writer<x86>& writer)
1981 : WriterAtom<x86>(writer, Segment::fgTextSegment)
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));
1988 uint64_t FastStubHelperHelperAtom<x86>::getSize() const
1994 void FastStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1996 buffer[0] = 0x68; // pushl $dyld_ImageLoaderCache
2001 buffer[5] = 0xFF; // jmp *_fast_lazy_bind
2007 buffer[11] = 0x90; // nop
2012 FastStubHelperHelperAtom<arm>::FastStubHelperHelperAtom(Writer<arm>& writer)
2013 : WriterAtom<arm>(writer, Segment::fgTextSegment)
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));
2020 uint64_t FastStubHelperHelperAtom<arm>::getSize() const
2026 void FastStubHelperHelperAtom<arm>::copyRawContent(uint8_t buffer[]) const
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)
2043 ObjectFile::Alignment StubHelperAtom<arm>::getAlignment() const { return ObjectFile::Alignment(2); }
2046 FastStubHelperAtom<arm>::FastStubHelperAtom(Writer<arm>& writer, ObjectFile::Atom& target,
2047 class LazyPointerAtom<arm>& lazyPointer, bool forLazyDylib)
2048 : StubHelperAtom<arm>(writer, target, lazyPointer, forLazyDylib)
2050 if ( fgHelperHelperAtom == NULL ) {
2051 fgHelperHelperAtom = new FastStubHelperHelperAtom<arm>::FastStubHelperHelperAtom(fWriter);
2052 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2054 fReferences.push_back(new WriterReference<arm>(4, arm::kBranch24, fgHelperHelperAtom));
2058 uint64_t FastStubHelperAtom<arm>::getSize() const
2064 void FastStubHelperAtom<arm>::copyRawContent(uint8_t buffer[]) const
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());
2075 HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(Writer<x86>& writer)
2076 : WriterAtom<x86>(writer, Segment::fgTextSegment)
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));
2087 uint64_t HybridStubHelperHelperAtom<x86>::getSize() const
2094 void HybridStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2096 buffer[0] = 0x83; // cmpl $0x00,_fast_lazy_bind
2103 buffer[7] = 0x75; // jne 22
2105 buffer[9] = 0x89; // %eax,4(%esp)
2109 buffer[13] = 0x58; // popl %eax
2110 buffer[14] = 0x87; // xchgl (%esp),%eax
2113 buffer[17] = 0xE9; // jmpl dyld_stub_binding_helper
2118 buffer[22] = 0x83; // addl $0x04,%esp
2121 buffer[25] = 0x68; // pushl imageloadercahce
2126 buffer[30] = 0xFF; // jmp *_fast_lazy_bind(%rip)
2136 ClassicStubHelperAtom<x86>::ClassicStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2137 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2138 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
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));
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));
2154 uint64_t ClassicStubHelperAtom<x86>::getSize() const
2160 void ClassicStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2162 buffer[0] = 0x68; // pushl $foo$lazy_ptr
2167 buffer[5] = 0xE9; // jmp helperhelper
2175 HybridStubHelperAtom<x86>::HybridStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2176 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2177 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2179 if ( fgHelperHelperAtom == NULL ) {
2180 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(fWriter);
2181 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2183 fReferences.push_back(new WriterReference<x86>(6, x86::kAbsolute32, &fLazyPointerAtom));
2184 fReferences.push_back(new WriterReference<x86>(11, x86::kPCRel32, fgHelperHelperAtom));
2189 uint64_t HybridStubHelperAtom<x86>::getSize() const
2195 void HybridStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2197 buffer[0] = 0x68; // pushl $lazy-info-offset
2202 buffer[5] = 0x68; // pushl $foo$lazy_ptr
2207 buffer[10] = 0xE9; // jmp dyld_hybrid_stub_binding_helper
2212 buffer[15] = 0x90; // nop
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.
2217 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2218 memcpy(&buffer[1], &offset, 4);
2223 FastStubHelperAtom<x86>::FastStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2224 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2225 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2227 if ( fgHelperHelperAtom == NULL ) {
2228 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(fWriter);
2229 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2231 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fgHelperHelperAtom));
2236 uint64_t FastStubHelperAtom<x86>::getSize() const
2242 void FastStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2244 buffer[0] = 0x68; // pushl $lazy-info-offset
2249 buffer[5] = 0xE9; // jmp helperhelper
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.
2258 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2259 memcpy(&buffer[1], &offset, 4);
2262 template <typename A>
2263 const char* LazyPointerAtom<A>::getSectionName() const
2266 return "__lazy_symbol";
2267 else if ( fForLazyDylib )
2268 return "__ld_symbol_ptr";
2270 return "__la_symbol_ptr";
2273 // specialize lazy pointer for x86_64 to initially pointer to stub helper
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)
2280 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2282 writer.fAllSynthesizedLazyPointers.push_back(this);
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);
2291 helper = new HybridStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2293 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2296 helper = new FastStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2300 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2302 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
2306 // specialize lazy pointer for x86 to initially pointer to stub helper
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)
2313 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2315 writer.fAllSynthesizedLazyPointers.push_back(this);
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);
2324 helper = new HybridStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2327 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2330 helper = new FastStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2334 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2336 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, helper));
2339 // specialize lazy pointer for arm to initially pointer to stub helper
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)
2346 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2348 writer.fAllSynthesizedLazyPointers.push_back(this);
2350 // The one instruction stubs must be close to the lazy pointers
2351 if ( stub.fKind == StubAtom<arm>::kStubShort )
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;
2360 else if ( writer.fOptions.makeCompressedDyldInfo() ) {
2361 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2364 helper = new FastStubHelperAtom<arm>(writer, target, *this, forLazyDylib);
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;
2371 fReferences.push_back(new WriterReference<arm>(0, arm::kPointer, helper));
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)
2380 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2382 writer.fAllSynthesizedLazyPointers.push_back(this);
2384 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2389 template <typename A>
2390 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
2393 asprintf(&buf, "%s$lazy_pointer", name);
2397 template <typename A>
2398 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2400 bzero(buffer, getSize());
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)
2408 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2409 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2412 template <typename A>
2413 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer)
2414 : WriterAtom<A>(writer, Segment::fgDataSegment), fName("none"), fTarget(NULL)
2416 writer.fAllSynthesizedNonLazyPointers.push_back(this);
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)
2423 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2424 fReferences.push_back(new WriterReference<A>(0, A::kPointer, targetName));
2427 template <typename A>
2428 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
2431 asprintf(&buf, "%s$non_lazy_pointer", name);
2435 template <typename A>
2436 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2438 bzero(buffer, getSize());
2445 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
2451 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
2457 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
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)
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);
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);
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);
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));
2494 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
2495 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
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)
2504 writer.fAllSynthesizedStubs.push_back(this);
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);
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);
2517 if ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) )
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));
2527 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
2528 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
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)
2537 if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) {
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);
2546 if ( &target == NULL )
2547 asprintf((char**)&fName, "cache-line-crossing-stub %p", this);
2549 fName = stubName(target.getName());
2550 writer.fAllSynthesizedStubs.push_back(this);
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)
2560 writer.fAllSynthesizedStubs.push_back(this);
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));
2567 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2568 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
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.
2579 else if ( fWriter.fSlideable ) {
2585 LazyPointerAtom<arm>* lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
2588 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
2591 fReferences.push_back(new WriterReference<arm>(8, arm::kReadOnlyPointer, lp));
2594 fReferences.push_back(new WriterReference<arm>(0, arm::kPointerDiff12, lp, 0, this, 8));
2597 throw "internal error";
2603 template <typename A>
2604 const char* StubAtom<A>::stubName(const char* name)
2607 asprintf(&buf, "%s$stub", name);
2612 uint64_t StubAtom<ppc>::getSize() const
2615 return ( (fKind == kStubPIC) ? 32 : 16 );
2619 uint64_t StubAtom<ppc64>::getSize() const
2621 return ( (fKind == kStubPIC) ? 32 : 16 );
2626 uint64_t StubAtom<arm>::getSize() const
2636 throw "internal error";
2641 uint64_t StubAtom<x86>::getSize() const
2649 throw "internal error";
2654 uint64_t StubAtom<x86_64>::getSize() const
2660 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
2666 return 0; // special case x86 self-modifying stubs to be byte aligned
2668 throw "internal error";
2673 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
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
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
2694 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
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
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
2715 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
2719 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
2727 if ( fWriter.fOptions.prebind() ) {
2728 uint32_t address = this->getAddress();
2729 int32_t rel32 = 0 - (address+5);
2731 buffer[1] = rel32 & 0xFF;
2732 buffer[2] = (rel32 >> 8) & 0xFF;
2733 buffer[3] = (rel32 >> 16) & 0xFF;
2734 buffer[4] = (rel32 >> 24) & 0xFF;
2745 throw "internal error";
2750 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
2752 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
2761 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
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)
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
2776 OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000);// ldr pc, [pc, #foo$lazy_ptr]
2779 throw "internal error";
2783 // x86_64 stubs are 6 bytes
2785 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
2791 const char* StubAtom<ppc>::getSectionName() const
2793 return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1");
2797 const char* StubAtom<ppc64>::getSectionName() const
2799 return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1");
2803 const char* StubAtom<arm>::getSectionName() const
2807 return "__picsymbolstub4";
2809 return "__symbol_stub4";
2811 return "__symbolstub1";
2813 throw "internal error";
2818 const char* StubAtom<x86>::getSectionName() const
2822 return "__symbol_stub";
2824 return "__jump_table";
2826 throw "internal error";
2833 struct AtomByNameSorter
2835 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2837 return (strcmp(left->getName(), right->getName()) < 0);
2841 template <typename P>
2842 struct ExternalRelocSorter
2844 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
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());
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)
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));
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));
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));
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));
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));
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));
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));
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));
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));
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);
3010 case Options::kDynamicLibrary:
3011 case Options::kDynamicBundle:
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() );
3019 if ( dylibInfo.options.fReExport ) {
3020 hasReExports = true;
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;
3031 if ( dylibInfo.options.fWeakImport ) {
3032 fForcedWeakImportReaders.insert(dylibInfo.reader);
3035 if ( dylibInfo.options.fBundleLoader ) {
3036 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
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;
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;
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);
3085 if ( isFrameworkReExport ) {
3086 // needs a LC_SUB_UMBRELLA command
3087 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
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, '.');
3097 len = dot - nameStart;
3098 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
3105 // add umbrella command if needed
3106 if ( fOptions.umbrellaName() != NULL ) {
3107 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
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));
3115 case Options::kStaticExecutable:
3116 case Options::kObjectFile:
3117 case Options::kDyld:
3118 case Options::kPreload:
3119 case Options::kKextBundle:
3122 fNoReExportedDylibs = !hasReExports;
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));
3129 // set up fSlideable
3130 switch ( fOptions.outputKind() ) {
3131 case Options::kObjectFile:
3132 case Options::kStaticExecutable:
3135 case Options::kDynamicExecutable:
3136 fSlideable = fOptions.positionIndependentExecutable();
3138 case Options::kDyld:
3139 case Options::kDynamicLibrary:
3140 case Options::kDynamicBundle:
3141 case Options::kPreload:
3142 case Options::kKextBundle:
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());
3153 template <typename A>
3154 Writer<A>::~Writer()
3156 if ( fFilePath != NULL )
3157 free((void*)fFilePath);
3158 if ( fSymbolTable != NULL )
3159 delete [] fSymbolTable;
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; }
3168 template <typename A>
3169 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
3171 if ( fOptions.outputKind() == Options::kKextBundle ) {
3172 return new UndefinedSymbolProxyAtom<A>(*this, name);
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) )
3181 return new UndefinedSymbolProxyAtom<A>(*this, name);
3183 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
3184 return new UndefinedSymbolProxyAtom<A>(*this, name);
3189 template <typename A>
3190 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
3192 // flat namespace images use zero for all ordinals
3193 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3196 // is an UndefinedSymbolProxyAtom
3198 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3199 return DYNAMIC_LOOKUP_ORDINAL;
3201 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
3202 if ( pos != fLibraryToOrdinal.end() )
3205 throw "can't find ordinal for imported symbol";
3208 template <typename A>
3209 bool Writer<A>::targetRequiresWeakBinding(const ObjectFile::Atom& target)
3211 switch ( target.getDefinitionKind() ) {
3212 case ObjectFile::Atom::kExternalWeakDefinition:
3213 case ObjectFile::Atom::kWeakDefinition:
3215 case ObjectFile::Atom::kExternalDefinition:
3216 case ObjectFile::Atom::kAbsoluteSymbol:
3217 case ObjectFile::Atom::kRegularDefinition:
3218 case ObjectFile::Atom::kTentativeDefinition:
3224 template <typename A>
3225 int Writer<A>::compressedOrdinalForImortedAtom(ObjectFile::Atom* target)
3227 // flat namespace images use zero for all ordinals
3228 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3229 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3231 // is an UndefinedSymbolProxyAtom
3232 ObjectFile::Reader* lib = target->getFile();
3234 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3235 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
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;
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;
3257 throw "can't find ordinal for imported symbol";
3261 template <typename A>
3262 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
3264 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
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)
3276 fDyldClassicHelperAtom = dyldClassicHelperAtom;
3277 fDyldCompressedHelperAtom = dyldCompressedHelperAtom;
3278 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
3279 fBiggerThanTwoGigs = biggerThanTwoGigs;
3280 fDylibSymbolCountUpperBound = dylibSymbolCount;
3282 // create inter-library stubs
3283 synthesizeStubs(existingAtoms, newAtoms);
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)
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;
3305 // Set for create UUID
3307 fUUIDAtom->generate();
3309 // remove uneeded dylib load commands
3310 optimizeDylibReferences();
3312 // check for mdynamic-no-pic codegen
3313 scanForAbsoluteReferences();
3315 // create table of unwind info
3316 synthesizeUnwindInfoTable();
3318 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
3319 partitionIntoSections();
3321 // segment load command can now be sized and padding can be set
3322 adjustLoadCommandsAndPadding();
3324 // assign each section a file offset
3325 assignFileOffsets();
3327 // if need to add branch islands, reassign file offsets
3328 if ( addBranchIslands() )
3329 assignFileOffsets();
3331 // now that addresses are assigned, create unwind info
3332 if ( fUnwindInfoAtom != NULL ) {
3333 fUnwindInfoAtom->generate();
3335 adjustLoadCommandsAndPadding();
3336 assignFileOffsets();
3339 // make spit-seg info now that all atoms exist
3340 createSplitSegContent();
3342 // build symbol table and relocations
3345 // write map file if requested
3349 return writeAtoms();
3351 // clean up if any errors
3352 (void)unlink(fFilePath);
3357 template <typename A>
3358 void Writer<A>::buildLinkEdit()
3360 this->collectExportedAndImportedAndLocalAtoms();
3361 this->buildSymbolTable();
3362 this->buildFixups();
3363 this->adjustLinkEditSections();
3368 template <typename A>
3369 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
3371 return atom->getAddress();
3372 // SectionInfo* info = (SectionInfo*)atom->getSection();
3373 // return info->getBaseAddress() + atom->getSectionOffset();
3377 bool Writer<x86_64>::stringsNeedLabelsInObjects()
3382 template <typename A>
3383 bool Writer<A>::stringsNeedLabelsInObjects()
3388 template <typename A>
3389 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
3391 static unsigned int counter = 0;
3393 if ( stringsNeedLabelsInObjects()
3394 && (atom->getContentType() == ObjectFile::Atom::kCStringType)
3395 && (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) )
3396 asprintf((char**)&name, "LC%u", counter++);
3398 name = atom->getName();
3400 return atom->getName();
3403 template <typename A>
3404 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3407 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
3410 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
3411 entry->set_n_type(N_EXT | N_ABS);
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);
3421 // set n_sect (section number of implementation )
3422 uint8_t sectionIndex = atom->getSection()->getIndex();
3423 entry->set_n_sect(sectionIndex);
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);
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 ) {
3441 fHasWeakExports = true;
3443 entry->set_n_desc(desc);
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());
3449 entry->set_n_value(this->getAtomLoadAddress(atom));
3452 template <typename A>
3453 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3456 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
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);
3464 entry->set_n_type(N_UNDF | N_EXT);
3467 if ( fOptions.prebind() )
3468 entry->set_n_type(N_PBUD | N_EXT);
3470 entry->set_n_type(N_UNDF | N_EXT);
3474 entry->set_n_sect(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;
3483 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
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);
3489 catch (const char* msg) {
3490 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
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);
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;
3506 // set weak_import attribute
3507 if ( fWeakImportMap[atom] )
3509 entry->set_n_desc(desc);
3511 // set n_value, zero for import proxy and size for tentative definition
3512 entry->set_n_value(atom->getSize());
3516 template <typename A>
3517 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3520 const char* symbolName = this->symbolTableName(atom);
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
3528 sprintf(anonName, "l%u", fAnonNameIndex++);
3529 symbolName = anonName;
3532 entry->set_n_strx(this->fStringsAtom->add(symbolName));
3535 uint8_t type = N_SECT;
3536 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3538 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
3540 entry->set_n_type(type);
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 )
3549 entry->set_n_sect(sectIndex);
3553 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3554 desc |= N_NO_DEAD_STRIP;
3555 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
3557 if ( atom->isThumb() )
3558 desc |= N_ARM_THUMB_DEF;
3559 entry->set_n_desc(desc);
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());
3565 entry->set_n_value(this->getAtomLoadAddress(atom));
3569 template <typename A>
3570 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3572 macho_nlist<P> entry;
3575 entry.set_n_strx(fStringsAtom->add(name));
3578 entry.set_n_type(N_SECT);
3580 // set n_sect (section number of implementation )
3581 entry.set_n_sect(atom.getSection()->getIndex());
3584 entry.set_n_desc(0);
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);
3590 fLocalExtraLabels.push_back(entry);
3595 template <typename A>
3596 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3598 macho_nlist<P> entry;
3601 entry.set_n_strx(fStringsAtom->add(name));
3604 entry.set_n_type(N_SECT|N_EXT);
3606 // set n_sect (section number of implementation )
3607 entry.set_n_sect(atom.getSection()->getIndex());
3610 entry.set_n_desc(0);
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);
3616 fGlobalExtraLabels.push_back(entry);
3619 template <typename A>
3620 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
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);
3628 else if ( &atoms == &fImportedAtoms ) {
3629 this->setImportNlist(atom, entry);
3632 this->setLocalNlist(atom, entry);
3637 template <typename A>
3638 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
3640 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
3641 fSymbolTable[startIndex++] = *it;
3645 template <typename A>
3646 struct NListNameSorter
3648 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
3650 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
3652 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
3655 StringsLinkEditAtom<A>* fStringPool;
3659 template <typename A>
3660 void Writer<A>::buildSymbolTable()
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();
3671 // allocate symbol table
3672 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
3673 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
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) );
3687 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
3688 addStabs(fSymbolTableStabsStartIndex);
3690 // set up module table
3691 if ( fModuleInfoAtom != NULL )
3692 fModuleInfoAtom->setName();
3694 // create atom to symbol index map
3697 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
3698 fAtomToSymbolIndex[*it] = i + fSymbolTableImportStartIndex;
3703 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
3704 fAtomToSymbolIndex[*it] = i + fSymbolTableLocalStartIndex;
3709 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
3710 fAtomToSymbolIndex[*it] = i + fSymbolTableExportStartIndex;
3718 template <typename A>
3719 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
3721 switch ( atom.getSymbolTableInclusion() ) {
3722 case ObjectFile::Atom::kSymbolTableNotIn:
3724 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3726 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3727 case ObjectFile::Atom::kSymbolTableIn:
3728 switch ( atom.getScope() ) {
3729 case ObjectFile::Atom::scopeGlobal:
3731 case ObjectFile::Atom::scopeLinkageUnit:
3732 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
3741 template <typename A>
3742 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
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);
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);
3765 case ObjectFile::Atom::kTentativeDefinition:
3766 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
3767 fImportedAtoms.push_back(atom);
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);
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);
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());
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());
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());
3824 template <typename A>
3825 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
3827 switch ( stab.type ) {
3829 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3830 // end of function N_FUN has size
3831 return stab.atom->getSize();
3834 // start of function N_FUN has address
3835 return getAtomLoadAddress(stab.atom);
3840 if ( stab.atom == NULL )
3841 // some weird assembly files have slines not associated with a function
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;
3849 // all these need address of atom
3850 return getAtomLoadAddress(stab.atom);;
3852 return stab.atom->getSize();
3854 if ( stab.atom == NULL ) {
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();
3863 // start of translation unit N_SO has address of end of first atom
3864 return getAtomLoadAddress(stab.atom);
3873 template <typename A>
3874 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
3876 switch (stab.type) {
3878 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
3879 return this->fStringsAtom->emptyString();
3882 // fall into uniquing case
3886 return this->fStringsAtom->addUnique(stab.string);
3889 if ( stab.string == NULL )
3891 else if ( stab.string[0] == '\0' )
3892 return this->fStringsAtom->emptyString();
3894 return this->fStringsAtom->add(stab.string);
3899 template <typename A>
3900 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
3902 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
3903 if ( stab.type == N_FUN )
3905 else if ( stab.atom != NULL )
3906 return stab.atom->getSection()->getIndex();
3911 template <typename A>
3912 void Writer<A>::addStabs(uint32_t startIndex)
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));
3927 template <typename A>
3928 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
3930 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fAtomToSymbolIndex.find(&atom);
3931 if ( pos != fAtomToSymbolIndex.end() )
3933 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
3938 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3940 switch ( target.getSymbolTableInclusion() ) {
3941 case ObjectFile::Atom::kSymbolTableNotIn:
3943 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3944 case ObjectFile::Atom::kSymbolTableIn:
3945 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3951 template <typename A>
3952 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3954 switch ( target.getDefinitionKind() ) {
3955 case ObjectFile::Atom::kRegularDefinition:
3956 case ObjectFile::Atom::kWeakDefinition:
3957 case ObjectFile::Atom::kAbsoluteSymbol:
3959 case ObjectFile::Atom::kTentativeDefinition:
3960 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
3963 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
3964 case ObjectFile::Atom::kExternalDefinition:
3965 case ObjectFile::Atom::kExternalWeakDefinition:
3966 return shouldExport(target);
3971 template <typename A>
3972 void Writer<A>::buildFixups()
3974 if ( fOptions.outputKind() == Options::kObjectFile ) {
3975 this->buildObjectFileFixups();
3978 if ( fOptions.keepRelocations() )
3979 this->buildObjectFileFixups();
3980 this->buildExecutableFixups();
3985 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
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();
3996 case x86_64::kNoFixUp:
3997 case x86_64::kGOTNoFixUp:
3998 case x86_64::kFollowOn:
3999 case x86_64::kGroupSubordinate:
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);
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);
4023 case x86_64::kPointerDiff32:
4024 case x86_64::kPointerDiff:
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);
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);
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);
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);
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);
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);
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);
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);
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);
4131 case x86_64::kPointerDiff24:
4132 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4134 case x86_64::kImageOffset32:
4135 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4137 case x86_64::kSectionOffset24:
4138 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
4140 case x86_64::kDtraceTypeReference:
4141 case x86_64::kDtraceProbe:
4142 // generates no relocs
4150 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4152 ObjectFile::Atom& target = ref->getTarget();
4153 bool isExtern = this->makesExternalRelocatableReference(target);
4154 uint32_t symbolIndex = 0;
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();
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());
4172 case x86::kFollowOn:
4173 case x86::kGroupSubordinate:
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());
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);
4196 fSectionRelocs.push_back(reloc1);
4199 case x86::kPointerDiff16:
4200 case x86::kPointerDiff:
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);
4212 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
4213 sreloc1->set_r_address(address);
4214 sreloc1->set_r_value(target.getAddress());
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());
4224 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4225 fSectionRelocs.push_back(reloc2);
4226 fSectionRelocs.push_back(reloc1);
4230 case x86::kPCRel32WeakImport:
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());
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);
4253 fSectionRelocs.push_back(reloc1);
4256 case x86::kPointerDiff24:
4257 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4259 case x86::kImageOffset32:
4260 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4262 case x86::kSectionOffset24:
4263 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
4265 case x86::kDtraceTypeReference:
4266 case x86::kDtraceProbe:
4267 // generates no relocs
4275 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4277 ObjectFile::Atom& target = ref->getTarget();
4278 bool isExtern = this->makesExternalRelocatableReference(target);
4279 uint32_t symbolIndex = 0;
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();
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());
4297 case arm::kFollowOn:
4298 case arm::kGroupSubordinate:
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());
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);
4321 fSectionRelocs.push_back(reloc1);
4324 case arm::kPointerDiff:
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);
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());
4343 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4344 fSectionRelocs.push_back(reloc2);
4345 fSectionRelocs.push_back(reloc1);
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());
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);
4370 fSectionRelocs.push_back(reloc1);
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());
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);
4392 fSectionRelocs.push_back(reloc1);
4395 case arm::kPointerDiff12:
4396 throw "internal error. no reloc for 12-bit pointer diffs";
4398 case arm::kDtraceTypeReference:
4399 case arm::kDtraceProbe:
4400 // generates no relocs
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; }
4414 uint8_t Writer<ppc>::getRelocPointerSize()
4420 uint8_t Writer<ppc64>::getRelocPointerSize()
4426 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4428 return addObjectRelocs_powerpc(atom, ref);
4432 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4434 return addObjectRelocs_powerpc(atom, ref);
4438 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
4439 // they use a common addObjectRelocs_powerpc() method.
4441 template <typename A>
4442 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4444 ObjectFile::Atom& target = ref->getTarget();
4445 bool isExtern = this->makesExternalRelocatableReference(target);
4446 uint32_t symbolIndex = 0;
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();
4460 case A::kGroupSubordinate:
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());
4475 reloc1.set_r_address(address);
4477 reloc1.set_r_symbolnum(symbolIndex);
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);
4485 fSectionRelocs.push_back(reloc1);
4488 case A::kPointerDiff16:
4489 case A::kPointerDiff32:
4490 case A::kPointerDiff64:
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);
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);
4512 case A::kBranch24WeakImport:
4514 case A::kDtraceProbeSite:
4515 case A::kDtraceIsEnabledSite:
4516 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4517 reloc1.set_r_address(address);
4519 reloc1.set_r_symbolnum(symbolIndex);
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);
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());
4535 fSectionRelocs.push_back(reloc1);
4539 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4540 reloc1.set_r_address(address);
4542 reloc1.set_r_symbolnum(symbolIndex);
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);
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());
4558 fSectionRelocs.push_back(reloc1);
4561 case A::kPICBaseLow16:
4562 case A::kPICBaseLow14:
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);
4583 case A::kPICBaseHigh16:
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);
4607 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4608 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4609 reloc1.set_r_address(address);
4611 reloc1.set_r_symbolnum(symbolIndex);
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);
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());
4628 reloc2.set_r_address(ref->getTargetOffset() >> 16);
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);
4643 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4644 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4645 reloc1.set_r_address(address);
4647 reloc1.set_r_symbolnum(symbolIndex);
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);
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());
4664 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
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);
4677 case A::kAbsHigh16AddLow:
4679 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4680 uint32_t overflow = 0;
4681 if ( (toAddr & 0x00008000) != 0 )
4683 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4684 reloc1.set_r_address(address);
4686 reloc1.set_r_symbolnum(symbolIndex);
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);
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());
4703 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
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);
4716 case A::kDtraceTypeReference:
4717 case A::kDtraceProbe:
4718 // generates no relocs
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.
4732 template <typename A>
4733 bool Writer<A>::indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const
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 )
4740 // must use INDIRECT_SYMBOL_LOCAL if there is an addend
4741 if ( ref->getTargetOffset() != 0 )
4744 // don't use INDIRECT_SYMBOL_LOCAL for external symbols
4745 return ! this->shouldExport(ref->getTarget());
4749 template <typename A>
4750 void Writer<A>::buildObjectFileFixups()
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);
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;
4792 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
4795 // should never get here, fAllLazyPointers not used in generated .o files
4796 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
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());
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);
4823 else if ( curSection->fAllStubs ) {
4824 relocIndex += this->addObjectRelocs(atom, ref);
4827 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
4828 relocIndex += this->addObjectRelocs(atom, ref);
4832 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
4837 // reverse the relocs
4838 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
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;
4855 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
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());
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());
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());
4885 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4887 switch ( ref.getKind() ) {
4888 case ppc::kAbsLow16:
4889 case ppc::kAbsLow14:
4890 case ppc::kAbsHigh16:
4891 case ppc::kAbsHigh16AddLow:
4900 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4902 switch ( ref.getKind() ) {
4903 case ppc::kAbsLow16:
4904 case ppc::kAbsLow14:
4905 case ppc::kAbsHigh16:
4906 case ppc::kAbsHigh16AddLow:
4914 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
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
4923 case ObjectFile::Atom::kExternalDefinition:
4924 case ObjectFile::Atom::kExternalWeakDefinition:
4925 // illegal until we support TEXT relocs
4927 case ObjectFile::Atom::kAbsoluteSymbol:
4928 // absolute symbbols only allowed in static executables
4929 return ( fOptions.outputKind() != Options::kStaticExecutable);
4936 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
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:
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:
4964 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4966 switch ( fOptions.outputKind()) {
4967 case Options::kStaticExecutable:
4968 case Options::kPreload:
4969 // all relocations allowed in static executables
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
4981 case ObjectFile::Atom::kExternalDefinition:
4982 case ObjectFile::Atom::kExternalWeakDefinition:
4983 // illegal until we support TEXT relocs
4985 case ObjectFile::Atom::kAbsoluteSymbol:
4986 // absolute symbbols only allowed in static executables
4994 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
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
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()));
5020 case ObjectFile::Atom::kExternalDefinition:
5021 case ObjectFile::Atom::kExternalWeakDefinition:
5022 case ObjectFile::Atom::kAbsoluteSymbol:
5030 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
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
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;
5064 case ppc::kAbsHigh16:
5065 case ppc::kAbsHigh16AddLow:
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;
5088 case ObjectFile::Atom::kExternalDefinition:
5089 case ObjectFile::Atom::kExternalWeakDefinition:
5090 case ObjectFile::Atom::kAbsoluteSymbol:
5097 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
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
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()));
5123 case ObjectFile::Atom::kExternalDefinition:
5124 case ObjectFile::Atom::kExternalWeakDefinition:
5125 case ObjectFile::Atom::kAbsoluteSymbol:
5134 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5136 // text relocs not supported (usually never needed because of RIP addressing)
5141 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5143 // text relocs not supported
5148 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
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:
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;
5170 case ObjectFile::Atom::kAbsoluteSymbol:
5178 bool Writer<x86_64>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
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:
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;
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;
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;
5238 template <typename A>
5239 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5247 template <typename A>
5248 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
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;
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;
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;
5283 case ObjectFile::Atom::kExternalDefinition:
5284 case ObjectFile::Atom::kExternalWeakDefinition:
5285 return kRelocExternal;
5286 case ObjectFile::Atom::kAbsoluteSymbol:
5292 template <typename A>
5293 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
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;
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());
5313 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
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
5321 bool badFor10_4 = false;
5322 if ( fWritableSegmentPastFirst4GB ) {
5323 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
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());
5332 result = address - fSegmentInfos[0]->fBaseAddress;
5333 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
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());
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; }
5350 template <typename A>
5351 void Writer<A>::buildExecutableFixups()
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();
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);
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());
5396 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
5397 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5398 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
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));
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()));
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));
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));
5460 if ( curSection->fAllNonLazyPointers && fOptions.makeCompressedDyldInfo() ) {
5461 if ( pointerTarget != NULL ) {
5462 switch ( this->relocationNeededInFinalLinkedImage(*pointerTarget) ) {
5464 // no rebase or binding info needed
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()));
5472 case kRelocExternal:
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));
5487 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
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));
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));
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());
5513 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
5514 atom->getDisplayName(), atom->getFile()->getPath());
5517 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
5521 case kRelocInternal:
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) )
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()));
5541 case kRelocExternal:
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));
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));
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));
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));
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
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
5597 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
5598 // relocs added to fExternalRelocs
5601 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
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());
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);
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();
5640 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5642 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
5643 case ppc::kPICBaseHigh16:
5644 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5646 case ppc::kPointerDiff32:
5647 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5649 case ppc::kPointerDiff64:
5650 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5653 case ppc::kGroupSubordinate:
5655 case ppc::kPointerWeakImport:
5656 case ppc::kPICBaseLow16:
5657 case ppc::kPICBaseLow14:
5661 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5662 fSplitCodeToDataContentAtom->setCantEncode();
5667 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5669 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
5670 case ppc64::kPICBaseHigh16:
5671 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5673 case ppc64::kPointerDiff32:
5674 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5676 case ppc64::kPointerDiff64:
5677 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5679 case ppc64::kNoFixUp:
5680 case ppc64::kGroupSubordinate:
5681 case ppc64::kPointer:
5682 case ppc64::kPointerWeakImport:
5683 case ppc64::kPICBaseLow16:
5684 case ppc64::kPICBaseLow14:
5688 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5689 fSplitCodeToDataContentAtom->setCantEncode();
5694 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
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());
5702 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5705 case x86::kGroupSubordinate:
5707 case x86::kPointerWeakImport:
5711 case x86::kPCRel32WeakImport:
5712 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
5713 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
5714 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5717 // fall into warning case
5719 if ( fOptions.makeCompressedDyldInfo() && (ref->getKind() == x86::kAbsolute32) ) {
5720 // will be encoded in rebase info
5723 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
5724 fSplitCodeToDataContentAtom->setCantEncode();
5730 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
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());
5745 case x86_64::kPointerDiff:
5746 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5748 case x86_64::kNoFixUp:
5749 case x86_64::kGroupSubordinate:
5750 case x86_64::kPointer:
5751 case x86_64::kGOTNoFixUp:
5755 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
5756 fSplitCodeToDataContentAtom->setCantEncode();
5761 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5763 switch ( (arm::ReferenceKinds)ref->getKind() ) {
5764 case arm::kPointerDiff:
5765 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5768 case arm::kGroupSubordinate:
5770 case arm::kPointerWeakImport:
5771 case arm::kReadOnlyPointer:
5775 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
5776 fSplitCodeToDataContentAtom->setCantEncode();
5780 template <typename A>
5781 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
5783 switch ( to.getDefinitionKind() ) {
5784 case ObjectFile::Atom::kExternalDefinition:
5785 case ObjectFile::Atom::kExternalWeakDefinition:
5786 case ObjectFile::Atom::kAbsoluteSymbol:
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()) );
5795 throw "ld64 internal error";
5800 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
5803 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5804 for (uint32_t p=from; p < to; p += 4)
5805 ::pwrite(fd, &ppcNop, 4, p);
5809 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5812 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5813 for (uint32_t p=from; p < to; p += 4)
5814 ::pwrite(fd, &ppcNop, 4, p);
5818 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
5820 uint8_t x86Nop = 0x90;
5821 for (uint32_t p=from; p < to; ++p)
5822 ::pwrite(fd, &x86Nop, 1, p);
5826 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5828 uint8_t x86Nop = 0x90;
5829 for (uint32_t p=from; p < to; ++p)
5830 ::pwrite(fd, &x86Nop, 1, p);
5834 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
5836 // FIXME: need thumb nop?
5838 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
5839 for (uint32_t p=from; p < to; p += 4)
5840 ::pwrite(fd, &armNop, 4, p);
5844 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
5846 for (uint8_t* p=from; p < to; p += 4)
5847 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5851 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
5853 for (uint8_t* p=from; p < to; p += 4)
5854 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5858 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
5860 for (uint8_t* p=from; p < to; ++p)
5865 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
5867 for (uint8_t* p=from; p < to; ++p)
5872 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
5874 // fixme: need thumb nop?
5875 for (uint8_t* p=from; p < to; p += 4)
5876 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
5879 static const char* stringName(const char* str)
5881 if ( strncmp(str, "cstring=", 8) == 0) {
5882 static char buffer[1024];
5885 for(const char*s = &str[8]; *s != '\0'; ++s) {
5899 if ( t > &buffer[1020] ) {
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"; }
5924 template <typename A>
5925 void Writer<A>::writeMap()
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());
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]);
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;
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++;
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);
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());
6005 warning("could not write map file: %s\n", fOptions.generatedMapPath());
6010 static const char* sCleanupFile = NULL;
6011 static void cleanup(int sig)
6013 ::signal(sig, SIG_DFL);
6014 if ( sCleanupFile != NULL ) {
6015 ::unlink(sCleanupFile);
6017 if ( sig == SIGINT )
6022 template <typename A>
6023 uint64_t Writer<A>::writeAtoms()
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);
6029 int permissions = 0777;
6030 if ( fOptions.outputKind() == Options::kObjectFile )
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);
6037 // try to allocate buffer for entire output file content
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);
6047 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
6048 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
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);
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);
6078 // fill gaps with no-ops
6080 writeNoOps(fd, end, fileOffset);
6082 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
6084 else if ( streaming ) {
6086 if ( (fileOffset-end) == 4 ) {
6088 ::pwrite(fd, &zero, 4, end);
6091 uint8_t zero = 0x00;
6092 for (uint32_t p=end; p < fileOffset; ++p)
6093 ::pwrite(fd, &zero, 1, p);
6097 uint64_t atomSize = atom->getSize();
6099 if ( atomSize > fLargestAtomSize )
6100 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%llX > 0x%X",
6101 atom->getDisplayName(), atomSize, fLargestAtomSize);
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);
6108 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
6109 end = fileOffset+atomSize;
6111 atom->copyRawContent(buffer);
6112 // apply any fix-ups
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 ) {
6119 // skip fix-ups for undefined targets
6120 if ( &(ref->getTarget()) != NULL )
6121 this->fixUpReferenceRelocatable(ref, atom, buffer);
6124 // producing final linked image
6125 this->fixUpReferenceFinal(ref, atom, buffer);
6129 catch (const char* msg) {
6130 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
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());
6136 ::pwrite(fd, buffer, atomSize, fileOffset);
6139 if ( (fileOffset + atomSize) > size )
6140 size = fileOffset + atomSize;
6148 // update content based UUID
6149 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
6150 uint8_t digest[CC_MD5_DIGEST_LENGTH];
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);
6160 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
6161 CC_MD5_Update(&md5State, md5Buffer, len);
6162 CC_MD5_Final(digest, &md5State);
6166 // if malloc fails, fall back to random uuid
6167 ::uuid_generate_random(digest);
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);
6175 // if output file fit in memory, just genrate an md5 hash in memory
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);
6183 CC_MD5(wholeBuffer, size, digest);
6185 fUUIDAtom->setContent(digest);
6186 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
6187 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
6192 if ( sCleanupFile != NULL )
6193 ::unlink(sCleanupFile);
6199 delete [] atomBuffer;
6201 // restore default signal handlers
6202 sCleanupFile = NULL;
6203 ::signal(SIGINT, SIG_DFL);
6204 ::signal(SIGBUS, SIG_DFL);
6205 ::signal(SIGSEGV, SIG_DFL);
6208 // write whole output file in one chunk
6209 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
6211 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
6212 ::pwrite(fd, wholeBuffer, size, 0);
6214 delete [] wholeBuffer;
6221 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6223 int64_t displacement;
6225 uint32_t instruction;
6226 uint32_t newInstruction;
6227 uint64_t targetAddr = 0;
6230 uint32_t opcode = 0;
6231 bool relocateableExternal = false;
6236 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6237 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6238 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
6241 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6242 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6244 case arm::kFollowOn:
6245 case arm::kGroupSubordinate:
6248 case arm::kPointerWeakImport:
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);
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) )
6267 LittleEndian::set32(*fixUp, targetAddr);
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());
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) )
6285 LittleEndian::set32(*fixUp, targetAddr);
6287 case ObjectFile::Atom::kAbsoluteSymbol:
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() )
6296 LittleEndian::set32(*fixUp, targetAddr);
6299 // external relocation ==> pointer contains addend
6300 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6304 // pointer contains target address
6305 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6307 LittleEndian::set32(*fixUp, targetAddr);
6310 case arm::kPointerDiff:
6311 LittleEndian::set32(*fixUp,
6312 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6314 case arm::kReadOnlyPointer:
6315 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
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);
6324 case ObjectFile::Atom::kExternalDefinition:
6325 case ObjectFile::Atom::kExternalWeakDefinition:
6326 // external relocation ==> pointer contains addend
6327 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6329 case ObjectFile::Atom::kAbsoluteSymbol:
6330 // pointer contains target address
6331 LittleEndian::set32(*fixUp, targetAddr);
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;
6348 // The pc added will be +8 from the pc
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());
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;
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;
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());
6378 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6380 LittleEndian::set32(*fixUp, newInstruction);
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();
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
6395 if ( !targetIsThumb ) {
6396 targetAddr &= -3ULL;
6397 targetAddr |= (baseAddr & 2LL);
6399 displacement = targetAddr - baseAddr;
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());
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);
6425 if ( targetIsThumb )
6426 opcode = 0xD000F000; // keep bl
6428 opcode = 0xC000F000; // change to blx
6430 else if ( is_blx ) {
6431 if ( targetIsThumb )
6432 opcode = 0xD000F000; // change to bl
6434 opcode = 0xC000F000; // keep blx
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());
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);
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());
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;
6465 else if ( is_blx && targetIsThumb ) {
6466 opcode = 0xF800F000;
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());
6473 opcode = instruction & 0xF800F800;
6475 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6476 LittleEndian::set32(*fixUp, newInstruction);
6479 case arm::kDtraceProbeSite:
6480 if ( inAtom->isThumb() ) {
6481 // change 32-bit blx call site to two thumb NOPs
6482 LittleEndian::set32(*fixUp, 0x46C046C0);
6485 // change call site to a NOP
6486 LittleEndian::set32(*fixUp, 0xE1A00000);
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);
6495 // change call site to 'eor r0, r0, r0'
6496 LittleEndian::set32(*fixUp, 0xE0200000);
6499 case arm::kDtraceTypeReference:
6500 case arm::kDtraceProbe:
6501 // nothing to fix up
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());
6508 instruction = LittleEndian::get32(*fixUp);
6509 if ( displacement >= 0 ) {
6510 instruction &= 0xFFFFF000;
6511 instruction |= ((uint32_t)displacement & 0xFFF);
6514 instruction &= 0xFF7FF000;
6515 instruction |= ((uint32_t)(-displacement) & 0xFFF);
6517 LittleEndian::set32(*fixUp, instruction);
6523 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6525 int64_t displacement;
6526 uint32_t instruction;
6527 uint32_t newInstruction;
6528 uint64_t targetAddr = 0;
6532 uint32_t opcode = 0;
6533 bool relocateableExternal = false;
6538 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6539 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6540 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
6543 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6544 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6546 case arm::kFollowOn:
6547 case arm::kGroupSubordinate:
6551 case arm::kReadOnlyPointer:
6552 case arm::kPointerWeakImport:
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);
6559 LittleEndian::set32(*fixUp, 0);
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());
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);
6575 case ObjectFile::Atom::kAbsoluteSymbol:
6581 // internal relocation
6582 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6583 // pointer contains target address
6584 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6586 LittleEndian::set32(*fixUp, targetAddr);
6589 // pointer contains addend
6590 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6595 case arm::kPointerDiff:
6596 LittleEndian::set32(*fixUp,
6597 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
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
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();
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());
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;
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;
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());
6641 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6643 LittleEndian::set32(*fixUp, newInstruction);
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();
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
6658 if (!targetIsThumb) {
6659 targetAddr &= -3ULL;
6660 targetAddr |= (baseAddr & 2LL);
6662 displacement = targetAddr - baseAddr;
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();
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());
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);
6693 if ( targetIsThumb )
6694 opcode = 0xD000F000; // keep bl
6696 opcode = 0xC000F000; // change to blx
6698 else if ( is_blx ) {
6699 if ( targetIsThumb )
6700 opcode = 0xD000F000; // change to bl
6702 opcode = 0xC000F000; // keep blx
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());
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);
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());
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;
6733 else if ( is_blx && targetIsThumb ) {
6734 opcode = 0xF800F000;
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());
6741 opcode = instruction & 0xF800F800;
6743 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6744 LittleEndian::set32(*fixUp, newInstruction);
6746 case arm::kDtraceProbe:
6747 case arm::kDtraceTypeReference:
6748 // nothing to fix up
6750 case arm::kPointerDiff12:
6751 throw "internal error. no reloc for 12-bit pointer diffs";
6756 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
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;
6766 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6769 case x86::kFollowOn:
6770 case x86::kGroupSubordinate:
6773 case x86::kPointerWeakImport:
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());
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());
6790 case ObjectFile::Atom::kAbsoluteSymbol:
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());
6800 // external relocation ==> pointer contains addend
6801 LittleEndian::set32(*fixUp, ref->getTargetOffset());
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());
6811 case x86::kPointerDiff:
6812 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6813 LittleEndian::set32(*fixUp, (uint32_t)displacement);
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);
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);
6827 temp |= (displacement & 0x00FFFFFF);
6828 LittleEndian::set32(*fixUp, temp);
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);
6836 temp |= (displacement & 0x00FFFFFF);
6837 LittleEndian::set32(*fixUp, temp);
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;
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
6857 case x86::kPCRel32WeakImport:
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);
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:
6873 case ObjectFile::Atom::kAbsoluteSymbol:
6874 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6877 if ( kind == x86::kPCRel8 ) {
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());
6883 *(int8_t*)fixUp = (int8_t)displacement;
6885 else if ( kind == x86::kPCRel16 ) {
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());
6891 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
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());
6898 LittleEndian::set32(*fixUp, (int32_t)displacement);
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());
6909 case ObjectFile::Atom::kExternalDefinition:
6910 case ObjectFile::Atom::kExternalWeakDefinition:
6911 // external relocation ==> pointer contains addend
6912 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6914 case ObjectFile::Atom::kAbsoluteSymbol:
6915 // pointer contains target address
6916 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
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);
6925 case x86::kDtraceTypeReference:
6926 case x86::kDtraceProbe:
6927 // nothing to fix up
6935 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
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());
6946 case x86::kFollowOn:
6947 case x86::kGroupSubordinate:
6951 case x86::kPointerWeakImport:
6952 case x86::kAbsolute32:
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());
6959 LittleEndian::set32(*fixUp, 0);
6961 else if ( isExtern ) {
6962 // external relocation ==> pointer contains addend
6963 LittleEndian::set32(*fixUp, ref->getTargetOffset());
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());
6970 // internal relocation to tentative ==> pointer contains addend
6971 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6975 case x86::kPointerDiff:
6976 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6977 LittleEndian::set32(*fixUp, (uint32_t)displacement);
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);
6988 case x86::kPCRel32WeakImport:
6989 case x86::kDtraceProbeSite:
6990 case x86::kDtraceIsEnabledSite:
6993 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6995 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6996 if ( kind == x86::kPCRel8 ) {
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());
7002 int8_t byte = (int8_t)displacement;
7003 *((int8_t*)fixUp) = byte;
7005 else if ( kind == x86::kPCRel16 ) {
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());
7011 int16_t word = (int16_t)displacement;
7012 LittleEndian::set16(*((uint16_t*)fixUp), word);
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());
7020 LittleEndian::set32(*fixUp, (int32_t)displacement);
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
7038 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
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;
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:
7053 case x86_64::kPointerWeakImport:
7054 case x86_64::kPointer:
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());
7065 // external relocation ==> pointer contains addend
7066 LittleEndian::set64(*fixUp, ref->getTargetOffset());
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());
7078 case x86_64::kPointer32:
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());
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";
7103 case Options::kStaticExecutable:
7104 // <rdar://problem/5855588> allow x86_64 mach_kernel to truncate pointers
7107 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
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);
7117 case x86_64::kPointerDiff:
7118 LittleEndian::set64(*fixUp,
7119 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
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));
7127 temp |= (displacement & 0x00FFFFFF);
7128 LittleEndian::set32(*((uint32_t*)fixUp), temp);
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));
7136 temp |= (displacement & 0x00FFFFFF);
7137 LittleEndian::set32(*((uint32_t*)fixUp), temp);
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";
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);
7165 case ObjectFile::Atom::kAbsoluteSymbol:
7166 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7168 case ObjectFile::Atom::kExternalDefinition:
7169 case ObjectFile::Atom::kExternalWeakDefinition:
7170 if ( fOptions.outputKind() == Options::kKextBundle )
7173 throwf("codegen problem, can't use rel32 to external symbol %s", ref->getTarget().getDisplayName());
7176 switch ( ref->getKind() ) {
7177 case x86_64::kPCRel32_1:
7180 case x86_64::kPCRel32_2:
7183 case x86_64::kPCRel32_4:
7186 case x86_64::kBranchPCRel8:
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";
7196 *((int8_t*)fixUp) = (int8_t)displacement;
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";
7204 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
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);
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;
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
7230 case x86_64::kDtraceTypeReference:
7231 case x86_64::kDtraceProbe:
7232 // nothing to fix up
7238 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
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;
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:
7252 case x86_64::kPointer:
7253 case x86_64::kPointerWeakImport:
7256 // external relocation ==> pointer contains addend
7257 LittleEndian::set64(*fixUp, ref->getTargetOffset());
7260 // internal relocation ==> pointer contains target address
7261 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
7265 case x86_64::kPointer32:
7268 // external relocation ==> pointer contains addend
7269 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset());
7272 // internal relocation ==> pointer contains target address
7273 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTarget().getAddress() + ref->getTargetOffset());
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);
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);
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();
7304 // extern relocation contains addend
7305 displacement = temp32;
7308 // internal relocations contain delta to target address
7309 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7311 switch ( ref->getKind() ) {
7312 case x86_64::kPCRel32_1:
7315 case x86_64::kPCRel32_2:
7318 case x86_64::kPCRel32_4:
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";
7326 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
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();
7332 // extern relocation contains addend
7333 displacement = temp32;
7336 // internal relocations contain delta to target address
7337 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
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";
7343 *((int8_t*)fixUp) = (int8_t)displacement;
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()));
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
7366 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7368 fixUpReference_powerpc(ref, inAtom, buffer, true);
7372 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7374 fixUpReference_powerpc(ref, inAtom, buffer, true);
7378 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7380 fixUpReference_powerpc(ref, inAtom, buffer, false);
7384 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7386 fixUpReference_powerpc(ref, inAtom, buffer, false);
7390 // ppc and ppc64 are mostly the same, so they share a template specialzation
7392 template <typename A>
7393 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
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;
7407 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
7408 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
7409 if ( finalLinkedImage )
7410 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
7412 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
7415 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
7418 case A::kGroupSubordinate:
7421 case A::kPointerWeakImport:
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);
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);
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);
7447 P::setP(*fixUpPointer, 0);
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());
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);
7463 case ObjectFile::Atom::kAbsoluteSymbol:
7468 // external relocation ==> pointer contains addend
7469 P::setP(*fixUpPointer, ref->getTargetOffset());
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);
7480 // pointer contains addend
7481 P::setP(*fixUpPointer, ref->getTargetOffset());
7486 case A::kPointerDiff64:
7487 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7489 case A::kPointerDiff32:
7490 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7492 case A::kPointerDiff16:
7493 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7495 case A::kDtraceProbeSite:
7496 if ( finalLinkedImage ) {
7497 // change call site to a NOP
7498 BigEndian::set32(*fixUp, 0x60000000);
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);
7508 case A::kDtraceIsEnabledSite:
7509 if ( finalLinkedImage ) {
7510 // change call site to a li r3,0
7511 BigEndian::set32(*fixUp, 0x38600000);
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);
7521 case A::kBranch24WeakImport:
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();
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());
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);
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();
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());
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);
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);
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);
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);
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);
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);
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());
7629 case ObjectFile::Atom::kTentativeDefinition:
7630 case ObjectFile::Atom::kRegularDefinition:
7631 case ObjectFile::Atom::kWeakDefinition:
7632 // use target address
7634 case ObjectFile::Atom::kAbsoluteSymbol:
7635 targetAddr = ref->getTarget().getSectionOffset();
7640 targetAddr -= ref->getTarget().getAddress();
7643 instructionHighHalf = (targetAddr >> 16);
7644 instruction = BigEndian::get32(*fixUp);
7645 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
7646 BigEndian::set32(*fixUp, newInstruction);
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());
7656 case ObjectFile::Atom::kTentativeDefinition:
7657 case ObjectFile::Atom::kRegularDefinition:
7658 case ObjectFile::Atom::kWeakDefinition:
7659 // use target address
7661 case ObjectFile::Atom::kAbsoluteSymbol:
7662 targetAddr = ref->getTarget().getSectionOffset();
7667 targetAddr -= ref->getTarget().getAddress();
7670 if ( targetAddr & 0x00008000 )
7671 targetAddr += 0x00010000;
7672 instruction = BigEndian::get32(*fixUp);
7673 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
7674 BigEndian::set32(*fixUp, newInstruction);
7676 case A::kDtraceTypeReference:
7677 case A::kDtraceProbe:
7678 // nothing to fix up
7684 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7686 uint8_t kind = ref->getKind();
7687 switch ( (ppc::ReferenceKinds)kind ) {
7689 case ppc::kFollowOn:
7690 case ppc::kGroupSubordinate:
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
7702 case ppc::kBranch24:
7703 case ppc::kBranch24WeakImport:
7704 case ppc::kBranch14:
7705 // these are used to call external functions
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:
7735 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7737 uint8_t kind = ref->getKind();
7738 switch ( (arm::ReferenceKinds)kind ) {
7739 case arm::kBranch24:
7740 case arm::kBranch24WeakImport:
7742 case arm::kThumbBranch22:
7743 case arm::kThumbBranch22WeakImport:
7744 fHasThumbBranches = true;
7747 case arm::kFollowOn:
7748 case arm::kGroupSubordinate:
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:
7764 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7766 uint8_t kind = ref->getKind();
7767 switch ( (ppc64::ReferenceKinds)kind ) {
7769 case ppc::kFollowOn:
7770 case ppc::kGroupSubordinate:
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
7789 case ppc::kBranch24:
7790 case ppc::kBranch24WeakImport:
7791 case ppc::kBranch14:
7792 // these are used to call external functions
7799 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7801 uint8_t kind = ref->getKind();
7802 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
7806 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7808 uint8_t kind = ref->getKind();
7809 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
7814 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
7816 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
7820 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
7822 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
7826 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
7828 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
7832 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
7835 case x86_64::kPointerWeakImport:
7836 case x86_64::kBranchPCRel32WeakImport:
7837 case x86_64::kPCRel32GOTWeakImport:
7838 case x86_64::kPCRel32GOTLoadWeakImport:
7845 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
7847 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
7848 kind == arm::kPointerWeakImport);
7852 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
7858 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
7864 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
7870 bool Writer<x86_64>::GOTReferenceKind(uint8_t 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:
7884 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
7890 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
7896 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
7902 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
7908 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
7911 case x86_64::kPCRel32GOTLoad:
7912 case x86_64::kPCRel32GOTLoadWeakImport:
7919 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
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; }
7930 template <typename A>
7931 void Writer<A>::optimizeDylibReferences()
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());
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;
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();
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;
7960 readerAliases[reader] = pos->second;
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;
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;
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);
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];
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());
7997 void Writer<arm>::scanForAbsoluteReferences()
7999 // arm codegen never has absolute references. FIXME: Is this correct?
8003 void Writer<x86_64>::scanForAbsoluteReferences()
8005 // x86_64 codegen never has absolute references
8009 void Writer<x86>::scanForAbsoluteReferences()
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 )
8017 if ( atom->getContentType() == ObjectFile::Atom::kStubHelper )
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());
8033 void Writer<ppc>::scanForAbsoluteReferences()
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());
8056 // for ppc64 look for any -mdynamic-no-pic codegen
8058 void Writer<ppc64>::scanForAbsoluteReferences()
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);
8085 template <typename A>
8086 void Writer<A>::insertDummyStubs()
8088 // only needed for x86
8092 void Writer<x86>::insertDummyStubs()
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
8105 betterStubs.push_back(*it);
8108 fAllSynthesizedStubs.clear();
8109 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
8113 template <typename A>
8114 void Writer<A>::synthesizeKextGOT(const std::vector<class ObjectFile::Atom*>& existingAtoms,
8115 std::vector<class ObjectFile::Atom*>& newAtoms)
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:
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()) )
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);
8147 // alter reference to use non lazy pointer instead
8148 ref->setTarget(*nlp, ref->getTargetOffset());
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;
8165 template <typename A>
8166 void Writer<A>::synthesizeStubs(const std::vector<class ObjectFile::Atom*>& existingAtoms,
8167 std::vector<class ObjectFile::Atom*>& newAtoms)
8169 switch ( fOptions.outputKind() ) {
8170 case Options::kObjectFile:
8171 case Options::kPreload:
8172 // these output kinds never have stubs
8174 case Options::kKextBundle:
8175 // new kext need a synthesized GOT only
8176 synthesizeKextGOT(existingAtoms, newAtoms);
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
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:
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() )
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;
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;
8227 // target in fWeakImportMap, check for weakness mismatch
8228 if ( pos->second != weakImport ) {
8230 switch ( fOptions.weakReferenceMismatchTreatment() ) {
8231 case Options::kWeakReferenceMismatchError:
8232 throwf("mismatching weak references for symbol: %s", target.getName());
8233 case Options::kWeakReferenceMismatchWeak:
8236 case Options::kWeakReferenceMismatchNonWeak:
8237 pos->second = false;
8242 // update if we use a weak_import or a strong import from this dylib
8243 if ( fWeakImportMap[&target] )
8244 fDylibReadersWithWeakImports.insert(target.getFile());
8246 fDylibReadersWithNonWeakImports.insert(target.getFile());
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:
8262 case ObjectFile::Atom::kExternalDefinition:
8263 case ObjectFile::Atom::kExternalWeakDefinition:
8264 if ( target.getFile()->isLazyLoadedDylib() )
8265 forLazyDylib = true;
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);
8274 stub = new StubAtom<A>(*this, target, forLazyDylib);
8275 fStubsMap[&target] = stub;
8280 // alter reference to use stub instead
8281 ref->setTarget(*stub, 0);
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());
8288 // create GOT slots (non-lazy pointers) as needed
8289 else if ( this->GOTReferenceKind(ref->getKind()) ) {
8291 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
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();
8299 // < 2GB image so remove all GOT entries that we can
8300 useGOT = mustUseGOT;
8302 // if this GOT usage cannot be optimized away then make a GOT enry
8303 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
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;
8315 // alter reference to use non lazy pointer instead
8316 ref->setTarget(*nlp, ref->getTargetOffset());
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());
8334 // sort lazy pointers
8335 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
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());
8341 // sort non-lazy pointers
8342 std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter());
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());
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());
8357 template <typename A>
8358 void Writer<A>::createSplitSegContent()
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:
8371 case ObjectFile::Reference::kBoundByName:
8372 case ObjectFile::Reference::kBoundDirectly:
8373 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
8374 this->addCrossSegmentRef(atom, ref);
8380 // bad codegen may cause LC_SEGMENT_SPLIT_INFO to be removed
8381 adjustLoadCommandsAndPadding();
8387 template <typename A>
8388 void Writer<A>::synthesizeUnwindInfoTable()
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);
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());
8410 template <typename A>
8411 void Writer<A>::partitionIntoSections()
8413 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
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);
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;
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
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;
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);
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;
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);
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;
8507 switch ( atom->getContentType() ) {
8508 case ObjectFile::Atom::kLazyPointer:
8509 currentSectionInfo->fAllLazyPointers = true;
8510 fSymbolTableCommands->needDynamicTable();
8512 case ObjectFile::Atom::kNonLazyPointer:
8513 currentSectionInfo->fAllNonLazyPointers = true;
8514 fSymbolTableCommands->needDynamicTable();
8516 case ObjectFile::Atom::kLazyDylibPointer:
8517 currentSectionInfo->fAllLazyDylibPointers = true;
8519 case ObjectFile::Atom::kStubHelper:
8520 currentSectionInfo->fAllStubHelpers = true;
8522 case ObjectFile::Atom::kCFIType:
8523 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
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
8531 currentSectionInfo->fAllStubs = true;
8533 fSymbolTableCommands->needDynamicTable();
8538 curSection = atom->getSection();
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;
8558 offset += requiredModulus+alignment-currentModulus;
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;
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();
8581 cstringSectionInfo->fSize = offset;
8586 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
8587 class TargetAndOffsetComparor
8590 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
8592 if ( left.atom != right.atom )
8593 return ( left.atom < right.atom );
8594 return ( left.offset < right.offset );
8599 bool Writer<ppc>::addBranchIslands()
8601 return this->createBranchIslands();
8605 bool Writer<ppc64>::addBranchIslands()
8607 return this->createBranchIslands();
8611 bool Writer<x86>::addBranchIslands()
8613 // x86 branches can reach entire 4G address space, so no need for branch islands
8618 bool Writer<x86_64>::addBranchIslands()
8620 // x86 branches can reach entire 4G size of largest image
8625 bool Writer<arm>::addBranchIslands()
8627 return this->createBranchIslands();
8631 bool Writer<ppc>::isBranchThatMightNeedIsland(uint8_t kind)
8634 case ppc::kBranch24:
8635 case ppc::kBranch24WeakImport:
8642 bool Writer<ppc64>::isBranchThatMightNeedIsland(uint8_t kind)
8645 case ppc64::kBranch24:
8646 case ppc64::kBranch24WeakImport:
8653 bool Writer<arm>::isBranchThatMightNeedIsland(uint8_t kind)
8656 case arm::kBranch24:
8657 case arm::kBranch24WeakImport:
8658 case arm::kThumbBranch22:
8659 case arm::kThumbBranch22WeakImport:
8666 uint32_t Writer<ppc>::textSizeWhenMightNeedBranchIslands()
8672 uint32_t Writer<ppc64>::textSizeWhenMightNeedBranchIslands()
8678 uint32_t Writer<arm>::textSizeWhenMightNeedBranchIslands()
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
8685 return 4000000; // thumb1 can branch +/- 4MB
8689 uint32_t Writer<ppc>::maxDistanceBetweenIslands()
8691 return 14*1024*1024;
8695 uint32_t Writer<ppc64>::maxDistanceBetweenIslands()
8697 return 14*1024*1024;
8701 uint32_t Writer<arm>::maxDistanceBetweenIslands()
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;
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.
8718 // Branch Island Algorithm
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.
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.
8734 template <typename A>
8735 bool Writer<A>::createBranchIslands()
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 ) {
8747 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
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);
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 = ⌖
8774 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
8775 AtomToIsland* region = ®ionsMap[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);
8786 nextTarget = island;
8789 nextTarget = pos->second;
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);
8796 else if ( displacement < (-kBranchLimit) ) {
8797 // create back branching chain
8798 ObjectFile::Atom* prevTarget = ⌖
8799 for (int i=0; i < kIslandRegionsCount ; ++i) {
8800 AtomToIsland* region = ®ionsMap[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);
8811 prevTarget = island;
8814 prevTarget = pos->second;
8818 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
8819 ref->setTarget(*prevTarget, 0);
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 = ®ionsIslands[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();
8851 islandRegionAddr += kBetweenRegions;
8852 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
8853 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
8855 newAtomList.push_back(atom);
8856 if ( atomSlide != 0 )
8857 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
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 = ®ionsIslands[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();
8874 textSection->fAtoms = newAtomList;
8875 textSection->fSize = sectionOffset;
8884 template <typename A>
8885 void Writer<A>::adjustLoadCommandsAndPadding()
8887 fSegmentCommands->computeSize();
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;
8902 fLoadCommandsSection->fSize = offset;
8904 const uint32_t sizeOfLoadCommandsPlusHeader = offset + sizeof(macho_header<typename A::P>);
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 )
8913 totalSizeOfTEXTLessHeaderAndLoadCommands += curSection->fSize;
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);
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
8925 else if ( fOptions.outputKind() == Options::kPreload ) {
8926 // mach-o MH_PRELOAD files need no padding between load commands and first section
8930 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
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();
8939 addr -= curSection->fSize;
8940 addr = addr & (0 - (1 << curSection->fAlignment));
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 )
8953 if ( paddingSize < minPad ) {
8954 int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment();
8955 paddingSize += extraPages * fOptions.segmentAlignment();
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();
8967 //paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
8968 fEncryptionLoadCommand->setStartEncryptionOffset(textPage*fOptions.segmentAlignment());
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;
8981 static uint64_t segmentAlign(uint64_t addr, uint64_t alignment)
8983 return ((addr+alignment-1) & (-alignment));
8986 // assign file offsets and logical address to all segments
8987 template <typename A>
8988 void Writer<A>::assignFileOffsets()
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();
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;
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;
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;
9025 if ( fOptions.splitSeg() ) {
9026 if ( curSegment->fInitProtection & VM_PROT_WRITE )
9027 nextContiguousAddress = nextWritableAddress;
9029 nextContiguousAddress = nextReadOnlyAddress;
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();
9039 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
9040 curSegment->fFileOffset = fileOffset;
9042 // Set the segment base address
9043 if ( curSegment->fFixedAddress )
9044 haveFixedSegments = true;
9046 curSegment->fBaseAddress = segmentAlign(nextContiguousAddress, curSegment->fPageSize);
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;
9053 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
9055 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
9056 SectionInfo* curSection = *it;
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;
9069 address += atomAlign.modulus+atomAlignP2-currentModulus;
9073 address = ( (address+alignment-1) & (-alignment) );
9075 // adjust file offset to match address
9076 if ( prevSection != NULL ) {
9077 if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection )
9078 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
9080 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
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);
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);
9094 // update running pointers
9095 if ( virtualSectionOccupyAddressSpace || !curSection->fVirtualSection )
9096 address += curSection->fSize;
9097 fileOffset += curSection->fSize;
9099 // sanity check size of 32-bit binaries
9100 if ( address > maxAddress() )
9101 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
9103 // update segment info
9104 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
9105 curSegment->fSize = curSegment->fFileSize;
9106 prevSection = curSection;
9109 if ( fOptions.outputKind() == Options::kObjectFile ) {
9110 // don't page align .o files
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;
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;
9127 nextReadOnlyAddress = nextContiguousAddress;
9130 //fprintf(stderr, "end of seg %s, fileoffset=0x%llX, nextContiguousAddress=0x%llX\n", curSegment->fName, fileOffset, nextContiguousAddress);
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];
9139 for(int j=0; j < segCount; ++j) {
9141 SegmentInfo* segment2 = fSegmentInfos[j];
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);
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);
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);
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;
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);
9186 template <typename A>
9187 void Writer<A>::adjustLinkEditSections()
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;
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);
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();
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;
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;
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;
9240 if ( fOptions.outputKind() == Options::kObjectFile ) {
9241 //lastSeg->fBaseAddress = 0;
9242 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
9243 //lastSeg->fFileOffset = 0;
9244 //lastSeg->fFileSize =
9247 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
9248 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
9253 template <typename A>
9254 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
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;
9268 throw "unknown header type";
9271 template <typename A>
9272 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
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;
9288 throw "unknown header type";
9291 template <typename A>
9292 const char* MachHeaderAtom<A>::getName() const
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:
9306 case Options::kDyld:
9307 return "__mh_dylinker_header";
9309 throw "unknown header type";
9312 template <typename A>
9313 const char* MachHeaderAtom<A>::getDisplayName() const
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";
9327 throw "unknown header type";
9330 template <typename A>
9331 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
9334 uint32_t fileType = 0;
9335 switch ( fWriter.fOptions.outputKind() ) {
9336 case Options::kDynamicExecutable:
9337 case Options::kStaticExecutable:
9338 fileType = MH_EXECUTE;
9340 case Options::kDynamicLibrary:
9341 fileType = MH_DYLIB;
9343 case Options::kDynamicBundle:
9344 fileType = MH_BUNDLE;
9346 case Options::kObjectFile:
9347 fileType = MH_OBJECT;
9349 case Options::kDyld:
9350 fileType = MH_DYLINKER;
9352 case Options::kPreload:
9353 fileType = MH_PRELOAD;
9355 case Options::kKextBundle:
9356 fileType = MH_KEXT_BUNDLE;
9362 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
9363 if ( fWriter.fCanScatter )
9364 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
9367 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
9368 flags |= MH_NOUNDEFS;
9370 else if ( fWriter.fOptions.outputKind() == Options::kPreload ) {
9371 flags |= MH_NOUNDEFS;
9372 if ( fWriter.fOptions.positionIndependentExecutable() )
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;
9383 case Options::kFlatNameSpace:
9385 case Options::kForceFlatNameSpace:
9386 flags |= MH_FORCE_FLAT;
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;
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() )
9411 if ( fWriter.fOptions.markAutoDeadStripDylib() )
9412 flags |= MH_DEAD_STRIPPABLE_DYLIB;
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;
9422 // get commands info
9423 uint32_t commandsSize = 0;
9424 uint32_t commandsCount = 0;
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 )
9439 // fill out mach_header
9440 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
9442 mh->set_filetype(fileType);
9443 mh->set_ncmds(commandsCount);
9444 mh->set_sizeofcmds(commandsSize);
9445 mh->set_flags(flags);
9449 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
9451 header.set_magic(MH_MAGIC);
9452 header.set_cputype(CPU_TYPE_POWERPC);
9453 header.set_cpusubtype(fWriter.fCpuConstraint);
9457 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
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);
9464 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
9465 header.set_reserved(0);
9469 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
9471 header.set_magic(MH_MAGIC);
9472 header.set_cputype(CPU_TYPE_I386);
9473 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
9477 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
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);
9484 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
9485 header.set_reserved(0);
9489 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
9491 header.set_magic(MH_MAGIC);
9492 header.set_cputype(CPU_TYPE_ARM);
9493 header.set_cpusubtype(fWriter.fCpuConstraint);
9496 template <typename A>
9497 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
9498 : WriterAtom<A>(writer, Segment::fgStackSegment)
9500 if ( stackGrowsDown() )
9501 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
9503 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
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; }
9513 template <typename A>
9514 void SegmentLoadCommandsAtom<A>::computeSize()
9517 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9519 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9520 SegmentInfo* seg = *it;
9521 if ( seg->fHasLoadCommand ) {
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>);
9533 fCommandCount = segCount;
9534 if ( fWriter.fPadSegmentInfo != NULL ) {
9536 fSize += sizeof(macho_segment_command<P>);
9541 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
9543 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9547 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
9549 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9553 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
9555 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9559 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
9561 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9565 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
9567 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9570 template <typename A>
9571 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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 )
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 = §ions[sectionsEmitted++];
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);
9605 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
9606 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
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);
9618 if ( sectInfo->fAllZeroFill ) {
9619 sect->set_flags(S_ZEROFILL);
9620 sect->set_offset(0);
9622 else if ( sectInfo->fAllLazyPointers ) {
9623 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
9624 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9626 else if ( sectInfo->fAllLazyDylibPointers ) {
9627 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
9628 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9630 else if ( sectInfo->fAllNonLazyPointers ) {
9631 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
9632 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
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);
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());
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);
9651 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCStringType ) {
9652 sect->set_flags(S_CSTRING_LITERALS);
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);
9657 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9658 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
9660 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9661 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
9663 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9664 sect->set_flags(S_COALESCED);
9666 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9667 sect->set_flags(S_COALESCED);
9669 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9670 sect->set_flags(S_INTERPOSING);
9672 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9673 sect->set_flags(S_4BYTE_LITERALS);
9675 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9676 sect->set_flags(S_8BYTE_LITERALS);
9678 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9679 sect->set_flags(S_16BYTE_LITERALS);
9681 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9682 sect->set_flags(S_LITERAL_POINTERS);
9684 else if ( (strcmp(sectInfo->fSectionName, "__objc_selrefs") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9685 sect->set_flags(S_LITERAL_POINTERS);
9687 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9688 sect->set_flags(S_LITERAL_POINTERS);
9690 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9691 sect->set_flags(S_DTRACE_DOF);
9693 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9694 sect->set_flags(S_DTRACE_DOF);
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);
9703 //fprintf(stderr, "section %s flags=0x%08X\n", sectInfo->fSectionName, sect->flags());
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);
9713 template <typename A>
9714 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
9715 : LoadCommandAtom<A>(writer), fNeedsDynamicSymbolTable(false)
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;
9727 case Options::kObjectFile:
9728 case Options::kStaticExecutable:
9729 fNeedsDynamicSymbolTable = false;
9730 case Options::kPreload:
9731 fNeedsDynamicSymbolTable = fWriter.fOptions.positionIndependentExecutable();
9734 writer.fSymbolTableCommands = this;
9739 template <typename A>
9740 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
9742 fNeedsDynamicSymbolTable = true;
9746 template <typename A>
9747 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
9749 if ( fNeedsDynamicSymbolTable )
9750 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
9752 return this->alignedSize(sizeof(macho_symtab_command<P>));
9755 template <typename A>
9756 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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());
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());
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());
9795 if ( fWriter.fLocalRelocationsAtom != 0 ) {
9796 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
9797 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
9804 template <typename A>
9805 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
9807 return fNeedsDynamicSymbolTable ? 2 : 1;
9810 template <typename A>
9811 uint64_t DyldLoadCommandsAtom<A>::getSize() const
9813 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
9816 template <typename A>
9817 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
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");
9831 template <typename A>
9832 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
9834 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
9837 template <typename A>
9838 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9840 uint64_t size = this->getSize();
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);
9851 template <typename A>
9852 uint64_t DylibLoadCommandsAtom<A>::getSize() const
9854 if ( fOptimizedAway ) {
9858 const char* path = fInfo.reader->getInstallPath();
9859 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
9863 template <typename A>
9864 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9866 if ( fOptimizedAway )
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);
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);
9893 template <typename A>
9894 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
9896 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
9899 template <typename A>
9900 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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());
9915 template <typename A>
9916 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9918 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9919 if (fWriter.fEntryPoint->isThumb())
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);
9929 template <typename A>
9930 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
9932 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
9935 template <typename A>
9936 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
9947 template <typename A>
9948 void UUIDLoadCommandAtom<A>::generate()
9950 switch ( fWriter.fOptions.getUUIDMode() ) {
9951 case Options::kUUIDNone:
9954 case Options::kUUIDRandom:
9955 ::uuid_generate_random(fUUID);
9958 case Options::kUUIDContent:
9965 template <typename A>
9966 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
9968 memcpy(fUUID, uuid, 16);
9971 template <typename A>
9972 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
9985 template <typename A>
9986 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
9988 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
9991 template <typename A>
9992 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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';
10004 template <typename A>
10005 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
10007 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
10010 template <typename A>
10011 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
10023 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
10025 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
10029 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
10031 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
10035 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
10037 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
10041 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
10043 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
10046 // We should be picking it up from a header
10048 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
10050 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
10054 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
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
10071 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
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
10087 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
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
10103 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
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
10119 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
10121 uint64_t size = this->getSize();
10122 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
10123 if ( fWriter.fEntryPoint->isThumb() )
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?
10136 template <typename A>
10137 uint64_t RPathLoadCommandsAtom<A>::getSize() const
10139 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
10142 template <typename A>
10143 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
10156 template <typename A>
10157 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
10171 template <typename A>
10172 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
10174 bzero(buffer, fSize);
10177 template <typename A>
10178 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
10181 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
10182 if ( fWriter.fLargestAtomSize < newSize )
10183 fWriter.fLargestAtomSize = newSize;
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)
10193 if ( fdeRef != NULL )
10194 info.fde = &fdeRef->getTarget();
10197 if ( lsdaRef != NULL ) {
10198 info.lsda = &lsdaRef->getTarget();
10199 info.lsdaOffset = lsdaRef->getTargetOffset();
10203 info.lsdaOffset = 0;
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());
10213 bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10215 return ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
10219 bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10221 return ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
10224 template <typename A>
10225 bool UnwindInfoAtom<A>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10231 template <typename A>
10232 void UnwindInfoAtom<A>::compressDuplicates(std::vector<Info>& uniqueInfos)
10234 // build new list removing entries where next function has same encoding
10235 uniqueInfos.reserve(fInfos.size());
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);
10252 //fprintf(stderr, "compressDuplicates() fInfos.size()=%lu, uniqueInfos.size()=%lu\n", fInfos.size(), uniqueInfos.size());
10255 template <typename A>
10256 void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings)
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) )
10265 std::map<uint32_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
10266 if ( pos == encodingsUsed.end() ) {
10267 encodingsUsed[it->encoding] = 1;
10270 encodingsUsed[it->encoding] += 1;
10271 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
10272 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
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;
10288 template <typename A>
10289 void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap)
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 ) {
10295 entry.func = it->func;
10296 entry.lsda = it->lsda;
10297 entry.lsdaOffset = it->lsdaOffset;
10298 fLSDAIndex.push_back(entry);
10303 template <typename A>
10304 void UnwindInfoAtom<A>::makePersonalityIndex(std::vector<Info>& uniqueInfos)
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;
10313 uint32_t personalityIndex = fPersonalityIndexMap[it->personalityPointer];
10314 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
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)
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);
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);
10343 //fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
10344 pageEnd = pageStart;
10345 return endIndex - entriesToAdd;
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)
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();
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;
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);
10384 std::map<uint32_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
10385 if ( ppos != pageSpecificEncodings.end() ) {
10386 encodingIndex = pos->second;
10389 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
10390 if ( encodingIndex <= 255 ) {
10391 pageSpecificEncodings[encoding] = encodingIndex;
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());
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);
10412 // check room for entry
10413 if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
10414 canDo = false; // case 1)
10416 if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
10418 //if (log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
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);
10432 // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
10434 if ( compressPageUsed == (pageSize-4) )
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];
10457 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10458 if ( pos != commonEncodings.end() )
10459 encodingIndex = pos->second;
10461 encodingIndex = pageSpecificEncodings[info.encoding];
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);
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);
10482 if (log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
10485 pageEnd = pageStart;
10486 return endIndex-entryCount; // endIndex for next page
10489 template <> void UnwindInfoAtom<ppc>::generate() { }
10490 template <> void UnwindInfoAtom<ppc64>::generate() { }
10491 template <> void UnwindInfoAtom<arm>::generate() { }
10494 template <typename A>
10495 void UnwindInfoAtom<A>::generate()
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();
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);
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";
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);
10515 // build lsda index
10516 std::map<ObjectFile::Atom*, uint32_t> lsdaIndexOffsetMap;
10517 this->makeLsdaIndex(uniqueInfos, lsdaIndexOffsetMap);
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);
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];
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;
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
10549 fPagesContent = pageEnd;
10550 fPagesSize = &fPagesContentForDelete[pageCount*4096] - pageEnd;
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;
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);
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);
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));
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]));
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));
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);
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));
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));
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));
10634 // update section record with new size
10635 unwindSectionInfo->fSize = this->getSize();
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);
10647 template <typename A>
10648 void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10650 memcpy(buffer, fHeaderContent, fHeaderSize);
10651 memcpy(&buffer[fHeaderSize], fPagesContent, fPagesSize);
10656 template <typename A>
10657 uint64_t LinkEditAtom<A>::getFileOffset() const
10659 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
10663 template <typename A>
10664 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
10666 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
10669 template <typename A>
10670 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10672 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
10676 template <typename A>
10677 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
10679 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
10682 template <typename A>
10683 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10685 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
10690 template <typename A>
10691 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
10693 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
10696 template <typename A>
10697 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10699 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
10702 template <typename A>
10703 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
10705 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
10708 template <typename A>
10709 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10711 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
10712 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
10717 template <typename A>
10718 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
10720 return fTable.size() * sizeof(uint32_t);
10723 template <typename A>
10724 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
10734 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
10740 template <typename A>
10741 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
10743 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
10744 + sizeof(macho_dylib_module<P>)
10745 + this->getReferencesCount()*sizeof(uint32_t);
10748 template <typename A>
10749 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
10751 return this->getFileOffset();
10754 template <typename A>
10755 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
10757 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
10760 template <typename A>
10761 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
10763 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
10766 template <typename A>
10767 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
10769 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
10772 template <typename A>
10773 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
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);
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);
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;
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);
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);
10835 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
10841 template <typename A>
10842 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
10843 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
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';
10852 template <typename A>
10853 uint64_t StringsLinkEditAtom<A>::getSize() const
10856 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
10859 template <typename A>
10860 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
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;
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;
10874 template <typename A>
10875 int32_t StringsLinkEditAtom<A>::add(const char* name)
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;
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]);
10897 template <typename A>
10898 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
10900 StringToOffset::iterator pos = fUniqueStrings.find(name);
10901 if ( pos != fUniqueStrings.end() ) {
10902 return pos->second;
10905 int32_t offset = this->add(name);
10906 fUniqueStrings[name] = offset;
10912 template <typename A>
10913 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
10915 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
10916 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
10917 // check for out of bounds
10918 if ( index > maxIndex )
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)];
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)
10935 if ( finalTargetOffset == 0 ) {
10936 if ( islandRegion == 0 )
10937 asprintf((char**)&fName, "%s$island", name);
10939 asprintf((char**)&fName, "%s$island$%d", name, islandRegion+1);
10942 asprintf((char**)&fName, "%s_plus_%d$island$%d", name, finalTargetOffset, islandRegion);
10945 if ( finalTarget.isThumb() ) {
10946 if ( writer.fOptions.preferSubArchitecture() && writer.fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
10947 fIslandKind = kBranchIslandToThumb2;
10950 fIslandKind = kBranchIslandToThumb1;
10954 fIslandKind = kBranchIslandToARM;
10960 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
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();
10971 displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress();
10973 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10974 OSWriteBigInt32(buffer, 0, branchInstruction);
10978 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
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();
10989 displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress();
10991 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10992 OSWriteBigInt32(buffer, 0, branchInstruction);
10996 void BranchIslandAtom<arm>::copyRawContent(uint8_t buffer[]) const
10998 const bool log = false;
10999 switch ( fIslandKind ) {
11000 case kBranchIslandToARM:
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());
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());
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());
11024 uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF;
11025 int32_t branchInstruction = 0xEA000000 | imm24;
11026 OSWriteLittleInt32(buffer, 0, branchInstruction);
11029 case kBranchIslandToThumb2:
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());
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());
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());
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());
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);
11079 case kBranchIslandToThumb1:
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() )
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
11098 uint64_t BranchIslandAtom<ppc>::getSize() const
11104 uint64_t BranchIslandAtom<ppc64>::getSize() const
11110 uint64_t BranchIslandAtom<arm>::getSize() const
11112 switch ( fIslandKind ) {
11113 case kBranchIslandToARM:
11115 case kBranchIslandToThumb1:
11117 case kBranchIslandToThumb2:
11120 throw "internal error: no ARM branch island kind";
11125 template <typename A>
11126 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
11128 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
11129 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
11131 return 0; // a zero size causes the load command to be suppressed
11134 template <typename A>
11135 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
11137 uint64_t size = this->getSize();
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());
11149 template <typename A>
11150 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
11152 return fEncodedData.size();
11155 template <typename A>
11156 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
11158 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
11162 template <typename A>
11163 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
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;
11171 throw "double split seg info for same address";
11175 byte = delta & 0x7F;
11179 fEncodedData.push_back(byte);
11180 delta = delta >> 7;
11182 while( byte >= 0x80 );
11187 template <typename A>
11188 void SegmentSplitInfoContentAtom<A>::encode()
11190 if ( ! fCantEncode ) {
11191 fEncodedData.reserve(8192);
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);
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);
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);
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);
11221 // always add zero byte to mark end
11222 fEncodedData.push_back(0);
11224 // add zeros to end to align size
11225 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
11226 fEncodedData.push_back(0);
11231 template <typename A>
11232 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
11233 : WriterAtom<A>(writer, getInfoSegment())
11236 uint32_t value = 0;
11237 // struct objc_image_info {
11238 // uint32_t version; // initially 0
11241 // #define OBJC_IMAGE_SUPPORTS_GC 2
11242 // #define OBJC_IMAGE_GC_ONLY 4
11244 if ( objcReplacementClasses )
11246 switch ( objcConstraint ) {
11247 case ObjectFile::Reader::kObjcNone:
11248 case ObjectFile::Reader::kObjcRetainRelease:
11250 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
11253 case ObjectFile::Reader::kObjcGC:
11257 A::P::E::set32(fContent[1], value);
11260 template <typename A>
11261 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
11263 memcpy(buffer, &fContent[0], 8);
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"; }
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; }
11283 template <typename A>
11284 void DyldInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
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>));
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());
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());
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());
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());
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());
11317 rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
11324 template <typename A>
11325 void CompressedRebaseInfoLinkEditAtom<A>::encode()
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());
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;
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));
11343 if ( address != it->fAddress ) {
11344 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11345 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= it->fAddress) ) {
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;
11354 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11357 mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11359 address = it->fAddress;
11361 mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
11362 address += sizeof(pint_t);
11364 mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
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) ) {
11371 while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
11372 dst->operand1 += src->operand1;
11382 dst->opcode = REBASE_OPCODE_DONE;
11384 // optimize phase 2, combine rebase/add pairs
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;
11399 dst->opcode = REBASE_OPCODE_DONE;
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
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;
11414 dst->operand2 = delta;
11416 while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11417 && (src->operand1 == delta) ) {
11428 dst->opcode = REBASE_OPCODE_DONE;
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);
11438 else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
11439 p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
11443 // convert to compressed encoding
11444 const static bool log = false;
11445 fEncodedData.reserve(info.size()*2);
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");
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);
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);
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);
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 );
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);
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);
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);
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);
11495 // align to pointer size
11496 fEncodedData.pad_to_size(sizeof(pint_t));
11498 if (log) fprintf(stderr, "total rebase info size = %ld\n", fEncodedData.size());
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) {}
11514 template <typename A>
11515 void CompressedBindingInfoLinkEditAtom<A>::encode()
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());
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;
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));
11538 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->fLibraryOrdinal));
11540 ordinal = it->fLibraryOrdinal;
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;
11546 if ( type != it->fType ) {
11547 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11550 if ( address != it->fAddress ) {
11551 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11552 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress)
11553 || (it->fAddress < address) ) {
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;
11562 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11565 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11567 address = it->fAddress;
11569 if ( addend != it->fAddend ) {
11570 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11571 addend = it->fAddend;
11573 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11574 address += sizeof(pint_t);
11576 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
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;
11593 dst->opcode = BIND_OPCODE_DONE;
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
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;
11606 dst->operand2 = delta;
11608 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11609 && (src->operand1 == delta) ) {
11620 dst->opcode = BIND_OPCODE_DONE;
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);
11630 else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
11631 p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
11634 dst->opcode = BIND_OPCODE_DONE;
11636 // convert to compressed encoding
11637 const static bool log = false;
11638 fEncodedData.reserve(info.size()*2);
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");
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);
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);
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));
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);
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);
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);
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);
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);
11683 case BIND_OPCODE_DO_BIND:
11684 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11685 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
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);
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 );
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);
11705 // align to pointer size
11706 fEncodedData.pad_to_size(sizeof(pint_t));
11708 if (log) fprintf(stderr, "total binding info size = %ld\n", fEncodedData.size());
11714 struct WeakBindingSorter
11716 bool operator()(const BindingInfo& left, const BindingInfo& right)
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);
11729 template <typename A>
11730 void CompressedWeakBindingInfoLinkEditAtom<A>::encode()
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));
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));
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 )
11752 std::sort(info.begin(), info.end(), WeakBindingSorter());
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;
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;
11768 if ( it->fType != 0 ) {
11769 if ( type != it->fType ) {
11770 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
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) ) {
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;
11786 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11789 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11791 address = it->fAddress;
11793 if ( addend != it->fAddend ) {
11794 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11795 addend = it->fAddend;
11797 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11798 address += sizeof(pint_t);
11801 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
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;
11818 dst->opcode = BIND_OPCODE_DONE;
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
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;
11831 dst->operand2 = delta;
11833 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11834 && (src->operand1 == delta) ) {
11845 dst->opcode = BIND_OPCODE_DONE;
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);
11856 dst->opcode = BIND_OPCODE_DONE;
11859 // convert to compressed encoding
11860 const static bool log = false;
11861 fEncodedData.reserve(info.size()*2);
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);
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);
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);
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));
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);
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);
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);
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);
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);
11907 case BIND_OPCODE_DO_BIND:
11908 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11909 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
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);
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 );
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);
11929 // align to pointer size
11930 fEncodedData.pad_to_size(sizeof(pint_t));
11932 if (log) fprintf(stderr, "total weak binding info size = %ld\n", fEncodedData.size());
11936 template <typename A>
11937 void CompressedLazyBindingInfoLinkEditAtom<A>::encode()
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();
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());
11953 // write address to bind
11954 pint_t address = lazyPointerAtom->getAddress();
11955 if ( (currentSegment == NULL) || (address < currentSegment->fBaseAddress)
11956 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= address) ) {
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;
11966 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
11967 fEncodedData.append_uleb128(lazyPointerAtom->getAddress() - currentSegment->fBaseAddress);
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) );
11975 else if ( ordinal <= 15 ) {
11976 // small ordinals are encoded in opcode
11977 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
11980 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11981 fEncodedData.append_uleb128(ordinal);
11983 // write symbol name
11984 bool weak_import = fWriter.fWeakImportMap[lazyPointerTargetAtom];
11986 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | BIND_SYMBOL_FLAGS_WEAK_IMPORT);
11988 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
11989 fEncodedData.append_string(lazyPointerTargetAtom->getName());
11991 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11992 fEncodedData.append_byte(BIND_OPCODE_DONE);
11995 // align to pointer size
11996 fEncodedData.pad_to_size(sizeof(pint_t));
11998 //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", fEncodedData.size(), allLazys.size());
12001 struct TrieEntriesSorter
12003 TrieEntriesSorter(Options& o) : fOptions(o) {}
12005 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
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);
12014 return (left.address < right.address);
12021 template <typename A>
12022 void CompressedExportInfoLinkEditAtom<A>::encode()
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() )
12037 mach_o::trie::Entry entry;
12038 entry.name = atom->getName();
12039 entry.flags = flags;
12040 entry.address = address;
12041 entries.push_back(entry);
12044 // sort vector by -exported_symbols_order, and any others by address
12045 std::sort(entries.begin(), entries.end(), TrieEntriesSorter(fWriter.fOptions));
12048 mach_o::trie::makeTrie(entries, fEncodedData.bytes());
12050 // align to pointer size
12051 fEncodedData.pad_to_size(sizeof(pint_t));
12058 }; // namespace executable
12059 }; // namespace mach_o
12062 #endif // __EXECUTABLE_MACH_O__