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;
112 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
113 class SectionInfo : public ObjectFile::Section {
115 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0),
116 fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false),
117 fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false),
118 fAllSelfModifyingStubs(false), fAllStubHelpers(false),
119 fAllZeroFill(false), fVirtualSection(false),
120 fHasTextLocalRelocs(false), fHasTextExternalRelocs(false)
121 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
122 void setIndex(unsigned int index) { fIndex=index; }
123 std::vector<ObjectFile::Atom*> fAtoms;
124 char fSegmentName[20];
125 char fSectionName[20];
126 uint64_t fFileOffset;
128 uint32_t fRelocCount;
129 uint32_t fRelocOffset;
130 uint32_t fIndirectSymbolOffset;
132 bool fAllLazyPointers;
133 bool fAllLazyDylibPointers;
134 bool fAllNonLazyPointers;
136 bool fAllSelfModifyingStubs;
137 bool fAllStubHelpers;
139 bool fVirtualSection;
140 bool fHasTextLocalRelocs;
141 bool fHasTextExternalRelocs;
144 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
148 SegmentInfo(uint64_t pageSize) : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
149 fBaseAddress(0), fSize(0), fPageSize(pageSize), fFixedAddress(false),
150 fIndependentAddress(false), fHasLoadCommand(true) { fName[0] = '\0'; }
151 std::vector<class SectionInfo*> fSections;
153 uint32_t fInitProtection;
154 uint32_t fMaxProtection;
155 uint64_t fFileOffset;
157 uint64_t fBaseAddress;
161 bool fIndependentAddress;
162 bool fHasLoadCommand;
167 RebaseInfo(uint8_t t, uint64_t addr) : fType(t), fAddress(addr) {}
171 int operator<(const RebaseInfo& rhs) const {
172 // sort by type, then address
173 if ( this->fType != rhs.fType )
174 return (this->fType < rhs.fType );
175 return (this->fAddress < rhs.fAddress );
180 BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t addend)
181 : fType(t), fFlags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), fLibraryOrdinal(ord),
182 fSymbolName(sym), fAddress(addr), fAddend(addend) {}
183 BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t addend)
184 : fType(t), fFlags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ), fLibraryOrdinal(0),
185 fSymbolName(sym), fAddress(addr), fAddend(addend) {}
189 const char* fSymbolName;
194 int operator<(const BindingInfo& rhs) const {
195 // sort by library, symbol, type, then address
196 if ( this->fLibraryOrdinal != rhs.fLibraryOrdinal )
197 return (this->fLibraryOrdinal < rhs.fLibraryOrdinal );
198 if ( this->fSymbolName != rhs.fSymbolName )
199 return ( strcmp(this->fSymbolName, rhs.fSymbolName) < 0 );
200 if ( this->fType != rhs.fType )
201 return (this->fType < rhs.fType );
202 return (this->fAddress < rhs.fAddress );
209 std::vector<uint8_t> fData;
211 std::vector<uint8_t>& bytes() { return fData; }
212 unsigned long size() const { return fData.size(); }
213 void reserve(unsigned long l) { fData.reserve(l); }
214 const uint8_t* start() const { return &fData[0]; }
216 void append_uleb128(uint64_t value) {
223 fData.push_back(byte);
225 } while( byte >= 0x80 );
228 void append_sleb128(int64_t value) {
229 bool isNeg = ( value < 0 );
236 more = ( (value != -1) || ((byte & 0x40) == 0) );
238 more = ( (value != 0) || ((byte & 0x40) != 0) );
241 fData.push_back(byte);
246 void append_string(const char* str) {
247 for (const char* s = str; *s != '\0'; ++s)
249 fData.push_back('\0');
252 void append_byte(uint8_t byte) {
253 fData.push_back(byte);
256 static unsigned int uleb128_size(uint64_t value) {
261 } while ( value != 0 );
265 void pad_to_size(unsigned int alignment) {
266 while ( (fData.size() % alignment) != 0 )
272 template <typename A>
273 class Writer : public ExecutableFile::Writer
276 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
279 virtual const char* getPath() { return fFilePath; }
280 virtual time_t getModificationTime() { return 0; }
281 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
282 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
283 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
284 virtual std::vector<Stab>* getStabs() { return NULL; }
286 virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint,
287 bool objcReplacementClasses);
288 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
289 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
290 std::vector<class ObjectFile::Reader::Stab>& stabs,
291 class ObjectFile::Atom* entryPointAtom,
292 class ObjectFile::Atom* dyldClassicHelperAtom,
293 class ObjectFile::Atom* dyldCompressedHelperAtom,
294 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
295 bool createUUID, bool canScatter,
296 ObjectFile::Reader::CpuConstraint cpuConstraint,
297 bool biggerThanTwoGigs,
298 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
299 bool hasExternalWeakDefinitions);
302 typedef typename A::P P;
303 typedef typename A::P::uint_t pint_t;
305 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
307 void assignFileOffsets();
308 void synthesizeStubs();
309 void synthesizeKextGOT();
310 void createSplitSegContent();
311 void synthesizeUnwindInfoTable();
312 void insertDummyStubs();
313 void partitionIntoSections();
314 bool addBranchIslands();
315 bool addPPCBranchIslands();
316 bool isBranch24Reference(uint8_t kind);
317 void adjustLoadCommandsAndPadding();
318 void createDynamicLinkerCommand();
319 void createDylibCommands();
320 void buildLinkEdit();
321 const char* getArchString();
323 uint64_t writeAtoms();
324 void writeNoOps(int fd, uint32_t from, uint32_t to);
325 void copyNoOps(uint8_t* from, uint8_t* to);
326 bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
327 void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
328 void collectExportedAndImportedAndLocalAtoms();
329 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
330 void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
331 void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
332 void buildSymbolTable();
333 bool stringsNeedLabelsInObjects();
334 const char* symbolTableName(const ObjectFile::Atom* atom);
335 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
336 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
337 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
338 void copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
339 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
340 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
341 bool targetRequiresWeakBinding(const ObjectFile::Atom& target);
342 int compressedOrdinalForImortedAtom(ObjectFile::Atom* target);
343 bool shouldExport(const ObjectFile::Atom& atom) const;
345 void adjustLinkEditSections();
346 void buildObjectFileFixups();
347 void buildExecutableFixups();
348 bool preboundLazyPointerType(uint8_t* type);
349 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
350 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
351 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
352 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
353 uint8_t buffer[], bool finalLinkedImage) const;
354 uint32_t symbolIndex(ObjectFile::Atom& atom);
355 bool makesExternalRelocatableReference(ObjectFile::Atom& target) const;
356 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
357 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
358 uint8_t getRelocPointerSize();
359 uint64_t maxAddress();
360 bool stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref);
361 bool GOTReferenceKind(uint8_t kind);
362 bool optimizableGOTReferenceKind(uint8_t kind);
363 bool weakImportReferenceKind(uint8_t kind);
364 unsigned int collectStabs();
365 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
366 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
367 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
368 void addStabs(uint32_t startIndex);
369 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
370 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
371 bool generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
372 bool generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
373 bool mightNeedPadSegment();
374 void scanForAbsoluteReferences();
375 bool needsModuleTable();
376 void optimizeDylibReferences();
377 bool indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const;
379 struct DirectLibrary {
380 class ObjectFile::Reader* fLibrary;
385 friend class WriterAtom<A>;
386 friend class PageZeroAtom<A>;
387 friend class CustomStackAtom<A>;
388 friend class MachHeaderAtom<A>;
389 friend class SegmentLoadCommandsAtom<A>;
390 friend class EncryptionLoadCommandsAtom<A>;
391 friend class SymbolTableLoadCommandsAtom<A>;
392 friend class DyldInfoLoadCommandsAtom<A>;
393 friend class ThreadsLoadCommandsAtom<A>;
394 friend class DylibIDLoadCommandsAtom<A>;
395 friend class RoutinesLoadCommandsAtom<A>;
396 friend class DyldLoadCommandsAtom<A>;
397 friend class UUIDLoadCommandAtom<A>;
398 friend class LinkEditAtom<A>;
399 friend class SectionRelocationsLinkEditAtom<A>;
400 friend class CompressedRebaseInfoLinkEditAtom<A>;
401 friend class CompressedBindingInfoLinkEditAtom<A>;
402 friend class CompressedWeakBindingInfoLinkEditAtom<A>;
403 friend class CompressedLazyBindingInfoLinkEditAtom<A>;
404 friend class CompressedExportInfoLinkEditAtom<A>;
405 friend class LocalRelocationsLinkEditAtom<A>;
406 friend class ExternalRelocationsLinkEditAtom<A>;
407 friend class SymbolTableLinkEditAtom<A>;
408 friend class SegmentSplitInfoLoadCommandsAtom<A>;
409 friend class SegmentSplitInfoContentAtom<A>;
410 friend class IndirectTableLinkEditAtom<A>;
411 friend class ModuleInfoLinkEditAtom<A>;
412 friend class StringsLinkEditAtom<A>;
413 friend class LoadCommandsPaddingAtom<A>;
414 friend class UnwindInfoAtom<A>;
415 friend class StubAtom<A>;
416 friend class StubHelperAtom<A>;
417 friend class ClassicStubHelperAtom<A>;
418 friend class HybridStubHelperAtom<A>;
419 friend class FastStubHelperAtom<A>;
420 friend class FastStubHelperHelperAtom<A>;
421 friend class HybridStubHelperHelperAtom<A>;
422 friend class LazyPointerAtom<A>;
423 friend class NonLazyPointerAtom<A>;
424 friend class DylibLoadCommandsAtom<A>;
426 const char* fFilePath;
428 std::vector<class ObjectFile::Atom*>* fAllAtoms;
429 std::vector<class ObjectFile::Reader::Stab>* fStabs;
430 std::set<const class ObjectFile::Atom*>* fRegularDefAtomsThatOverrideADylibsWeakDef;
431 class SectionInfo* fLoadCommandsSection;
432 class SegmentInfo* fLoadCommandsSegment;
433 class MachHeaderAtom<A>* fMachHeaderAtom;
434 class EncryptionLoadCommandsAtom<A>* fEncryptionLoadCommand;
435 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
436 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
437 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
438 class UnwindInfoAtom<A>* fUnwindInfoAtom;
439 class UUIDLoadCommandAtom<A>* fUUIDAtom;
440 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
441 std::vector<SegmentInfo*> fSegmentInfos;
442 class SegmentInfo* fPadSegmentInfo;
443 class ObjectFile::Atom* fEntryPoint;
444 class ObjectFile::Atom* fDyldClassicHelperAtom;
445 class ObjectFile::Atom* fDyldCompressedHelperAtom;
446 class ObjectFile::Atom* fDyldLazyDylibHelper;
447 std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*> fLibraryToLoadCommand;
448 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
449 std::map<class ObjectFile::Reader*, class ObjectFile::Reader*> fLibraryAliases;
450 std::set<class ObjectFile::Reader*> fForcedWeakImportReaders;
451 std::vector<class ObjectFile::Atom*> fExportedAtoms;
452 std::vector<class ObjectFile::Atom*> fImportedAtoms;
453 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
454 std::vector<macho_nlist<P> > fLocalExtraLabels;
455 std::vector<macho_nlist<P> > fGlobalExtraLabels;
456 std::map<ObjectFile::Atom*, uint32_t> fAtomToSymbolIndex;
457 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
458 class CompressedRebaseInfoLinkEditAtom<A>* fCompressedRebaseInfoAtom;
459 class CompressedBindingInfoLinkEditAtom<A>* fCompressedBindingInfoAtom;
460 class CompressedWeakBindingInfoLinkEditAtom<A>* fCompressedWeakBindingInfoAtom;
461 class CompressedLazyBindingInfoLinkEditAtom<A>* fCompressedLazyBindingInfoAtom;
462 class CompressedExportInfoLinkEditAtom<A>* fCompressedExportInfoAtom;
463 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
464 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
465 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
466 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
467 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
468 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
469 class StringsLinkEditAtom<A>* fStringsAtom;
470 class PageZeroAtom<A>* fPageZeroAtom;
471 class NonLazyPointerAtom<A>* fFastStubGOTAtom;
472 macho_nlist<P>* fSymbolTable;
473 std::vector<macho_relocation_info<P> > fSectionRelocs;
474 std::vector<macho_relocation_info<P> > fInternalRelocs;
475 std::vector<macho_relocation_info<P> > fExternalRelocs;
476 std::vector<RebaseInfo> fRebaseInfo;
477 std::vector<BindingInfo> fBindingInfo;
478 std::vector<BindingInfo> fWeakBindingInfo;
479 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
480 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
481 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
482 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
483 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
484 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyDylibPointers;
485 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
486 uint32_t fSymbolTableCount;
487 uint32_t fSymbolTableStabsCount;
488 uint32_t fSymbolTableStabsStartIndex;
489 uint32_t fSymbolTableLocalCount;
490 uint32_t fSymbolTableLocalStartIndex;
491 uint32_t fSymbolTableExportCount;
492 uint32_t fSymbolTableExportStartIndex;
493 uint32_t fSymbolTableImportCount;
494 uint32_t fSymbolTableImportStartIndex;
495 uint32_t fLargestAtomSize;
496 bool fEmitVirtualSections;
497 bool fHasWeakExports;
498 bool fReferencesWeakImports;
500 bool fWritableSegmentPastFirst4GB;
501 bool fNoReExportedDylibs;
502 bool fBiggerThanTwoGigs;
504 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
505 std::set<const ObjectFile::Reader*> fDylibReadersWithNonWeakImports;
506 std::set<const ObjectFile::Reader*> fDylibReadersWithWeakImports;
507 SegmentInfo* fFirstWritableSegment;
508 ObjectFile::Reader::CpuConstraint fCpuConstraint;
509 uint32_t fAnonNameIndex;
513 class Segment : public ObjectFile::Segment
516 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
517 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
518 virtual const char* getName() const { return fName; }
519 virtual bool isContentReadable() const { return fReadable; }
520 virtual bool isContentWritable() const { return fWritable; }
521 virtual bool isContentExecutable() const { return fExecutable; }
522 virtual bool hasFixedAddress() const { return fFixedAddress; }
524 static Segment fgTextSegment;
525 static Segment fgPageZeroSegment;
526 static Segment fgLinkEditSegment;
527 static Segment fgStackSegment;
528 static Segment fgImportSegment;
529 static Segment fgROImportSegment;
530 static Segment fgDataSegment;
531 static Segment fgObjCSegment;
532 static Segment fgHeaderSegment;
537 const bool fReadable;
538 const bool fWritable;
539 const bool fExecutable;
540 const bool fFixedAddress;
543 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
544 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
545 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
546 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
547 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
548 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
549 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
550 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
551 Segment Segment::fgHeaderSegment("__HEADER", true, false, true, false);
554 template <typename A>
555 class WriterAtom : public ObjectFile::Atom
558 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
559 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
561 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
562 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
563 virtual const char* getName() const { return NULL; }
564 virtual const char* getDisplayName() const { return this->getName(); }
565 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
566 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
567 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
568 virtual bool dontDeadStrip() const { return true; }
569 virtual bool isZeroFill() const { return false; }
570 virtual bool isThumb() const { return false; }
571 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
572 virtual bool mustRemainInSection() const { return true; }
573 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
574 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
575 virtual uint32_t getOrdinal() const { return 0; }
576 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
577 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
578 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
579 virtual void setScope(Scope) { }
583 virtual ~WriterAtom() {}
584 typedef typename A::P P;
585 typedef typename A::P::E E;
587 static Segment& headerSegment(Writer<A>& writer) { return (writer.fOptions.outputKind()==Options::kPreload)
588 ? Segment::fgHeaderSegment : Segment::fgTextSegment; }
590 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
596 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
599 template <typename A>
600 class PageZeroAtom : public WriterAtom<A>
603 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
604 fSize(fWriter.fOptions.zeroPageSize()) {}
605 virtual const char* getDisplayName() const { return "page zero content"; }
606 virtual bool isZeroFill() const { return true; }
607 virtual uint64_t getSize() const { return fSize; }
608 virtual const char* getSectionName() const { return "._zeropage"; }
609 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
610 void setSize(uint64_t size) { fSize = size; }
612 using WriterAtom<A>::fWriter;
613 typedef typename A::P P;
618 template <typename A>
619 class DsoHandleAtom : public WriterAtom<A>
622 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
623 virtual const char* getName() const { return "___dso_handle"; }
624 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
625 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
626 virtual uint64_t getSize() const { return 0; }
627 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
628 virtual const char* getSectionName() const { return "._mach_header"; }
629 virtual void copyRawContent(uint8_t buffer[]) const {}
633 template <typename A>
634 class MachHeaderAtom : public WriterAtom<A>
637 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)) {}
638 virtual const char* getName() const;
639 virtual const char* getDisplayName() const;
640 virtual ObjectFile::Atom::Scope getScope() const;
641 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
642 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
643 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
644 virtual const char* getSectionName() const { return "._mach_header"; }
645 virtual uint32_t getOrdinal() const { return 1; }
646 virtual void copyRawContent(uint8_t buffer[]) const;
648 using WriterAtom<A>::fWriter;
649 typedef typename A::P P;
650 void setHeaderInfo(macho_header<typename A::P>& header) const;
653 template <typename A>
654 class CustomStackAtom : public WriterAtom<A>
657 CustomStackAtom(Writer<A>& writer);
658 virtual const char* getDisplayName() const { return "custom stack content"; }
659 virtual bool isZeroFill() const { return true; }
660 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
661 virtual const char* getSectionName() const { return "._stack"; }
662 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
664 using WriterAtom<A>::fWriter;
665 typedef typename A::P P;
666 static bool stackGrowsDown();
669 template <typename A>
670 class LoadCommandAtom : public WriterAtom<A>
673 LoadCommandAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)), fOrdinal(fgCurrentOrdinal++) {}
674 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
675 virtual const char* getSectionName() const { return "._load_commands"; }
676 virtual uint32_t getOrdinal() const { return fOrdinal; }
677 static uint64_t alignedSize(uint64_t size);
680 static uint32_t fgCurrentOrdinal;
683 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
685 template <typename A>
686 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
689 SegmentLoadCommandsAtom(Writer<A>& writer)
690 : LoadCommandAtom<A>(writer), fCommandCount(0), fSize(0)
691 { writer.fSegmentCommands = this; }
692 virtual const char* getDisplayName() const { return "segment load commands"; }
693 virtual uint64_t getSize() const { return fSize; }
694 virtual void copyRawContent(uint8_t buffer[]) const;
698 unsigned int commandCount() { return fCommandCount; }
700 using WriterAtom<A>::fWriter;
701 typedef typename A::P P;
702 unsigned int fCommandCount;
707 template <typename A>
708 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
711 SymbolTableLoadCommandsAtom(Writer<A>&);
712 virtual const char* getDisplayName() const { return "symbol table load commands"; }
713 virtual uint64_t getSize() const;
714 virtual void copyRawContent(uint8_t buffer[]) const;
715 unsigned int commandCount();
716 void needDynamicTable();
718 using WriterAtom<A>::fWriter;
719 typedef typename A::P P;
720 bool fNeedsDynamicSymbolTable;
721 macho_symtab_command<typename A::P> fSymbolTable;
722 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
725 template <typename A>
726 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
729 ThreadsLoadCommandsAtom(Writer<A>& writer)
730 : LoadCommandAtom<A>(writer) {}
731 virtual const char* getDisplayName() const { return "thread load commands"; }
732 virtual uint64_t getSize() const;
733 virtual void copyRawContent(uint8_t buffer[]) const;
735 using WriterAtom<A>::fWriter;
736 typedef typename A::P P;
738 uint32_t fBufferSize;
741 template <typename A>
742 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
745 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
746 virtual const char* getDisplayName() const { return "dyld load command"; }
747 virtual uint64_t getSize() const;
748 virtual void copyRawContent(uint8_t buffer[]) const;
750 using WriterAtom<A>::fWriter;
751 typedef typename A::P P;
754 template <typename A>
755 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
758 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
759 virtual const char* getDisplayName() const { return "segment split info load command"; }
760 virtual uint64_t getSize() const;
761 virtual void copyRawContent(uint8_t buffer[]) const;
763 using WriterAtom<A>::fWriter;
764 typedef typename A::P P;
767 template <typename A>
768 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
771 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
772 LoadCommandAtom<A>(writer), clientString(client) {}
773 virtual const char* getDisplayName() const { return "allowable_client load command"; }
774 virtual uint64_t getSize() const;
775 virtual void copyRawContent(uint8_t buffer[]) const;
777 using WriterAtom<A>::fWriter;
778 typedef typename A::P P;
779 const char* clientString;
782 template <typename A>
783 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
786 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
787 : LoadCommandAtom<A>(writer), fInfo(info),
788 fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
789 virtual const char* getDisplayName() const { return "dylib load command"; }
790 virtual uint64_t getSize() const;
791 virtual void copyRawContent(uint8_t buffer[]) const;
792 virtual void optimizeAway() { fOptimizedAway = true; }
793 bool linkedWeak() { return fInfo.options.fWeakImport; }
795 using WriterAtom<A>::fWriter;
796 typedef typename A::P P;
797 ExecutableFile::DyLibUsed fInfo;
801 template <typename A>
802 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
805 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
806 virtual const char* getDisplayName() const { return "dylib ID load command"; }
807 virtual uint64_t getSize() const;
808 virtual void copyRawContent(uint8_t buffer[]) const;
810 using WriterAtom<A>::fWriter;
811 typedef typename A::P P;
814 template <typename A>
815 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
818 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
819 virtual const char* getDisplayName() const { return "routines load command"; }
820 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
821 virtual void copyRawContent(uint8_t buffer[]) const;
823 using WriterAtom<A>::fWriter;
824 typedef typename A::P P;
827 template <typename A>
828 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
831 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
832 : LoadCommandAtom<A>(writer), fName(name) {}
833 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
834 virtual uint64_t getSize() const;
835 virtual void copyRawContent(uint8_t buffer[]) const;
837 typedef typename A::P P;
841 template <typename A>
842 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
845 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
846 : LoadCommandAtom<A>(writer), fNameStart(nameStart), fNameLength(nameLen) {}
847 virtual const char* getDisplayName() const { return "sub-library load command"; }
848 virtual uint64_t getSize() const;
849 virtual void copyRawContent(uint8_t buffer[]) const;
851 using WriterAtom<A>::fWriter;
852 typedef typename A::P P;
853 const char* fNameStart;
857 template <typename A>
858 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
861 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
862 : LoadCommandAtom<A>(writer), fName(name) {}
863 virtual const char* getDisplayName() const { return "umbrella load command"; }
864 virtual uint64_t getSize() const;
865 virtual void copyRawContent(uint8_t buffer[]) const;
867 using WriterAtom<A>::fWriter;
868 typedef typename A::P P;
872 template <typename A>
873 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
876 UUIDLoadCommandAtom(Writer<A>& writer)
877 : LoadCommandAtom<A>(writer), fEmit(false) {}
878 virtual const char* getDisplayName() const { return "uuid load command"; }
879 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
880 virtual void copyRawContent(uint8_t buffer[]) const;
881 virtual void generate();
882 void setContent(const uint8_t uuid[16]);
883 const uint8_t* getUUID() { return fUUID; }
885 using WriterAtom<A>::fWriter;
886 typedef typename A::P P;
892 template <typename A>
893 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
896 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
897 : LoadCommandAtom<A>(writer), fPath(path) {}
898 virtual const char* getDisplayName() const { return "rpath load command"; }
899 virtual uint64_t getSize() const;
900 virtual void copyRawContent(uint8_t buffer[]) const;
902 using WriterAtom<A>::fWriter;
903 typedef typename A::P P;
907 template <typename A>
908 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
911 EncryptionLoadCommandsAtom(Writer<A>& writer)
912 : LoadCommandAtom<A>(writer), fStartOffset(0),
914 virtual const char* getDisplayName() const { return "encryption info load command"; }
915 virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
916 virtual void copyRawContent(uint8_t buffer[]) const;
917 void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
918 void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
920 using WriterAtom<A>::fWriter;
921 typedef typename A::P P;
922 uint32_t fStartOffset;
926 template <typename A>
927 class DyldInfoLoadCommandsAtom : public LoadCommandAtom<A>
930 DyldInfoLoadCommandsAtom(Writer<A>& writer)
931 : LoadCommandAtom<A>(writer) {}
932 virtual const char* getDisplayName() const { return "dyld info load command"; }
933 virtual uint64_t getSize() const { return sizeof(macho_dyld_info_command<typename A::P>); }
934 virtual void copyRawContent(uint8_t buffer[]) const;
936 using WriterAtom<A>::fWriter;
937 typedef typename A::P P;
941 template <typename A>
942 class LoadCommandsPaddingAtom : public WriterAtom<A>
945 LoadCommandsPaddingAtom(Writer<A>& writer)
946 : WriterAtom<A>(writer, headerSegment(writer)), fSize(0) {}
947 virtual const char* getDisplayName() const { return "header padding"; }
948 virtual uint64_t getSize() const { return fSize; }
949 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
950 virtual void copyRawContent(uint8_t buffer[]) const;
952 void setSize(uint64_t newSize);
954 using WriterAtom<A>::fWriter;
955 typedef typename A::P P;
959 template <typename A>
960 class UnwindInfoAtom : public WriterAtom<A>
963 UnwindInfoAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment),
964 fHeaderSize(0), fPagesSize(0), fAlignment(4) {}
965 virtual const char* getName() const { return "unwind info"; }
966 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
967 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
968 virtual uint64_t getSize() const { return fHeaderSize+fPagesSize; }
969 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
970 virtual const char* getSectionName() const { return "__unwind_info"; }
971 virtual uint32_t getOrdinal() const { return 1; }
972 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)fReferences; }
973 virtual void copyRawContent(uint8_t buffer[]) const;
975 void addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
976 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsda,
977 ObjectFile::Atom* personalityPointer);
981 using WriterAtom<A>::fWriter;
982 typedef typename A::P P;
983 struct Info { ObjectFile::Atom* func; ObjectFile::Atom* fde; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; };
984 struct LSDAEntry { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; };
985 struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fde; };
986 struct CompressedFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fromFunc; };
987 struct CompressedEncodingFixUp { uint8_t* contentPointer; ObjectFile::Atom* fde; };
989 bool encodingMeansUseDwarf(compact_unwind_encoding_t encoding);
990 void compressDuplicates(std::vector<Info>& uniqueInfos);
991 void findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings);
992 void makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap);
993 unsigned int makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize, unsigned int endIndex,
995 unsigned int makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
996 const std::map<uint32_t,unsigned int> commonEncodings,
997 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
998 void makePersonalityIndex(std::vector<Info>& uniqueInfos);
1001 uint32_t fHeaderSize;
1002 uint32_t fPagesSize;
1003 uint8_t* fHeaderContent;
1004 uint8_t* fPagesContent;
1005 uint8_t* fPagesContentForDelete;
1006 ObjectFile::Alignment fAlignment;
1007 std::vector<Info> fInfos;
1008 std::map<ObjectFile::Atom*, uint32_t> fPersonalityIndexMap;
1009 std::vector<LSDAEntry> fLSDAIndex;
1010 std::vector<RegFixUp> fRegFixUps;
1011 std::vector<CompressedFixUp> fCompressedFixUps;
1012 std::vector<CompressedEncodingFixUp> fCompressedEncodingFixUps;
1013 std::vector<ObjectFile::Reference*> fReferences;
1018 template <typename A>
1019 class LinkEditAtom : public WriterAtom<A>
1022 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
1023 uint64_t getFileOffset() const;
1024 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
1025 virtual uint32_t getOrdinal() const { return fOrdinal; }
1028 static uint32_t fgCurrentOrdinal;
1030 typedef typename A::P P;
1033 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
1035 template <typename A>
1036 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
1039 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1040 virtual const char* getDisplayName() const { return "section relocations"; }
1041 virtual uint64_t getSize() const;
1042 virtual const char* getSectionName() const { return "._section_relocs"; }
1043 virtual void copyRawContent(uint8_t buffer[]) const;
1045 using WriterAtom<A>::fWriter;
1046 typedef typename A::P P;
1049 template <typename A>
1050 class CompressedInfoLinkEditAtom : public LinkEditAtom<A>
1053 CompressedInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1054 virtual uint64_t getSize() const { return fEncodedData.size(); }
1055 virtual void copyRawContent(uint8_t buffer[]) const { memcpy(buffer, fEncodedData.start(), fEncodedData.size()); }
1057 typedef typename A::P::uint_t pint_t;
1058 ByteStream fEncodedData;
1060 using WriterAtom<A>::fWriter;
1061 typedef typename A::P P;
1066 template <typename A>
1067 class CompressedRebaseInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1070 CompressedRebaseInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1071 virtual const char* getDisplayName() const { return "compressed rebase info"; }
1072 virtual const char* getSectionName() const { return "._rebase info"; }
1075 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1076 using CompressedInfoLinkEditAtom<A>::fWriter;
1077 typedef typename A::P P;
1078 typedef typename A::P::uint_t pint_t;
1081 template <typename A>
1082 class CompressedBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1085 CompressedBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1086 virtual const char* getDisplayName() const { return "compressed binding info"; }
1087 virtual const char* getSectionName() const { return "._binding info"; }
1090 using CompressedInfoLinkEditAtom<A>::fWriter;
1091 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1092 typedef typename A::P P;
1093 typedef typename A::P::uint_t pint_t;
1096 template <typename A>
1097 class CompressedWeakBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1100 CompressedWeakBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1101 virtual const char* getDisplayName() const { return "compressed weak binding info"; }
1102 virtual const char* getSectionName() const { return "._wkbinding info"; }
1105 using CompressedInfoLinkEditAtom<A>::fWriter;
1106 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1107 typedef typename A::P P;
1108 typedef typename A::P::uint_t pint_t;
1111 template <typename A>
1112 class CompressedLazyBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1115 CompressedLazyBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1116 virtual const char* getDisplayName() const { return "compressed lazy binding info"; }
1117 virtual const char* getSectionName() const { return "._lzbinding info"; }
1120 std::vector<uint32_t> fStarts;
1122 using CompressedInfoLinkEditAtom<A>::fWriter;
1123 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1124 typedef typename A::P P;
1125 typedef typename A::P::uint_t pint_t;
1129 template <typename A>
1130 class CompressedExportInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1133 CompressedExportInfoLinkEditAtom(Writer<A>& writer)
1134 : CompressedInfoLinkEditAtom<A>(writer), fStartNode(strdup("")) { }
1135 virtual const char* getDisplayName() const { return "compressed export info"; }
1136 virtual const char* getSectionName() const { return "._export info"; }
1139 using WriterAtom<A>::fWriter;
1140 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1141 typedef typename A::P P;
1142 typedef typename A::P::uint_t pint_t;
1147 edge(const char* s, struct node* n) : fSubString(s), fChild(n) { }
1149 const char* fSubString;
1150 struct node* fChild;
1156 node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false),
1157 fHaveExportInfo(false), fTrieOffset(0) {}
1159 const char* fCummulativeString;
1160 std::vector<edge> fChildren;
1164 bool fHaveExportInfo;
1165 uint32_t fTrieOffset;
1167 void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
1168 const char* partialStr = &fullStr[strlen(fCummulativeString)];
1169 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1171 int subStringLen = strlen(e.fSubString);
1172 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1173 // already have matching edge, go down that path
1174 e.fChild->addSymbol(fullStr, address, flags);
1178 for (int i=subStringLen-1; i > 0; --i) {
1179 if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
1180 // found a common substring, splice in new node
1181 // was A -> C, now A -> B -> C
1182 char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
1183 bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
1184 //node* aNode = this;
1185 node* bNode = new node(bNodeCummStr);
1186 node* cNode = e.fChild;
1187 char* abEdgeStr = strdup(e.fSubString);
1188 abEdgeStr[i] = '\0';
1189 char* bcEdgeStr = strdup(&e.fSubString[i]);
1191 abEdge.fSubString = abEdgeStr;
1192 abEdge.fChild = bNode;
1193 edge bcEdge(bcEdgeStr, cNode);
1194 bNode->fChildren.push_back(bcEdge);
1195 bNode->addSymbol(fullStr, address, flags);
1201 // no commonality with any existing child, make a new edge that is this whole string
1202 node* newNode = new node(strdup(fullStr));
1203 edge newEdge(strdup(partialStr), newNode);
1204 fChildren.push_back(newEdge);
1205 newNode->fAddress = address;
1206 newNode->fFlags = flags;
1207 newNode->fHaveExportInfo = true;
1210 void addOrderedNodes(const char* name, std::vector<node*>& orderedNodes) {
1212 orderedNodes.push_back(this);
1213 //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
1216 const char* partialStr = &name[strlen(fCummulativeString)];
1217 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1219 int subStringLen = strlen(e.fSubString);
1220 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1221 // already have matching edge, go down that path
1222 e.fChild->addOrderedNodes(name, orderedNodes);
1228 // byte for terminal node size in bytes, or 0x00 if not terminal node
1229 // teminal node (uleb128 flags, uleb128 addr)
1230 // byte for child node count
1231 // each child: zero terminated substring, uleb128 node offset
1232 bool updateOffset(uint32_t& offset) {
1233 uint32_t nodeSize = 1; // byte for length of export info
1234 if ( fHaveExportInfo )
1235 nodeSize += ByteStream::uleb128_size(fFlags) + ByteStream::uleb128_size(fAddress);
1238 ++nodeSize; // byte for count of chidren
1239 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1241 nodeSize += strlen(e.fSubString) + 1 + ByteStream::uleb128_size(e.fChild->fTrieOffset);
1243 bool result = (fTrieOffset != offset);
1244 fTrieOffset = offset;
1245 //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
1247 // return true if fTrieOffset was changed
1251 void appendToStream(ByteStream& out) {
1252 if ( fHaveExportInfo ) {
1253 // nodes with export info: size, flags, address
1254 out.append_byte(out.uleb128_size(fFlags) + out.uleb128_size(fAddress));
1255 out.append_uleb128(fFlags);
1256 out.append_uleb128(fAddress);
1262 // write number of children
1263 out.append_byte(fChildren.size());
1265 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1267 out.append_string(e.fSubString);
1268 out.append_uleb128(e.fChild->fTrieOffset);
1275 struct node fStartNode;
1278 template <typename A>
1279 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
1282 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1283 virtual const char* getDisplayName() const { return "local relocations"; }
1284 virtual uint64_t getSize() const;
1285 virtual const char* getSectionName() const { return "._local_relocs"; }
1286 virtual void copyRawContent(uint8_t buffer[]) const;
1288 using WriterAtom<A>::fWriter;
1289 typedef typename A::P P;
1292 template <typename A>
1293 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
1296 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1297 virtual const char* getDisplayName() const { return "symbol table"; }
1298 virtual uint64_t getSize() const;
1299 virtual const char* getSectionName() const { return "._symbol_table"; }
1300 virtual void copyRawContent(uint8_t buffer[]) const;
1302 using WriterAtom<A>::fWriter;
1303 typedef typename A::P P;
1306 template <typename A>
1307 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
1310 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1311 virtual const char* getDisplayName() const { return "external relocations"; }
1312 virtual uint64_t getSize() const;
1313 virtual const char* getSectionName() const { return "._extern_relocs"; }
1314 virtual void copyRawContent(uint8_t buffer[]) const;
1316 using WriterAtom<A>::fWriter;
1317 typedef typename A::P P;
1320 struct IndirectEntry {
1321 uint32_t indirectIndex;
1322 uint32_t symbolIndex;
1326 template <typename A>
1327 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
1330 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
1331 virtual const char* getDisplayName() const { return "split segment info"; }
1332 virtual uint64_t getSize() const;
1333 virtual const char* getSectionName() const { return "._split_info"; }
1334 virtual void copyRawContent(uint8_t buffer[]) const;
1335 bool canEncode() { return !fCantEncode; }
1336 void setCantEncode() { fCantEncode = true; }
1337 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
1338 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
1339 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
1340 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
1344 using WriterAtom<A>::fWriter;
1345 typedef typename A::P P;
1346 typedef typename A::P::uint_t pint_t;
1347 struct AtomAndOffset {
1348 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
1349 const ObjectFile::Atom* atom;
1352 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
1354 std::vector<AtomAndOffset> fKind1Locations;
1355 std::vector<AtomAndOffset> fKind2Locations;
1356 std::vector<AtomAndOffset> fKind3Locations;
1357 std::vector<AtomAndOffset> fKind4Locations;
1358 std::vector<uint8_t> fEncodedData;
1362 template <typename A>
1363 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
1366 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1367 virtual const char* getDisplayName() const { return "indirect symbol table"; }
1368 virtual uint64_t getSize() const;
1369 virtual const char* getSectionName() const { return "._indirect_syms"; }
1370 virtual void copyRawContent(uint8_t buffer[]) const;
1372 std::vector<IndirectEntry> fTable;
1375 using WriterAtom<A>::fWriter;
1376 typedef typename A::P P;
1379 template <typename A>
1380 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
1383 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
1384 virtual const char* getDisplayName() const { return "module table"; }
1385 virtual uint64_t getSize() const;
1386 virtual const char* getSectionName() const { return "._module_info"; }
1387 virtual void copyRawContent(uint8_t buffer[]) const;
1389 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
1390 uint32_t getTableOfContentsFileOffset() const;
1391 uint32_t getModuleTableFileOffset() const;
1392 uint32_t getReferencesFileOffset() const;
1393 uint32_t getReferencesCount() const;
1396 using WriterAtom<A>::fWriter;
1397 typedef typename A::P P;
1398 typedef typename A::P::uint_t pint_t;
1399 uint32_t fModuleNameOffset;
1406 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
1409 template <typename A>
1410 class StringsLinkEditAtom : public LinkEditAtom<A>
1413 StringsLinkEditAtom(Writer<A>& writer);
1414 virtual const char* getDisplayName() const { return "string pool"; }
1415 virtual uint64_t getSize() const;
1416 virtual const char* getSectionName() const { return "._string_pool"; }
1417 virtual void copyRawContent(uint8_t buffer[]) const;
1419 int32_t add(const char* name);
1420 int32_t addUnique(const char* name);
1421 int32_t emptyString() { return 1; }
1422 const char* stringForIndex(int32_t) const;
1425 using WriterAtom<A>::fWriter;
1426 typedef typename A::P P;
1427 enum { kBufferSize = 0x01000000 };
1428 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
1430 std::vector<char*> fFullBuffers;
1431 char* fCurrentBuffer;
1432 uint32_t fCurrentBufferUsed;
1433 StringToOffset fUniqueStrings;
1438 template <typename A>
1439 class UndefinedSymbolProxyAtom : public WriterAtom<A>
1442 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
1443 virtual const char* getName() const { return fName; }
1444 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
1445 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
1446 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1447 virtual uint64_t getSize() const { return 0; }
1448 virtual const char* getSectionName() const { return "._imports"; }
1450 using WriterAtom<A>::fWriter;
1451 typedef typename A::P P;
1455 template <typename A>
1456 class BranchIslandAtom : public WriterAtom<A>
1459 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
1460 virtual const char* getName() const { return fName; }
1461 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1462 virtual uint64_t getSize() const;
1463 virtual const char* getSectionName() const { return "__text"; }
1464 virtual void copyRawContent(uint8_t buffer[]) const;
1466 using WriterAtom<A>::fWriter;
1468 ObjectFile::Atom& fTarget;
1469 uint32_t fTargetOffset;
1472 template <typename A>
1473 class StubAtom : public WriterAtom<A>
1476 StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
1477 virtual const char* getName() const { return fName; }
1478 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1479 virtual uint64_t getSize() const;
1480 virtual ObjectFile::Alignment getAlignment() const;
1481 virtual const char* getSectionName() const { return "__symbol_stub1"; }
1482 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1483 virtual void copyRawContent(uint8_t buffer[]) const;
1484 ObjectFile::Atom* getTarget() { return &fTarget; }
1486 static const char* stubName(const char* importName);
1487 bool pic() const { return fWriter.fSlideable; }
1488 using WriterAtom<A>::fWriter;
1490 ObjectFile::Atom& fTarget;
1491 std::vector<ObjectFile::Reference*> fReferences;
1496 template <typename A>
1497 class FastStubHelperHelperAtom : public WriterAtom<A>
1500 FastStubHelperHelperAtom(Writer<A>& writer);
1501 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1502 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1503 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1504 virtual uint64_t getSize() const;
1505 virtual const char* getSectionName() const { return "__stub_helper"; }
1506 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1507 virtual void copyRawContent(uint8_t buffer[]) const;
1508 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1510 using WriterAtom<A>::fWriter;
1511 std::vector<ObjectFile::Reference*> fReferences;
1514 template <typename A>
1515 class HybridStubHelperHelperAtom : public WriterAtom<A>
1518 HybridStubHelperHelperAtom(Writer<A>& writer);
1519 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1520 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1521 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1522 virtual uint64_t getSize() const;
1523 virtual const char* getSectionName() const { return "__stub_helper"; }
1524 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1525 virtual void copyRawContent(uint8_t buffer[]) const;
1526 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1528 using WriterAtom<A>::fWriter;
1529 std::vector<ObjectFile::Reference*> fReferences;
1532 template <typename A>
1533 class StubHelperAtom : public WriterAtom<A>
1536 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1537 LazyPointerAtom<A>& lazyPointer, bool forLazyDylib)
1538 : WriterAtom<A>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1539 fTarget(target), fLazyPointerAtom(lazyPointer) {
1540 writer.fAllSynthesizedStubHelpers.push_back(this);
1543 virtual const char* getName() const { return fName; }
1544 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1545 virtual const char* getSectionName() const { return "__stub_helper"; }
1546 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1547 ObjectFile::Atom* getTarget() { return &fTarget; }
1548 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1550 static const char* stubName(const char* importName);
1551 using WriterAtom<A>::fWriter;
1553 ObjectFile::Atom& fTarget;
1554 LazyPointerAtom<A>& fLazyPointerAtom;
1555 std::vector<ObjectFile::Reference*> fReferences;
1558 template <typename A>
1559 class ClassicStubHelperAtom : public StubHelperAtom<A>
1562 ClassicStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1563 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1565 virtual uint64_t getSize() const;
1566 virtual void copyRawContent(uint8_t buffer[]) const;
1570 template <typename A>
1571 class HybridStubHelperAtom : public StubHelperAtom<A>
1574 HybridStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1575 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1577 virtual uint64_t getSize() const;
1578 virtual void copyRawContent(uint8_t buffer[]) const;
1579 static class HybridStubHelperHelperAtom<A>* fgHelperHelperAtom;
1581 template <typename A> class HybridStubHelperHelperAtom<A>* HybridStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1583 template <typename A>
1584 class FastStubHelperAtom : public StubHelperAtom<A>
1587 FastStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1588 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1589 virtual uint64_t getSize() const;
1590 virtual void copyRawContent(uint8_t buffer[]) const;
1591 static FastStubHelperHelperAtom<A>* fgHelperHelperAtom;
1593 template <typename A> FastStubHelperHelperAtom<A>* FastStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1597 template <typename A>
1598 class LazyPointerAtom : public WriterAtom<A>
1601 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target,
1602 StubAtom<A>& stub, bool forLazyDylib);
1603 virtual const char* getName() const { return fName; }
1604 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1605 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1606 virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; }
1607 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1608 virtual void copyRawContent(uint8_t buffer[]) const;
1609 ObjectFile::Atom* getTarget() { return &fExternalTarget; }
1610 void setLazyBindingInfoOffset(uint32_t off) { fLazyBindingOffset = off; }
1611 uint32_t getLazyBindingInfoOffset() { return fLazyBindingOffset; }
1613 using WriterAtom<A>::fWriter;
1614 static const char* lazyPointerName(const char* importName);
1616 ObjectFile::Atom& fTarget;
1617 ObjectFile::Atom& fExternalTarget;
1618 std::vector<ObjectFile::Reference*> fReferences;
1620 uint32_t fLazyBindingOffset;
1624 template <typename A>
1625 class NonLazyPointerAtom : public WriterAtom<A>
1628 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1629 NonLazyPointerAtom(Writer<A>& writer, const char* targetName);
1630 NonLazyPointerAtom(Writer<A>& writer);
1631 virtual const char* getName() const { return fName; }
1632 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1633 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1634 virtual const char* getSectionName() const { return (fWriter.fOptions.outputKind() == Options::kKextBundle) ? "__got" : "__nl_symbol_ptr"; }
1635 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1636 virtual void copyRawContent(uint8_t buffer[]) const;
1637 ObjectFile::Atom* getTarget() { return fTarget; }
1639 using WriterAtom<A>::fWriter;
1640 static const char* nonlazyPointerName(const char* importName);
1642 ObjectFile::Atom* fTarget;
1643 std::vector<ObjectFile::Reference*> fReferences;
1647 template <typename A>
1648 class ObjCInfoAtom : public WriterAtom<A>
1651 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1652 bool objcReplacementClasses);
1653 virtual const char* getName() const { return "objc$info"; }
1654 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1655 virtual uint64_t getSize() const { return 8; }
1656 virtual const char* getSectionName() const;
1657 virtual void copyRawContent(uint8_t buffer[]) const;
1659 Segment& getInfoSegment() const;
1660 uint32_t fContent[2];
1664 template <typename A>
1665 class WriterReference : public ObjectFile::Reference
1668 typedef typename A::ReferenceKinds Kinds;
1670 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1671 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1672 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target), fTargetName(target->getName()),
1673 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1674 WriterReference(uint32_t offset, Kinds kind, const char* targetName)
1675 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(NULL), fTargetName(targetName),
1676 fTargetOffset(0), fFromTarget(NULL), fFromTargetOffset(0) {}
1678 virtual ~WriterReference() {}
1680 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return (fTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kUnboundByName; }
1681 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1682 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1683 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1684 virtual const char* getTargetName() const { return fTargetName; }
1685 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1686 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1687 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1688 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1689 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = ⌖ fTargetOffset = offset; }
1690 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ }
1691 virtual void setFromTargetName(const char* name) { }
1692 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1693 virtual const char* getDescription() const { return "writer reference"; }
1694 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1698 uint32_t fFixUpOffsetInSrc;
1699 ObjectFile::Atom* fTarget;
1700 const char* fTargetName;
1701 uint32_t fTargetOffset;
1702 ObjectFile::Atom* fFromTarget;
1703 uint32_t fFromTargetOffset;
1707 template <typename A>
1708 const char* StubHelperAtom<A>::stubName(const char* name)
1711 asprintf(&buf, "%s$stubHelper", name);
1716 ClassicStubHelperAtom<x86_64>::ClassicStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1717 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1718 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1720 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &fLazyPointerAtom));
1721 if ( forLazyDylib ) {
1722 if ( fWriter.fDyldLazyDylibHelper == NULL )
1723 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1724 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldLazyDylibHelper));
1727 if ( fWriter.fDyldClassicHelperAtom == NULL )
1728 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1729 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldClassicHelperAtom));
1735 uint64_t ClassicStubHelperAtom<x86_64>::getSize() const
1741 void ClassicStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1743 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1750 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1759 FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(Writer<x86_64>& writer)
1760 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1762 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1763 fReferences.push_back(new WriterReference<x86_64>(11, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1767 uint64_t FastStubHelperHelperAtom<x86_64>::getSize() const
1773 void FastStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1775 buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
1782 buffer[7] = 0x41; // pushq %r11
1784 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1790 buffer[15] = 0x90; // nop
1795 HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(Writer<x86_64>& writer)
1796 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1798 if ( writer.fDyldClassicHelperAtom == NULL )
1799 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1800 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32_1, writer.fFastStubGOTAtom));
1801 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1802 fReferences.push_back(new WriterReference<x86_64>(21, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1803 fReferences.push_back(new WriterReference<x86_64>(30, x86_64::kPCRel32, writer.fDyldClassicHelperAtom));
1807 uint64_t HybridStubHelperHelperAtom<x86_64>::getSize() const
1813 void HybridStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1815 buffer[0] = 0x48; // cmpl $0x00,_fast_lazy_bind
1823 buffer[8] = 0x74; // je 16
1825 buffer[10] = 0x4C; // leaq imageCache(%rip),%r11
1832 buffer[17] = 0x41; // pushq %r11
1834 buffer[19] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1840 buffer[25] = 0x48; // addq $8,%rsp
1844 buffer[29] = 0xE9; // jmp dyld_stub_binding_helper
1853 HybridStubHelperAtom<x86_64>::HybridStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1854 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1855 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1857 if ( fgHelperHelperAtom == NULL ) {
1858 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(fWriter);
1859 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1861 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, &fLazyPointerAtom));
1862 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, fgHelperHelperAtom));
1866 uint64_t HybridStubHelperAtom<x86_64>::getSize() const
1872 void HybridStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1874 buffer[0] = 0x68; // pushq $lazy-info-offset
1879 buffer[5] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1886 buffer[12] = 0xE9; // jmp helper-helper
1891 buffer[17] = 0x90; // nop
1893 // the lazy binding info is created later than this helper atom, so there
1894 // is no Reference to update. Instead we blast the offset here.
1896 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1897 memcpy(&buffer[1], &offset, 4);
1901 FastStubHelperAtom<x86_64>::FastStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1902 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1903 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1905 if ( fgHelperHelperAtom == NULL ) {
1906 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(fWriter);
1907 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1909 fReferences.push_back(new WriterReference<x86_64>(6, x86_64::kPCRel32, fgHelperHelperAtom));
1913 uint64_t FastStubHelperAtom<x86_64>::getSize() const
1919 void FastStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1921 buffer[0] = 0x68; // pushq $lazy-info-offset
1926 buffer[5] = 0xE9; // jmp helperhelper
1932 // the lazy binding info is created later than this helper atom, so there
1933 // is no Reference to update. Instead we blast the offset here.
1935 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1936 memcpy(&buffer[1], &offset, 4);
1940 FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(Writer<x86>& writer)
1941 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1943 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1944 fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, writer.fFastStubGOTAtom));
1948 uint64_t FastStubHelperHelperAtom<x86>::getSize() const
1954 void FastStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1956 buffer[0] = 0x68; // pushl $dyld_ImageLoaderCache
1961 buffer[5] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1967 buffer[11] = 0x90; // nop
1972 HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(Writer<x86>& writer)
1973 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1975 if ( writer.fDyldClassicHelperAtom == NULL )
1976 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1977 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, writer.fFastStubGOTAtom));
1978 fReferences.push_back(new WriterReference<x86>(18, x86::kPCRel32, writer.fDyldClassicHelperAtom));
1979 fReferences.push_back(new WriterReference<x86>(26, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1980 fReferences.push_back(new WriterReference<x86>(32, x86::kAbsolute32, writer.fFastStubGOTAtom));
1984 uint64_t HybridStubHelperHelperAtom<x86>::getSize() const
1991 void HybridStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1993 buffer[0] = 0x83; // cmpl $0x00,_fast_lazy_bind
2000 buffer[7] = 0x75; // jne 22
2002 buffer[9] = 0x89; // %eax,4(%esp)
2006 buffer[13] = 0x58; // popl %eax
2007 buffer[14] = 0x87; // xchgl (%esp),%eax
2010 buffer[17] = 0xE9; // jmpl dyld_stub_binding_helper
2015 buffer[22] = 0x83; // addl $0x04,%esp
2018 buffer[25] = 0x68; // pushl imageloadercahce
2023 buffer[30] = 0xFF; // jmp *_fast_lazy_bind(%rip)
2033 ClassicStubHelperAtom<x86>::ClassicStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2034 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2035 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2037 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, &fLazyPointerAtom));
2038 if ( forLazyDylib ) {
2039 if ( fWriter.fDyldLazyDylibHelper == NULL )
2040 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2041 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldLazyDylibHelper));
2044 if ( fWriter.fDyldClassicHelperAtom == NULL )
2045 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2046 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldClassicHelperAtom));
2051 uint64_t ClassicStubHelperAtom<x86>::getSize() const
2057 void ClassicStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2059 buffer[0] = 0x68; // pushl $foo$lazy_ptr
2064 buffer[5] = 0xE9; // jmp helperhelper
2072 HybridStubHelperAtom<x86>::HybridStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2073 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2074 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2076 if ( fgHelperHelperAtom == NULL ) {
2077 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(fWriter);
2078 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2080 fReferences.push_back(new WriterReference<x86>(6, x86::kAbsolute32, &fLazyPointerAtom));
2081 fReferences.push_back(new WriterReference<x86>(11, x86::kPCRel32, fgHelperHelperAtom));
2086 uint64_t HybridStubHelperAtom<x86>::getSize() const
2092 void HybridStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2094 buffer[0] = 0x68; // pushl $lazy-info-offset
2099 buffer[5] = 0x68; // pushl $foo$lazy_ptr
2104 buffer[10] = 0xE9; // jmp dyld_hybrid_stub_binding_helper
2109 buffer[15] = 0x90; // nop
2111 // the lazy binding info is created later than this helper atom, so there
2112 // is no Reference to update. Instead we blast the offset here.
2114 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2115 memcpy(&buffer[1], &offset, 4);
2120 FastStubHelperAtom<x86>::FastStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2121 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2122 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2124 if ( fgHelperHelperAtom == NULL ) {
2125 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(fWriter);
2126 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2128 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fgHelperHelperAtom));
2133 uint64_t FastStubHelperAtom<x86>::getSize() const
2139 void FastStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2141 buffer[0] = 0x68; // pushl $lazy-info-offset
2146 buffer[5] = 0xE9; // jmp helperhelper
2152 // the lazy binding info is created later than this helper atom, so there
2153 // is no Reference to update. Instead we blast the offset here.
2155 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2156 memcpy(&buffer[1], &offset, 4);
2161 // specialize lazy pointer for x86_64 to initially pointer to stub helper
2163 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
2164 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2165 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fLazyBindingOffset(0)
2168 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2170 writer.fAllSynthesizedLazyPointers.push_back(this);
2172 ObjectFile::Atom* helper;
2173 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2174 if ( writer.fOptions.makeClassicDyldInfo() )
2175 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2176 if ( writer.targetRequiresWeakBinding(target) )
2177 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2179 helper = new HybridStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2181 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2184 helper = new FastStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2188 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2190 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
2194 // specialize lazy pointer for x86 to initially pointer to stub helper
2196 LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
2197 : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2198 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
2201 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2203 writer.fAllSynthesizedLazyPointers.push_back(this);
2205 ObjectFile::Atom* helper;
2206 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2207 if ( writer.fOptions.makeClassicDyldInfo() ) {
2208 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2209 if ( writer.targetRequiresWeakBinding(target) )
2210 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2212 helper = new HybridStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2215 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2218 helper = new FastStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2222 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2224 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, helper));
2227 template <typename A>
2228 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
2229 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2230 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
2233 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2235 writer.fAllSynthesizedLazyPointers.push_back(this);
2237 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2242 template <typename A>
2243 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
2246 asprintf(&buf, "%s$lazy_pointer", name);
2250 template <typename A>
2251 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2253 bzero(buffer, getSize());
2257 template <typename A>
2258 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
2259 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(&target)
2261 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2262 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2265 template <typename A>
2266 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer)
2267 : WriterAtom<A>(writer, Segment::fgDataSegment), fName("none"), fTarget(NULL)
2269 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2272 template <typename A>
2273 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, const char* targetName)
2274 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(targetName)), fTarget(NULL)
2276 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2277 fReferences.push_back(new WriterReference<A>(0, A::kPointer, targetName));
2280 template <typename A>
2281 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
2284 asprintf(&buf, "%s$non_lazy_pointer", name);
2288 template <typename A>
2289 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2291 bzero(buffer, getSize());
2297 bool StubAtom<ppc64>::pic() const
2299 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
2300 // Usually that only happens if page zero is very large
2301 return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
2306 bool StubAtom<arm>::pic() const
2308 return fWriter.fSlideable;
2312 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
2318 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
2324 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
2330 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2331 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2332 fTarget(target), fForLazyDylib(forLazyDylib)
2334 writer.fAllSynthesizedStubs.push_back(this);
2335 LazyPointerAtom<ppc>* lp;
2336 if ( fWriter.fOptions.prebind() ) {
2337 // for prebound ppc, lazy pointer starts out pointing to target symbol's address
2338 // if target is a weak definition within this linkage unit or zero if in some dylib
2339 lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
2342 // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2343 if ( forLazyDylib ) {
2344 if ( writer.fDyldLazyDylibHelper == NULL )
2345 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2346 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2349 if ( writer.fDyldClassicHelperAtom == NULL )
2350 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2351 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2355 // picbase is 8 bytes into atom
2356 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
2357 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
2360 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
2361 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
2366 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2367 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2368 fTarget(target), fForLazyDylib(forLazyDylib)
2370 writer.fAllSynthesizedStubs.push_back(this);
2372 LazyPointerAtom<ppc64>* lp;
2373 if ( forLazyDylib ) {
2374 if ( writer.fDyldLazyDylibHelper == NULL )
2375 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2376 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2379 if ( writer.fDyldClassicHelperAtom == NULL )
2380 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2381 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2384 // picbase is 8 bytes into atom
2385 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
2386 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
2389 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
2390 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
2395 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2396 : WriterAtom<x86>(writer, (writer.fOptions.makeCompressedDyldInfo()|| forLazyDylib) ? Segment::fgTextSegment : Segment::fgImportSegment),
2397 fName(NULL), fTarget(target), fForLazyDylib(forLazyDylib)
2399 if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) {
2400 fName = stubName(target.getName());
2401 LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
2402 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
2403 writer.fAllSynthesizedStubs.push_back(this);
2406 if ( &target == NULL )
2407 fName = "cache-line-crossing-stub";
2409 fName = stubName(target.getName());
2410 writer.fAllSynthesizedStubs.push_back(this);
2417 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2418 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2420 writer.fAllSynthesizedStubs.push_back(this);
2422 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
2423 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
2427 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2428 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2430 writer.fAllSynthesizedStubs.push_back(this);
2432 LazyPointerAtom<arm>* lp;
2433 if ( fWriter.fOptions.prebind() && !forLazyDylib ) {
2434 // for prebound arm, lazy pointer starts out pointing to target symbol's address
2435 // if target is a weak definition within this linkage unit or zero if in some dylib
2436 lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
2439 // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2440 ObjectFile::Atom* helper;
2441 if ( forLazyDylib ) {
2442 if ( writer.fDyldLazyDylibHelper == NULL )
2443 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2444 helper = writer.fDyldLazyDylibHelper;
2447 if ( writer.fDyldClassicHelperAtom == NULL )
2448 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2449 helper = writer.fDyldClassicHelperAtom;
2451 lp = new LazyPointerAtom<arm>(writer, *helper, *this, forLazyDylib);
2454 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
2456 fReferences.push_back(new WriterReference<arm>(8, arm::kPointer, lp));
2459 template <typename A>
2460 const char* StubAtom<A>::stubName(const char* name)
2463 asprintf(&buf, "%s$stub", name);
2468 uint64_t StubAtom<ppc>::getSize() const
2470 return ( pic() ? 32 : 16 );
2474 uint64_t StubAtom<ppc64>::getSize() const
2476 return ( pic() ? 32 : 16 );
2481 uint64_t StubAtom<arm>::getSize() const
2483 return ( pic() ? 16 : 12 );
2487 uint64_t StubAtom<x86>::getSize() const
2489 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2496 uint64_t StubAtom<x86_64>::getSize() const
2502 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
2504 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2507 return 0; // special case x86 self-modifying stubs to be byte aligned
2511 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
2514 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
2515 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2516 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2517 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2518 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2519 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2520 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2521 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2524 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2525 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
2526 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2527 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2532 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
2535 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
2536 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2537 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2538 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2539 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2540 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2541 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2542 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2545 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2546 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
2547 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2548 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2553 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
2555 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) {
2556 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
2564 if ( fWriter.fOptions.prebind() ) {
2565 uint32_t address = this->getAddress();
2566 int32_t rel32 = 0 - (address+5);
2568 buffer[1] = rel32 & 0xFF;
2569 buffer[2] = (rel32 >> 8) & 0xFF;
2570 buffer[3] = (rel32 >> 16) & 0xFF;
2571 buffer[4] = (rel32 >> 24) & 0xFF;
2584 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
2586 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
2595 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
2598 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
2599 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
2600 OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
2601 OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
2604 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
2605 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
2606 OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
2610 // x86_64 stubs are 6 bytes
2612 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
2618 const char* StubAtom<ppc>::getSectionName() const
2620 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
2624 const char* StubAtom<ppc64>::getSectionName() const
2626 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
2630 const char* StubAtom<arm>::getSectionName() const
2632 return ( pic() ? "__picsymbolstub4" : "__symbol_stub4");
2636 const char* StubAtom<x86>::getSectionName() const
2638 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2639 return "__symbol_stub";
2641 return "__jump_table";
2647 struct AtomByNameSorter
2649 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2651 return (strcmp(left->getName(), right->getName()) < 0);
2655 template <typename P>
2656 struct ExternalRelocSorter
2658 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
2660 // sort first by symbol number
2661 if ( left.r_symbolnum() != right.r_symbolnum() )
2662 return (left.r_symbolnum() < right.r_symbolnum());
2663 // then sort all uses of the same symbol by address
2664 return (left.r_address() < right.r_address());
2669 template <typename A>
2670 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
2671 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
2672 fAllAtoms(NULL), fStabs(NULL), fRegularDefAtomsThatOverrideADylibsWeakDef(NULL), fLoadCommandsSection(NULL),
2673 fLoadCommandsSegment(NULL), fMachHeaderAtom(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
2674 fSymbolTableCommands(NULL), fHeaderPadding(NULL), fUnwindInfoAtom(NULL),
2675 fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL),
2676 fDyldClassicHelperAtom(NULL), fDyldCompressedHelperAtom(NULL), fDyldLazyDylibHelper(NULL),
2677 fSectionRelocationsAtom(NULL), fCompressedRebaseInfoAtom(NULL), fCompressedBindingInfoAtom(NULL),
2678 fCompressedWeakBindingInfoAtom(NULL), fCompressedLazyBindingInfoAtom(NULL), fCompressedExportInfoAtom(NULL),
2679 fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
2680 fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
2681 fStringsAtom(NULL), fPageZeroAtom(NULL), fFastStubGOTAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0),
2682 fSymbolTableStabsCount(0), fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
2683 fLargestAtomSize(1),
2684 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
2685 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
2686 fBiggerThanTwoGigs(false), fSlideable(false),
2687 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
2689 switch ( fOptions.outputKind() ) {
2690 case Options::kDynamicExecutable:
2691 case Options::kStaticExecutable:
2692 if ( fOptions.zeroPageSize() != 0 )
2693 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
2694 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2695 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2696 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2697 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2698 if ( fOptions.makeCompressedDyldInfo() )
2699 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2700 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2701 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2702 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2703 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2704 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2705 if ( fOptions.hasCustomStack() )
2706 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
2707 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2708 if ( fOptions.needsUnwindInfoSection() )
2709 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2710 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2711 if ( fOptions.makeCompressedDyldInfo() ) {
2712 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2713 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2714 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2715 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2716 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2718 if ( fOptions.makeClassicDyldInfo() )
2719 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2720 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2721 if ( fOptions.makeClassicDyldInfo() )
2722 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2723 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2724 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2726 case Options::kPreload:
2727 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2728 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2729 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2730 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2731 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2732 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2733 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2734 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2735 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2736 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2737 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2738 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2740 case Options::kDynamicLibrary:
2741 case Options::kDynamicBundle:
2742 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2743 case Options::kKextBundle:
2744 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2745 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2746 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
2747 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
2748 if ( fOptions.initFunctionName() != NULL )
2749 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
2751 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2752 if ( fOptions.makeCompressedDyldInfo() )
2753 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2754 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2755 if ( fOptions.sharedRegionEligible() )
2756 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
2757 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2758 if ( fOptions.needsUnwindInfoSection() )
2759 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2760 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2761 if ( fOptions.makeCompressedDyldInfo() ) {
2762 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2763 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2764 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2765 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2766 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2768 if ( fOptions.makeClassicDyldInfo() )
2769 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2770 if ( fOptions.sharedRegionEligible() ) {
2771 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
2773 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2774 if ( fOptions.makeClassicDyldInfo() )
2775 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2776 if ( fOptions.outputKind() != Options::kKextBundle )
2777 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2778 if ( this->needsModuleTable() )
2779 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
2780 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2782 case Options::kObjectFile:
2783 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2784 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2785 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2786 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2787 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2788 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2789 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2790 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2791 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2792 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2793 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2795 case Options::kDyld:
2796 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2797 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2798 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2799 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2800 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2801 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2802 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2803 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2804 if ( fOptions.needsUnwindInfoSection() )
2805 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2806 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2807 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2808 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2809 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2810 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2814 // add extra commmands
2815 bool hasReExports = false;
2816 uint32_t ordinal = 1;
2817 switch ( fOptions.outputKind() ) {
2818 case Options::kDynamicExecutable:
2819 if ( fOptions.makeEncryptable() ) {
2820 fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
2821 fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
2824 case Options::kDynamicLibrary:
2825 case Options::kDynamicBundle:
2827 // add dylib load command atoms for all dynamic libraries
2828 const unsigned int libCount = dynamicLibraries.size();
2829 for (unsigned int i=0; i < libCount; ++i) {
2830 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
2831 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
2833 if ( dylibInfo.options.fReExport ) {
2834 hasReExports = true;
2837 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
2838 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
2839 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
2840 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
2841 hasReExports = true;
2845 if ( dylibInfo.options.fWeakImport ) {
2846 fForcedWeakImportReaders.insert(dylibInfo.reader);
2849 if ( dylibInfo.options.fBundleLoader ) {
2850 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
2853 // see if a DylibLoadCommandsAtom has already been created for this install path
2854 bool newDylib = true;
2855 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
2856 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
2857 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
2858 if ( !seenDylibInfo.options.fBundleLoader ) {
2859 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
2860 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
2861 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
2862 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
2863 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
2871 // assign new ordinal and check for other paired load commands
2872 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
2873 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
2874 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
2875 fWriterSynthesizedAtoms.push_back(dyliblc);
2876 if ( dylibInfo.options.fReExport
2877 && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
2878 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
2879 // see if child has sub-framework that is this
2880 bool isSubFramework = false;
2881 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
2882 if ( childInUmbrella != NULL ) {
2883 const char* myLeaf = strrchr(fOptions.installPath(), '/');
2884 if ( myLeaf != NULL ) {
2885 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
2886 isSubFramework = true;
2889 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
2890 if ( ! isSubFramework ) {
2891 // this dylib also needs a sub_x load command
2892 bool isFrameworkReExport = false;
2893 const char* lastSlash = strrchr(dylibInstallPath, '/');
2894 if ( lastSlash != NULL ) {
2895 char frameworkName[strlen(lastSlash)+20];
2896 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
2897 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
2899 if ( isFrameworkReExport ) {
2900 // needs a LC_SUB_UMBRELLA command
2901 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
2904 // needs a LC_SUB_LIBRARY command
2905 const char* nameStart = &lastSlash[1];
2906 if ( lastSlash == NULL )
2907 nameStart = dylibInstallPath;
2908 int len = strlen(nameStart);
2909 const char* dot = strchr(nameStart, '.');
2911 len = dot - nameStart;
2912 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
2919 // add umbrella command if needed
2920 if ( fOptions.umbrellaName() != NULL ) {
2921 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
2923 // add allowable client commands if used
2924 std::vector<const char*>& allowableClients = fOptions.allowableClients();
2925 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
2926 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
2929 case Options::kStaticExecutable:
2930 case Options::kObjectFile:
2931 case Options::kDyld:
2932 case Options::kPreload:
2933 case Options::kKextBundle:
2936 fNoReExportedDylibs = !hasReExports;
2938 // add any rpath load commands
2939 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
2940 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
2943 // set up fSlideable
2944 switch ( fOptions.outputKind() ) {
2945 case Options::kObjectFile:
2946 case Options::kStaticExecutable:
2949 case Options::kDynamicExecutable:
2950 fSlideable = fOptions.positionIndependentExecutable();
2952 case Options::kDyld:
2953 case Options::kDynamicLibrary:
2954 case Options::kDynamicBundle:
2955 case Options::kPreload:
2956 case Options::kKextBundle:
2961 //fprintf(stderr, "ordinals table:\n");
2962 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
2963 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
2967 template <typename A>
2968 Writer<A>::~Writer()
2970 if ( fFilePath != NULL )
2971 free((void*)fFilePath);
2972 if ( fSymbolTable != NULL )
2973 delete [] fSymbolTable;
2977 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
2978 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
2979 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
2982 template <typename A>
2983 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
2985 if ( fOptions.outputKind() == Options::kKextBundle ) {
2986 return new UndefinedSymbolProxyAtom<A>(*this, name);
2988 else if ( fOptions.outputKind() == Options::kObjectFile ) {
2989 // when doing -r -exported_symbols_list, don't create proxy for a symbol
2990 // that is supposed to be exported. We want an error instead
2991 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
2992 if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) )
2995 return new UndefinedSymbolProxyAtom<A>(*this, name);
2997 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
2998 return new UndefinedSymbolProxyAtom<A>(*this, name);
3003 template <typename A>
3004 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
3006 // flat namespace images use zero for all ordinals
3007 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3010 // is an UndefinedSymbolProxyAtom
3012 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3013 return DYNAMIC_LOOKUP_ORDINAL;
3015 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
3016 if ( pos != fLibraryToOrdinal.end() )
3019 throw "can't find ordinal for imported symbol";
3022 template <typename A>
3023 bool Writer<A>::targetRequiresWeakBinding(const ObjectFile::Atom& target)
3025 switch ( target.getDefinitionKind() ) {
3026 case ObjectFile::Atom::kExternalWeakDefinition:
3027 case ObjectFile::Atom::kWeakDefinition:
3029 case ObjectFile::Atom::kExternalDefinition:
3030 case ObjectFile::Atom::kAbsoluteSymbol:
3031 case ObjectFile::Atom::kRegularDefinition:
3032 case ObjectFile::Atom::kTentativeDefinition:
3038 template <typename A>
3039 int Writer<A>::compressedOrdinalForImortedAtom(ObjectFile::Atom* target)
3041 // flat namespace images use zero for all ordinals
3042 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3043 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3045 // is an UndefinedSymbolProxyAtom
3046 ObjectFile::Reader* lib = target->getFile();
3048 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3049 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3051 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos;
3052 switch ( target->getDefinitionKind() ) {
3053 case ObjectFile::Atom::kExternalDefinition:
3054 case ObjectFile::Atom::kExternalWeakDefinition:
3055 pos = fLibraryToOrdinal.find(lib);
3056 if ( pos != fLibraryToOrdinal.end() ) {
3057 if ( pos->second == EXECUTABLE_ORDINAL )
3058 return BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
3063 case ObjectFile::Atom::kWeakDefinition:
3064 throw "compressedOrdinalForImortedAtom() should not have been called on a weak definition";
3065 case ObjectFile::Atom::kAbsoluteSymbol:
3066 case ObjectFile::Atom::kRegularDefinition:
3067 case ObjectFile::Atom::kTentativeDefinition:
3068 return BIND_SPECIAL_DYLIB_SELF;
3071 throw "can't find ordinal for imported symbol";
3075 template <typename A>
3076 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
3078 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
3082 template <typename A>
3083 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
3084 std::vector<class ObjectFile::Reader::Stab>& stabs,
3085 class ObjectFile::Atom* entryPointAtom,
3086 class ObjectFile::Atom* dyldClassicHelperAtom,
3087 class ObjectFile::Atom* dyldCompressedHelperAtom,
3088 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
3089 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
3090 bool biggerThanTwoGigs,
3091 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
3092 bool hasExternalWeakDefinitions)
3096 fEntryPoint = entryPointAtom;
3097 fDyldClassicHelperAtom = dyldClassicHelperAtom;
3098 fDyldCompressedHelperAtom = dyldCompressedHelperAtom;
3099 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
3100 fCanScatter = canScatter;
3101 fCpuConstraint = cpuConstraint;
3102 fBiggerThanTwoGigs = biggerThanTwoGigs;
3103 fHasWeakExports = hasExternalWeakDefinitions; // dyld needs to search this image as if it had weak exports
3104 fRegularDefAtomsThatOverrideADylibsWeakDef = &atomsThatOverrideWeak;
3108 // Set for create UUID
3110 fUUIDAtom->generate();
3112 // remove uneeded dylib load commands
3113 optimizeDylibReferences();
3115 // check for mdynamic-no-pic codegen
3116 scanForAbsoluteReferences();
3118 // create inter-library stubs
3121 // create table of unwind info
3122 synthesizeUnwindInfoTable();
3124 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
3125 partitionIntoSections();
3127 // segment load command can now be sized and padding can be set
3128 adjustLoadCommandsAndPadding();
3130 // assign each section a file offset
3131 assignFileOffsets();
3133 // if need to add branch islands, reassign file offsets
3134 if ( addBranchIslands() )
3135 assignFileOffsets();
3137 // now that addresses are assigned, create unwind info
3138 if ( fUnwindInfoAtom != NULL ) {
3139 fUnwindInfoAtom->generate();
3141 adjustLoadCommandsAndPadding();
3142 assignFileOffsets();
3145 // make spit-seg info now that all atoms exist
3146 createSplitSegContent();
3148 // build symbol table and relocations
3151 // write map file if requested
3155 return writeAtoms();
3157 // clean up if any errors
3158 (void)unlink(fFilePath);
3163 template <typename A>
3164 void Writer<A>::buildLinkEdit()
3166 this->collectExportedAndImportedAndLocalAtoms();
3167 this->buildSymbolTable();
3168 this->buildFixups();
3169 this->adjustLinkEditSections();
3174 template <typename A>
3175 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
3177 return atom->getAddress();
3178 // SectionInfo* info = (SectionInfo*)atom->getSection();
3179 // return info->getBaseAddress() + atom->getSectionOffset();
3183 bool Writer<x86_64>::stringsNeedLabelsInObjects()
3188 template <typename A>
3189 bool Writer<A>::stringsNeedLabelsInObjects()
3194 template <typename A>
3195 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
3197 static unsigned int counter = 0;
3199 if ( stringsNeedLabelsInObjects()
3200 && (atom->getContentType() == ObjectFile::Atom::kCStringType)
3201 && (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) )
3202 asprintf((char**)&name, "LC%u", counter++);
3204 name = atom->getName();
3206 return atom->getName();
3209 template <typename A>
3210 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3213 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
3216 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
3217 entry->set_n_type(N_EXT | N_ABS);
3220 entry->set_n_type(N_EXT | N_SECT);
3221 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
3222 if ( fOptions.keepPrivateExterns() )
3223 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
3227 // set n_sect (section number of implementation )
3228 uint8_t sectionIndex = atom->getSection()->getIndex();
3229 entry->set_n_sect(sectionIndex);
3231 // the __mh_execute_header is magic and must be an absolute symbol
3232 if ( (sectionIndex==0)
3233 && (fOptions.outputKind() == Options::kDynamicExecutable)
3234 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
3235 entry->set_n_type(N_EXT | N_ABS);
3239 if ( atom->isThumb() )
3240 desc |= N_ARM_THUMB_DEF;
3241 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3242 desc |= REFERENCED_DYNAMICALLY;
3243 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3244 desc |= N_NO_DEAD_STRIP;
3245 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
3247 fHasWeakExports = true;
3249 entry->set_n_desc(desc);
3251 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3252 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3253 entry->set_n_value(atom->getSectionOffset());
3255 entry->set_n_value(this->getAtomLoadAddress(atom));
3258 template <typename A>
3259 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3262 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
3265 if ( fOptions.outputKind() == Options::kObjectFile ) {
3266 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3267 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
3268 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
3270 entry->set_n_type(N_UNDF | N_EXT);
3273 if ( fOptions.prebind() )
3274 entry->set_n_type(N_PBUD | N_EXT);
3276 entry->set_n_type(N_UNDF | N_EXT);
3280 entry->set_n_sect(0);
3283 if ( fOptions.outputKind() != Options::kObjectFile ) {
3284 // set n_desc ( high byte is library ordinal, low byte is reference type )
3285 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
3286 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
3287 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
3289 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
3291 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
3292 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
3293 SET_LIBRARY_ORDINAL(desc, ordinal);
3295 catch (const char* msg) {
3296 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3299 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
3300 uint8_t align = atom->getAlignment().powerOf2;
3301 // always record custom alignment of common symbols to match what compiler does
3302 SET_COMM_ALIGN(desc, align);
3304 if ( atom->isThumb() )
3305 desc |= N_ARM_THUMB_DEF;
3306 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3307 desc |= REFERENCED_DYNAMICALLY;
3308 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
3309 desc |= N_REF_TO_WEAK;
3310 fReferencesWeakImports = true;
3312 // set weak_import attribute
3313 if ( fWeakImportMap[atom] )
3315 entry->set_n_desc(desc);
3317 // set n_value, zero for import proxy and size for tentative definition
3318 entry->set_n_value(atom->getSize());
3322 template <typename A>
3323 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3326 const char* symbolName = this->symbolTableName(atom);
3328 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
3329 if ( stringsNeedLabelsInObjects() && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3330 // don't use 'l' labels for x86_64 strings
3331 // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
3334 sprintf(anonName, "l%u", fAnonNameIndex++);
3335 symbolName = anonName;
3338 entry->set_n_strx(this->fStringsAtom->add(symbolName));
3341 uint8_t type = N_SECT;
3342 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3344 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
3346 entry->set_n_type(type);
3348 // set n_sect (section number of implementation )
3349 uint8_t sectIndex = atom->getSection()->getIndex();
3350 if ( sectIndex == 0 ) {
3351 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
3352 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
3355 entry->set_n_sect(sectIndex);
3359 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3360 desc |= N_NO_DEAD_STRIP;
3361 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
3363 if ( atom->isThumb() )
3364 desc |= N_ARM_THUMB_DEF;
3365 entry->set_n_desc(desc);
3367 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3368 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3369 entry->set_n_value(atom->getSectionOffset());
3371 entry->set_n_value(this->getAtomLoadAddress(atom));
3375 template <typename A>
3376 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3378 macho_nlist<P> entry;
3381 entry.set_n_strx(fStringsAtom->add(name));
3384 entry.set_n_type(N_SECT);
3386 // set n_sect (section number of implementation )
3387 entry.set_n_sect(atom.getSection()->getIndex());
3390 entry.set_n_desc(0);
3392 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3393 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3396 fLocalExtraLabels.push_back(entry);
3401 template <typename A>
3402 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3404 macho_nlist<P> entry;
3407 entry.set_n_strx(fStringsAtom->add(name));
3410 entry.set_n_type(N_SECT|N_EXT);
3412 // set n_sect (section number of implementation )
3413 entry.set_n_sect(atom.getSection()->getIndex());
3416 entry.set_n_desc(0);
3418 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3419 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3422 fGlobalExtraLabels.push_back(entry);
3425 template <typename A>
3426 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
3428 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3429 for (uint32_t i=0; i < count; ++i, ++entry) {
3430 ObjectFile::Atom* atom = atoms[i];
3431 if ( &atoms == &fExportedAtoms ) {
3432 this->setExportNlist(atom, entry);
3434 else if ( &atoms == &fImportedAtoms ) {
3435 this->setImportNlist(atom, entry);
3438 this->setLocalNlist(atom, entry);
3443 template <typename A>
3444 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
3446 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
3447 fSymbolTable[startIndex++] = *it;
3451 template <typename A>
3452 struct NListNameSorter
3454 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
3456 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
3458 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
3461 StringsLinkEditAtom<A>* fStringPool;
3465 template <typename A>
3466 void Writer<A>::buildSymbolTable()
3468 fSymbolTableStabsStartIndex = 0;
3469 fSymbolTableStabsCount = fStabs->size();
3470 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
3471 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
3472 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
3473 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
3474 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
3475 fSymbolTableImportCount = fImportedAtoms.size();
3477 // allocate symbol table
3478 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
3479 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
3481 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
3482 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
3483 if ( fLocalExtraLabels.size() != 0 )
3484 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
3485 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
3486 if ( fGlobalExtraLabels.size() != 0 ) {
3487 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
3488 // re-sort combined range
3489 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
3490 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
3491 NListNameSorter<A>(fStringsAtom) );
3493 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
3494 addStabs(fSymbolTableStabsStartIndex);
3496 // set up module table
3497 if ( fModuleInfoAtom != NULL )
3498 fModuleInfoAtom->setName();
3500 // create atom to symbol index map
3503 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
3504 fAtomToSymbolIndex[*it] = i + fSymbolTableImportStartIndex;
3509 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
3510 fAtomToSymbolIndex[*it] = i + fSymbolTableLocalStartIndex;
3515 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
3516 fAtomToSymbolIndex[*it] = i + fSymbolTableExportStartIndex;
3524 template <typename A>
3525 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
3527 switch ( atom.getSymbolTableInclusion() ) {
3528 case ObjectFile::Atom::kSymbolTableNotIn:
3530 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3532 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3533 case ObjectFile::Atom::kSymbolTableIn:
3534 switch ( atom.getScope() ) {
3535 case ObjectFile::Atom::scopeGlobal:
3537 case ObjectFile::Atom::scopeLinkageUnit:
3538 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
3547 template <typename A>
3548 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
3550 const int atomCount = fAllAtoms->size();
3551 // guess at sizes of each bucket to minimize re-allocations
3552 fImportedAtoms.reserve(100);
3553 fExportedAtoms.reserve(atomCount/2);
3554 fLocalSymbolAtoms.reserve(atomCount);
3555 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3556 ObjectFile::Atom* atom = *it;
3557 // only named atoms go in symbol table
3558 if ( atom->getName() != NULL ) {
3559 // put atom into correct bucket: imports, exports, locals
3560 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
3561 switch ( atom->getDefinitionKind() ) {
3562 case ObjectFile::Atom::kExternalDefinition:
3563 case ObjectFile::Atom::kExternalWeakDefinition:
3564 fImportedAtoms.push_back(atom);
3566 case ObjectFile::Atom::kTentativeDefinition:
3567 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
3568 fImportedAtoms.push_back(atom);
3572 case ObjectFile::Atom::kWeakDefinition:
3573 if ( stringsNeedLabelsInObjects()
3574 && (fOptions.outputKind() == Options::kObjectFile)
3575 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn)
3576 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3577 && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3578 fLocalSymbolAtoms.push_back(atom);
3582 case ObjectFile::Atom::kRegularDefinition:
3583 case ObjectFile::Atom::kAbsoluteSymbol:
3584 if ( this->shouldExport(*atom) )
3585 fExportedAtoms.push_back(atom);
3586 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
3587 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
3588 fLocalSymbolAtoms.push_back(atom);
3592 // when geneating a .o file, dtrace static probes become local labels
3593 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
3594 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3595 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3596 ObjectFile::Reference* ref = *rit;
3597 if ( ref->getKind() == A::kDtraceProbe ) {
3598 // dtrace probe points to be add back into generated .o file
3599 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3603 // when linking kernel, old style dtrace static probes become global labels
3604 else if ( fOptions.readerOptions().fForStatic ) {
3605 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3606 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3607 ObjectFile::Reference* ref = *rit;
3608 if ( ref->getKind() == A::kDtraceProbe ) {
3609 // dtrace probe points to be add back into generated .o file
3610 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3616 // sort exported atoms by name
3617 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
3618 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
3619 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
3623 template <typename A>
3624 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
3626 switch ( stab.type ) {
3628 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3629 // end of function N_FUN has size
3630 return stab.atom->getSize();
3633 // start of function N_FUN has address
3634 return getAtomLoadAddress(stab.atom);
3639 if ( stab.atom == NULL )
3640 // some weird assembly files have slines not associated with a function
3643 // all these stab types need their value changed from an offset in the atom to an address
3644 return getAtomLoadAddress(stab.atom) + stab.value;
3648 // all these need address of atom
3649 return getAtomLoadAddress(stab.atom);;
3651 return stab.atom->getSize();
3653 if ( stab.atom == NULL ) {
3657 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3658 // end of translation unit N_SO has address of end of last atom
3659 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
3662 // start of translation unit N_SO has address of end of first atom
3663 return getAtomLoadAddress(stab.atom);
3672 template <typename A>
3673 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
3675 switch (stab.type) {
3677 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
3678 return this->fStringsAtom->emptyString();
3681 // fall into uniquing case
3685 return this->fStringsAtom->addUnique(stab.string);
3688 if ( stab.string == NULL )
3690 else if ( stab.string[0] == '\0' )
3691 return this->fStringsAtom->emptyString();
3693 return this->fStringsAtom->add(stab.string);
3698 template <typename A>
3699 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
3701 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
3702 if ( stab.type == N_FUN )
3704 else if ( stab.atom != NULL )
3705 return stab.atom->getSection()->getIndex();
3710 template <typename A>
3711 void Writer<A>::addStabs(uint32_t startIndex)
3713 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3714 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
3715 const ObjectFile::Reader::Stab& stab = *it;
3716 entry->set_n_type(stab.type);
3717 entry->set_n_sect(sectionIndexForStab(stab));
3718 entry->set_n_desc(stab.desc);
3719 entry->set_n_value(valueForStab(stab));
3720 entry->set_n_strx(stringOffsetForStab(stab));
3726 template <typename A>
3727 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
3729 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fAtomToSymbolIndex.find(&atom);
3730 if ( pos != fAtomToSymbolIndex.end() )
3732 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
3737 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3739 switch ( target.getSymbolTableInclusion() ) {
3740 case ObjectFile::Atom::kSymbolTableNotIn:
3742 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3743 case ObjectFile::Atom::kSymbolTableIn:
3744 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3750 template <typename A>
3751 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3753 switch ( target.getDefinitionKind() ) {
3754 case ObjectFile::Atom::kRegularDefinition:
3755 case ObjectFile::Atom::kWeakDefinition:
3756 case ObjectFile::Atom::kAbsoluteSymbol:
3758 case ObjectFile::Atom::kTentativeDefinition:
3759 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
3762 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
3763 case ObjectFile::Atom::kExternalDefinition:
3764 case ObjectFile::Atom::kExternalWeakDefinition:
3765 return shouldExport(target);
3770 template <typename A>
3771 void Writer<A>::buildFixups()
3773 if ( fOptions.outputKind() == Options::kObjectFile ) {
3774 this->buildObjectFileFixups();
3777 if ( fOptions.keepRelocations() )
3778 this->buildObjectFileFixups();
3779 this->buildExecutableFixups();
3784 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3786 ObjectFile::Atom& target = ref->getTarget();
3787 bool external = this->makesExternalRelocatableReference(target);
3788 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
3789 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3790 macho_relocation_info<P> reloc1;
3791 macho_relocation_info<P> reloc2;
3792 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
3795 case x86_64::kNoFixUp:
3796 case x86_64::kGOTNoFixUp:
3797 case x86_64::kFollowOn:
3798 case x86_64::kGroupSubordinate:
3801 case x86_64::kPointer:
3802 case x86_64::kPointerWeakImport:
3803 reloc1.set_r_address(address);
3804 reloc1.set_r_symbolnum(symbolIndex);
3805 reloc1.set_r_pcrel(false);
3806 reloc1.set_r_length(3);
3807 reloc1.set_r_extern(external);
3808 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3809 fSectionRelocs.push_back(reloc1);
3812 case x86_64::kPointer32:
3813 reloc1.set_r_address(address);
3814 reloc1.set_r_symbolnum(symbolIndex);
3815 reloc1.set_r_pcrel(false);
3816 reloc1.set_r_length(2);
3817 reloc1.set_r_extern(external);
3818 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3819 fSectionRelocs.push_back(reloc1);
3822 case x86_64::kPointerDiff32:
3823 case x86_64::kPointerDiff:
3825 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3826 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
3827 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
3828 reloc1.set_r_address(address);
3829 reloc1.set_r_symbolnum(symbolIndex);
3830 reloc1.set_r_pcrel(false);
3831 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
3832 reloc1.set_r_extern(external);
3833 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3834 reloc2.set_r_address(address);
3835 reloc2.set_r_symbolnum(fromSymbolIndex);
3836 reloc2.set_r_pcrel(false);
3837 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
3838 reloc2.set_r_extern(fromExternal);
3839 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
3840 fSectionRelocs.push_back(reloc1);
3841 fSectionRelocs.push_back(reloc2);
3845 case x86_64::kBranchPCRel32:
3846 case x86_64::kBranchPCRel32WeakImport:
3847 case x86_64::kDtraceProbeSite:
3848 case x86_64::kDtraceIsEnabledSite:
3849 reloc1.set_r_address(address);
3850 reloc1.set_r_symbolnum(symbolIndex);
3851 reloc1.set_r_pcrel(true);
3852 reloc1.set_r_length(2);
3853 reloc1.set_r_extern(external);
3854 reloc1.set_r_type(X86_64_RELOC_BRANCH);
3855 fSectionRelocs.push_back(reloc1);
3858 case x86_64::kPCRel32:
3859 reloc1.set_r_address(address);
3860 reloc1.set_r_symbolnum(symbolIndex);
3861 reloc1.set_r_pcrel(true);
3862 reloc1.set_r_length(2);
3863 reloc1.set_r_extern(external);
3864 reloc1.set_r_type(X86_64_RELOC_SIGNED);
3865 fSectionRelocs.push_back(reloc1);
3868 case x86_64::kPCRel32_1:
3869 reloc1.set_r_address(address);
3870 reloc1.set_r_symbolnum(symbolIndex);
3871 reloc1.set_r_pcrel(true);
3872 reloc1.set_r_length(2);
3873 reloc1.set_r_extern(external);
3874 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
3875 fSectionRelocs.push_back(reloc1);
3878 case x86_64::kPCRel32_2:
3879 reloc1.set_r_address(address);
3880 reloc1.set_r_symbolnum(symbolIndex);
3881 reloc1.set_r_pcrel(true);
3882 reloc1.set_r_length(2);
3883 reloc1.set_r_extern(external);
3884 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
3885 fSectionRelocs.push_back(reloc1);
3888 case x86_64::kPCRel32_4:
3889 reloc1.set_r_address(address);
3890 reloc1.set_r_symbolnum(symbolIndex);
3891 reloc1.set_r_pcrel(true);
3892 reloc1.set_r_length(2);
3893 reloc1.set_r_extern(external);
3894 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
3895 fSectionRelocs.push_back(reloc1);
3898 case x86_64::kBranchPCRel8:
3899 reloc1.set_r_address(address);
3900 reloc1.set_r_symbolnum(symbolIndex);
3901 reloc1.set_r_pcrel(true);
3902 reloc1.set_r_length(0);
3903 reloc1.set_r_extern(external);
3904 reloc1.set_r_type(X86_64_RELOC_BRANCH);
3905 fSectionRelocs.push_back(reloc1);
3908 case x86_64::kPCRel32GOT:
3909 case x86_64::kPCRel32GOTWeakImport:
3910 reloc1.set_r_address(address);
3911 reloc1.set_r_symbolnum(symbolIndex);
3912 reloc1.set_r_pcrel(true);
3913 reloc1.set_r_length(2);
3914 reloc1.set_r_extern(external);
3915 reloc1.set_r_type(X86_64_RELOC_GOT);
3916 fSectionRelocs.push_back(reloc1);
3919 case x86_64::kPCRel32GOTLoad:
3920 case x86_64::kPCRel32GOTLoadWeakImport:
3921 reloc1.set_r_address(address);
3922 reloc1.set_r_symbolnum(symbolIndex);
3923 reloc1.set_r_pcrel(true);
3924 reloc1.set_r_length(2);
3925 reloc1.set_r_extern(external);
3926 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
3927 fSectionRelocs.push_back(reloc1);
3930 case x86_64::kPointerDiff24:
3931 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
3933 case x86_64::kImageOffset32:
3934 throw "internal linker error, kImageOffset32 can't be encoded into object files";
3936 case x86_64::kSectionOffset24:
3937 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
3939 case x86_64::kDtraceTypeReference:
3940 case x86_64::kDtraceProbe:
3941 // generates no relocs
3949 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3951 ObjectFile::Atom& target = ref->getTarget();
3952 bool isExtern = this->makesExternalRelocatableReference(target);
3953 uint32_t symbolIndex = 0;
3955 symbolIndex = this->symbolIndex(target);
3956 uint32_t sectionNum = target.getSection()->getIndex();
3957 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3958 macho_relocation_info<P> reloc1;
3959 macho_relocation_info<P> reloc2;
3960 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
3961 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
3962 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
3964 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
3965 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
3966 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
3971 case x86::kFollowOn:
3972 case x86::kGroupSubordinate:
3976 case x86::kPointerWeakImport:
3977 case x86::kAbsolute32:
3978 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
3979 // use scattered reloc is target offset is non-zero
3980 sreloc1->set_r_scattered(true);
3981 sreloc1->set_r_pcrel(false);
3982 sreloc1->set_r_length(2);
3983 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
3984 sreloc1->set_r_address(address);
3985 sreloc1->set_r_value(target.getAddress());
3988 reloc1.set_r_address(address);
3989 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3990 reloc1.set_r_pcrel(false);
3991 reloc1.set_r_length(2);
3992 reloc1.set_r_extern(isExtern);
3993 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3995 fSectionRelocs.push_back(reloc1);
3998 case x86::kPointerDiff16:
3999 case x86::kPointerDiff:
4001 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4002 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
4003 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
4004 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
4005 sreloc1->set_r_scattered(true);
4006 sreloc1->set_r_pcrel(false);
4007 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4008 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4009 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
4011 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
4012 sreloc1->set_r_address(address);
4013 sreloc1->set_r_value(target.getAddress());
4015 sreloc2->set_r_scattered(true);
4016 sreloc2->set_r_pcrel(false);
4017 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4018 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
4019 sreloc2->set_r_address(0);
4020 if ( &ref->getFromTarget() == atom )
4021 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4023 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4024 fSectionRelocs.push_back(reloc2);
4025 fSectionRelocs.push_back(reloc1);
4029 case x86::kPCRel32WeakImport:
4033 case x86::kDtraceProbeSite:
4034 case x86::kDtraceIsEnabledSite:
4035 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4036 // use scattered reloc is target offset is non-zero
4037 sreloc1->set_r_scattered(true);
4038 sreloc1->set_r_pcrel(true);
4039 sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4040 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4041 sreloc1->set_r_address(address);
4042 sreloc1->set_r_value(target.getAddress());
4045 reloc1.set_r_address(address);
4046 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4047 reloc1.set_r_pcrel(true);
4048 reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4049 reloc1.set_r_extern(isExtern);
4050 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4052 fSectionRelocs.push_back(reloc1);
4055 case x86::kPointerDiff24:
4056 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4058 case x86::kImageOffset32:
4059 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4061 case x86::kSectionOffset24:
4062 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
4064 case x86::kDtraceTypeReference:
4065 case x86::kDtraceProbe:
4066 // generates no relocs
4074 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4076 ObjectFile::Atom& target = ref->getTarget();
4077 bool isExtern = this->makesExternalRelocatableReference(target);
4078 uint32_t symbolIndex = 0;
4080 symbolIndex = this->symbolIndex(target);
4081 uint32_t sectionNum = target.getSection()->getIndex();
4082 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4083 macho_relocation_info<P> reloc1;
4084 macho_relocation_info<P> reloc2;
4085 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4086 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4087 arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
4089 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
4090 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
4091 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
4096 case arm::kFollowOn:
4097 case arm::kGroupSubordinate:
4101 case arm::kReadOnlyPointer:
4102 case arm::kPointerWeakImport:
4103 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4104 // use scattered reloc is target offset is non-zero
4105 sreloc1->set_r_scattered(true);
4106 sreloc1->set_r_pcrel(false);
4107 sreloc1->set_r_length(2);
4108 sreloc1->set_r_type(ARM_RELOC_VANILLA);
4109 sreloc1->set_r_address(address);
4110 sreloc1->set_r_value(target.getAddress());
4113 reloc1.set_r_address(address);
4114 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4115 reloc1.set_r_pcrel(false);
4116 reloc1.set_r_length(2);
4117 reloc1.set_r_extern(isExtern);
4118 reloc1.set_r_type(ARM_RELOC_VANILLA);
4120 fSectionRelocs.push_back(reloc1);
4123 case arm::kPointerDiff:
4125 sreloc1->set_r_scattered(true);
4126 sreloc1->set_r_pcrel(false);
4127 sreloc1->set_r_length(2);
4128 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4129 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
4131 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
4132 sreloc1->set_r_address(address);
4133 sreloc1->set_r_value(target.getAddress());
4134 sreloc2->set_r_scattered(true);
4135 sreloc2->set_r_pcrel(false);
4136 sreloc2->set_r_length(2);
4137 sreloc2->set_r_type(ARM_RELOC_PAIR);
4138 sreloc2->set_r_address(0);
4139 if ( &ref->getFromTarget() == atom )
4140 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4142 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4143 fSectionRelocs.push_back(reloc2);
4144 fSectionRelocs.push_back(reloc1);
4148 case arm::kBranch24WeakImport:
4149 case arm::kBranch24:
4150 case arm::kDtraceProbeSite:
4151 case arm::kDtraceIsEnabledSite:
4152 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4153 // use scattered reloc is target offset is non-zero
4154 sreloc1->set_r_scattered(true);
4155 sreloc1->set_r_pcrel(true);
4156 sreloc1->set_r_length(2);
4157 sreloc1->set_r_type(ARM_RELOC_BR24);
4158 sreloc1->set_r_address(address);
4159 sreloc1->set_r_value(target.getAddress());
4162 reloc1.set_r_address(address);
4163 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4164 reloc1.set_r_pcrel(true);
4165 reloc1.set_r_length(2);
4166 reloc1.set_r_extern(isExtern);
4167 reloc1.set_r_type(ARM_RELOC_BR24);
4169 fSectionRelocs.push_back(reloc1);
4172 case arm::kThumbBranch22WeakImport:
4173 case arm::kThumbBranch22:
4174 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4175 // use scattered reloc if target offset is non-zero
4176 sreloc1->set_r_scattered(true);
4177 sreloc1->set_r_pcrel(true);
4178 sreloc1->set_r_length(2);
4179 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
4180 sreloc1->set_r_address(address);
4181 sreloc1->set_r_value(target.getAddress());
4184 reloc1.set_r_address(address);
4185 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4186 reloc1.set_r_pcrel(true);
4187 reloc1.set_r_length(2);
4188 reloc1.set_r_extern(isExtern);
4189 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
4191 fSectionRelocs.push_back(reloc1);
4194 case arm::kDtraceTypeReference:
4195 case arm::kDtraceProbe:
4196 // generates no relocs
4203 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
4204 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4205 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
4206 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4207 template <> uint64_t Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
4210 uint8_t Writer<ppc>::getRelocPointerSize()
4216 uint8_t Writer<ppc64>::getRelocPointerSize()
4222 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4224 return addObjectRelocs_powerpc(atom, ref);
4228 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4230 return addObjectRelocs_powerpc(atom, ref);
4234 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
4235 // they use a common addObjectRelocs_powerpc() method.
4237 template <typename A>
4238 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4240 ObjectFile::Atom& target = ref->getTarget();
4241 bool isExtern = this->makesExternalRelocatableReference(target);
4242 uint32_t symbolIndex = 0;
4244 symbolIndex = this->symbolIndex(target);
4245 uint32_t sectionNum = target.getSection()->getIndex();
4246 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4247 macho_relocation_info<P> reloc1;
4248 macho_relocation_info<P> reloc2;
4249 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4250 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4251 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
4256 case A::kGroupSubordinate:
4260 case A::kPointerWeakImport:
4261 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
4262 // use scattered reloc is target offset is outside target
4263 sreloc1->set_r_scattered(true);
4264 sreloc1->set_r_pcrel(false);
4265 sreloc1->set_r_length(getRelocPointerSize());
4266 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4267 sreloc1->set_r_address(address);
4268 sreloc1->set_r_value(target.getAddress());
4271 reloc1.set_r_address(address);
4273 reloc1.set_r_symbolnum(symbolIndex);
4275 reloc1.set_r_symbolnum(sectionNum);
4276 reloc1.set_r_pcrel(false);
4277 reloc1.set_r_length(getRelocPointerSize());
4278 reloc1.set_r_extern(isExtern);
4279 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4281 fSectionRelocs.push_back(reloc1);
4284 case A::kPointerDiff16:
4285 case A::kPointerDiff32:
4286 case A::kPointerDiff64:
4288 sreloc1->set_r_scattered(true);
4289 sreloc1->set_r_pcrel(false);
4290 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
4291 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4292 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
4294 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
4295 sreloc1->set_r_address(address);
4296 sreloc1->set_r_value(target.getAddress());
4297 sreloc2->set_r_scattered(true);
4298 sreloc2->set_r_pcrel(false);
4299 sreloc2->set_r_length(sreloc1->r_length());
4300 sreloc2->set_r_type(PPC_RELOC_PAIR);
4301 sreloc2->set_r_address(0);
4302 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4303 fSectionRelocs.push_back(reloc2);
4304 fSectionRelocs.push_back(reloc1);
4308 case A::kBranch24WeakImport:
4310 case A::kDtraceProbeSite:
4311 case A::kDtraceIsEnabledSite:
4312 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4313 reloc1.set_r_address(address);
4315 reloc1.set_r_symbolnum(symbolIndex);
4317 reloc1.set_r_symbolnum(sectionNum);
4318 reloc1.set_r_pcrel(true);
4319 reloc1.set_r_length(2);
4320 reloc1.set_r_type(PPC_RELOC_BR24);
4321 reloc1.set_r_extern(isExtern);
4324 sreloc1->set_r_scattered(true);
4325 sreloc1->set_r_pcrel(true);
4326 sreloc1->set_r_length(2);
4327 sreloc1->set_r_type(PPC_RELOC_BR24);
4328 sreloc1->set_r_address(address);
4329 sreloc1->set_r_value(target.getAddress());
4331 fSectionRelocs.push_back(reloc1);
4335 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4336 reloc1.set_r_address(address);
4338 reloc1.set_r_symbolnum(symbolIndex);
4340 reloc1.set_r_symbolnum(sectionNum);
4341 reloc1.set_r_pcrel(true);
4342 reloc1.set_r_length(2);
4343 reloc1.set_r_type(PPC_RELOC_BR14);
4344 reloc1.set_r_extern(isExtern);
4347 sreloc1->set_r_scattered(true);
4348 sreloc1->set_r_pcrel(true);
4349 sreloc1->set_r_length(2);
4350 sreloc1->set_r_type(PPC_RELOC_BR14);
4351 sreloc1->set_r_address(address);
4352 sreloc1->set_r_value(target.getAddress());
4354 fSectionRelocs.push_back(reloc1);
4357 case A::kPICBaseLow16:
4358 case A::kPICBaseLow14:
4360 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4361 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4362 sreloc1->set_r_scattered(true);
4363 sreloc1->set_r_pcrel(false);
4364 sreloc1->set_r_length(2);
4365 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
4366 sreloc1->set_r_address(address);
4367 sreloc1->set_r_value(target.getAddress());
4368 sreloc2->set_r_scattered(true);
4369 sreloc2->set_r_pcrel(false);
4370 sreloc2->set_r_length(2);
4371 sreloc2->set_r_type(PPC_RELOC_PAIR);
4372 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
4373 sreloc2->set_r_value(fromAddr);
4374 fSectionRelocs.push_back(reloc2);
4375 fSectionRelocs.push_back(reloc1);
4379 case A::kPICBaseHigh16:
4381 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4382 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4383 sreloc1->set_r_scattered(true);
4384 sreloc1->set_r_pcrel(false);
4385 sreloc1->set_r_length(2);
4386 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
4387 sreloc1->set_r_address(address);
4388 sreloc1->set_r_value(target.getAddress());
4389 sreloc2->set_r_scattered(true);
4390 sreloc2->set_r_pcrel(false);
4391 sreloc2->set_r_length(2);
4392 sreloc2->set_r_type(PPC_RELOC_PAIR);
4393 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
4394 sreloc2->set_r_value(fromAddr);
4395 fSectionRelocs.push_back(reloc2);
4396 fSectionRelocs.push_back(reloc1);
4403 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4404 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4405 reloc1.set_r_address(address);
4407 reloc1.set_r_symbolnum(symbolIndex);
4409 reloc1.set_r_symbolnum(sectionNum);
4410 reloc1.set_r_pcrel(false);
4411 reloc1.set_r_length(2);
4412 reloc1.set_r_extern(isExtern);
4413 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4416 sreloc1->set_r_scattered(true);
4417 sreloc1->set_r_pcrel(false);
4418 sreloc1->set_r_length(2);
4419 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4420 sreloc1->set_r_address(address);
4421 sreloc1->set_r_value(target.getAddress());
4424 reloc2.set_r_address(ref->getTargetOffset() >> 16);
4426 reloc2.set_r_address(toAddr >> 16);
4427 reloc2.set_r_symbolnum(0);
4428 reloc2.set_r_pcrel(false);
4429 reloc2.set_r_length(2);
4430 reloc2.set_r_extern(false);
4431 reloc2.set_r_type(PPC_RELOC_PAIR);
4432 fSectionRelocs.push_back(reloc2);
4433 fSectionRelocs.push_back(reloc1);
4439 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4440 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4441 reloc1.set_r_address(address);
4443 reloc1.set_r_symbolnum(symbolIndex);
4445 reloc1.set_r_symbolnum(sectionNum);
4446 reloc1.set_r_pcrel(false);
4447 reloc1.set_r_length(2);
4448 reloc1.set_r_extern(isExtern);
4449 reloc1.set_r_type(PPC_RELOC_HI16);
4452 sreloc1->set_r_scattered(true);
4453 sreloc1->set_r_pcrel(false);
4454 sreloc1->set_r_length(2);
4455 sreloc1->set_r_type(PPC_RELOC_HI16);
4456 sreloc1->set_r_address(address);
4457 sreloc1->set_r_value(target.getAddress());
4460 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4462 reloc2.set_r_address(toAddr & 0xFFFF);
4463 reloc2.set_r_symbolnum(0);
4464 reloc2.set_r_pcrel(false);
4465 reloc2.set_r_length(2);
4466 reloc2.set_r_extern(false);
4467 reloc2.set_r_type(PPC_RELOC_PAIR);
4468 fSectionRelocs.push_back(reloc2);
4469 fSectionRelocs.push_back(reloc1);
4473 case A::kAbsHigh16AddLow:
4475 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4476 uint32_t overflow = 0;
4477 if ( (toAddr & 0x00008000) != 0 )
4479 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4480 reloc1.set_r_address(address);
4482 reloc1.set_r_symbolnum(symbolIndex);
4484 reloc1.set_r_symbolnum(sectionNum);
4485 reloc1.set_r_pcrel(false);
4486 reloc1.set_r_length(2);
4487 reloc1.set_r_extern(isExtern);
4488 reloc1.set_r_type(PPC_RELOC_HA16);
4491 sreloc1->set_r_scattered(true);
4492 sreloc1->set_r_pcrel(false);
4493 sreloc1->set_r_length(2);
4494 sreloc1->set_r_type(PPC_RELOC_HA16);
4495 sreloc1->set_r_address(address);
4496 sreloc1->set_r_value(target.getAddress());
4499 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4501 reloc2.set_r_address(toAddr & 0xFFFF);
4502 reloc2.set_r_symbolnum(0);
4503 reloc2.set_r_pcrel(false);
4504 reloc2.set_r_length(2);
4505 reloc2.set_r_extern(false);
4506 reloc2.set_r_type(PPC_RELOC_PAIR);
4507 fSectionRelocs.push_back(reloc2);
4508 fSectionRelocs.push_back(reloc1);
4512 case A::kDtraceTypeReference:
4513 case A::kDtraceProbe:
4514 // generates no relocs
4523 // There are cases when an entry in the indirect symbol table is the magic value
4524 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
4525 // the content of the corresponding part of the __nl_symbol_pointer section
4526 // must also change.
4528 template <typename A>
4529 bool Writer<A>::indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const
4531 // cannot use INDIRECT_SYMBOL_LOCAL to tentative definitions in object files
4532 // because tentative defs don't have addresses
4533 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition )
4536 // must use INDIRECT_SYMBOL_LOCAL if there is an addend
4537 if ( ref->getTargetOffset() != 0 )
4540 // don't use INDIRECT_SYMBOL_LOCAL for external symbols
4541 return ! this->shouldExport(ref->getTarget());
4545 template <typename A>
4546 void Writer<A>::buildObjectFileFixups()
4548 uint32_t relocIndex = 0;
4549 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
4550 const int segCount = segmentInfos.size();
4551 for(int i=0; i < segCount; ++i) {
4552 SegmentInfo* curSegment = segmentInfos[i];
4553 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4554 const int sectionCount = sectionInfos.size();
4555 for(int j=0; j < sectionCount; ++j) {
4556 SectionInfo* curSection = sectionInfos[j];
4557 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
4558 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
4559 if ( ! curSection->fAllZeroFill ) {
4560 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4561 || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
4562 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
4563 curSection->fRelocOffset = relocIndex;
4564 const int atomCount = sectionAtoms.size();
4565 for (int k=0; k < atomCount; ++k) {
4566 ObjectFile::Atom* atom = sectionAtoms[k];
4567 //fprintf(stderr, "buildObjectFileFixups(): atom %s has %lu references\n", atom->getDisplayName(), atom->getReferences().size());
4568 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
4569 const int refCount = refs.size();
4570 for (int l=0; l < refCount; ++l) {
4571 ObjectFile::Reference* ref = refs[l];
4572 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4573 || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
4574 uint32_t offsetInSection = atom->getSectionOffset();
4575 uint32_t indexInSection = offsetInSection / atom->getSize();
4576 uint32_t undefinedSymbolIndex;
4577 if ( curSection->fAllStubs ) {
4578 ObjectFile::Atom& stubTarget =ref->getTarget();
4579 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
4580 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
4581 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
4583 else if ( curSection->fAllNonLazyPointers) {
4584 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
4585 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
4586 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4588 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
4591 // should never get here, fAllLazyPointers not used in generated .o files
4592 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4594 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
4595 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
4596 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
4597 fIndirectTableAtom->fTable.push_back(entry);
4598 if ( curSection->fAllLazyPointers ) {
4599 ObjectFile::Atom& target = ref->getTarget();
4600 ObjectFile::Atom& fromTarget = ref->getFromTarget();
4601 if ( &fromTarget == NULL ) {
4602 warning("lazy pointer %s missing initial binding", atom->getDisplayName());
4605 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
4606 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
4607 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
4608 macho_relocation_info<P> reloc1;
4609 reloc1.set_r_address(atom->getSectionOffset());
4610 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
4611 reloc1.set_r_pcrel(false);
4612 reloc1.set_r_length();
4613 reloc1.set_r_extern(isExtern);
4614 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4615 fSectionRelocs.push_back(reloc1);
4619 else if ( curSection->fAllStubs ) {
4620 relocIndex += this->addObjectRelocs(atom, ref);
4623 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
4624 relocIndex += this->addObjectRelocs(atom, ref);
4628 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
4633 // reverse the relocs
4634 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
4636 // now reverse section reloc offsets
4637 for(int i=0; i < segCount; ++i) {
4638 SegmentInfo* curSegment = segmentInfos[i];
4639 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4640 const int sectionCount = sectionInfos.size();
4641 for(int j=0; j < sectionCount; ++j) {
4642 SectionInfo* curSection = sectionInfos[j];
4643 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
4651 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
4654 if ( fOptions.outputKind() == Options::kKextBundle ) {
4655 // for x86_64 kext bundles, the r_address field in relocs
4656 // is the offset from the start address of the first segment
4657 result = address - fSegmentInfos[0]->fBaseAddress;
4658 if ( result > 0xFFFFFFFF ) {
4659 throwf("kext bundle too large: address can't fit in 31-bit r_address field in %s from %s",
4660 atom->getDisplayName(), atom->getFile()->getPath());
4664 // for x86_64, the r_address field in relocs for final linked images
4665 // is the offset from the start address of the first writable segment
4666 result = address - fFirstWritableSegment->fBaseAddress;
4667 if ( result > 0xFFFFFFFF ) {
4668 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
4669 throwf("text relocs not supported for x86_64 in %s from %s",
4670 atom->getDisplayName(), atom->getFile()->getPath());
4672 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
4673 atom->getDisplayName(), atom->getFile()->getPath());
4681 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4683 switch ( ref.getKind() ) {
4684 case ppc::kAbsLow16:
4685 case ppc::kAbsLow14:
4686 case ppc::kAbsHigh16:
4687 case ppc::kAbsHigh16AddLow:
4696 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4698 switch ( ref.getKind() ) {
4699 case ppc::kAbsLow16:
4700 case ppc::kAbsLow14:
4701 case ppc::kAbsHigh16:
4702 case ppc::kAbsHigh16AddLow:
4710 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4712 if ( ref.getKind() == x86::kAbsolute32 ) {
4713 switch ( ref.getTarget().getDefinitionKind() ) {
4714 case ObjectFile::Atom::kTentativeDefinition:
4715 case ObjectFile::Atom::kRegularDefinition:
4716 case ObjectFile::Atom::kWeakDefinition:
4717 // illegal in dylibs/bundles, until we support TEXT relocs
4719 case ObjectFile::Atom::kExternalDefinition:
4720 case ObjectFile::Atom::kExternalWeakDefinition:
4721 // illegal until we support TEXT relocs
4723 case ObjectFile::Atom::kAbsoluteSymbol:
4724 // absolute symbbols only allowed in static executables
4725 return ( fOptions.outputKind() != Options::kStaticExecutable);
4732 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4734 if ( fOptions.outputKind() == Options::kKextBundle ) {
4735 switch ( ref.getTarget().getDefinitionKind() ) {
4736 case ObjectFile::Atom::kTentativeDefinition:
4737 case ObjectFile::Atom::kRegularDefinition:
4738 case ObjectFile::Atom::kWeakDefinition:
4739 case ObjectFile::Atom::kAbsoluteSymbol:
4741 case ObjectFile::Atom::kExternalDefinition:
4742 case ObjectFile::Atom::kExternalWeakDefinition:
4743 // true means we need a TEXT relocs
4744 switch ( ref.getKind() ) {
4745 case x86_64::kBranchPCRel32:
4746 case x86_64::kBranchPCRel32WeakImport:
4747 case x86_64::kPCRel32GOTLoad:
4748 case x86_64::kPCRel32GOTLoadWeakImport:
4749 case x86_64::kPCRel32GOT:
4750 case x86_64::kPCRel32GOTWeakImport:
4760 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4762 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4763 switch ( ref.getTarget().getDefinitionKind() ) {
4764 case ObjectFile::Atom::kTentativeDefinition:
4765 case ObjectFile::Atom::kRegularDefinition:
4766 case ObjectFile::Atom::kWeakDefinition:
4767 // illegal in dylibs/bundles, until we support TEXT relocs
4769 case ObjectFile::Atom::kExternalDefinition:
4770 case ObjectFile::Atom::kExternalWeakDefinition:
4771 // illegal until we support TEXT relocs
4773 case ObjectFile::Atom::kAbsoluteSymbol:
4774 // absolute symbbols only allowed in static executables
4775 return ( fOptions.outputKind() != Options::kStaticExecutable);
4782 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4784 if ( ref.getKind() == x86::kAbsolute32 ) {
4785 switch ( ref.getTarget().getDefinitionKind() ) {
4786 case ObjectFile::Atom::kTentativeDefinition:
4787 case ObjectFile::Atom::kRegularDefinition:
4788 case ObjectFile::Atom::kWeakDefinition:
4789 // a reference to the absolute address of something in this same linkage unit can be
4790 // encoded as a local text reloc in a dylib or bundle
4792 macho_relocation_info<P> reloc;
4793 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4794 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4795 reloc.set_r_symbolnum(sectInfo->getIndex());
4796 reloc.set_r_pcrel(false);
4797 reloc.set_r_length();
4798 reloc.set_r_extern(false);
4799 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4800 fInternalRelocs.push_back(reloc);
4801 atomSection->fHasTextLocalRelocs = true;
4802 if ( fOptions.makeCompressedDyldInfo() ) {
4803 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
4808 case ObjectFile::Atom::kExternalDefinition:
4809 case ObjectFile::Atom::kExternalWeakDefinition:
4810 case ObjectFile::Atom::kAbsoluteSymbol:
4818 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4820 macho_relocation_info<P> reloc1;
4821 macho_relocation_info<P> reloc2;
4822 switch ( ref.getTarget().getDefinitionKind() ) {
4823 case ObjectFile::Atom::kTentativeDefinition:
4824 case ObjectFile::Atom::kRegularDefinition:
4825 case ObjectFile::Atom::kWeakDefinition:
4826 switch ( ref.getKind() ) {
4827 case ppc::kAbsLow16:
4828 case ppc::kAbsLow14:
4829 // a reference to the absolute address of something in this same linkage unit can be
4830 // encoded as a local text reloc in a dylib or bundle
4832 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4833 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
4834 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4835 reloc1.set_r_symbolnum(sectInfo->getIndex());
4836 reloc1.set_r_pcrel(false);
4837 reloc1.set_r_length(2);
4838 reloc1.set_r_extern(false);
4839 reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4840 reloc2.set_r_address(targetAddr >> 16);
4841 reloc2.set_r_symbolnum(0);
4842 reloc2.set_r_pcrel(false);
4843 reloc2.set_r_length(2);
4844 reloc2.set_r_extern(false);
4845 reloc2.set_r_type(PPC_RELOC_PAIR);
4846 fInternalRelocs.push_back(reloc1);
4847 fInternalRelocs.push_back(reloc2);
4848 atomSection->fHasTextLocalRelocs = true;
4852 case ppc::kAbsHigh16:
4853 case ppc::kAbsHigh16AddLow:
4855 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4856 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
4857 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4858 reloc1.set_r_symbolnum(sectInfo->getIndex());
4859 reloc1.set_r_pcrel(false);
4860 reloc1.set_r_length(2);
4861 reloc1.set_r_extern(false);
4862 reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
4863 reloc2.set_r_address(targetAddr & 0xFFFF);
4864 reloc2.set_r_symbolnum(0);
4865 reloc2.set_r_pcrel(false);
4866 reloc2.set_r_length(2);
4867 reloc2.set_r_extern(false);
4868 reloc2.set_r_type(PPC_RELOC_PAIR);
4869 fInternalRelocs.push_back(reloc1);
4870 fInternalRelocs.push_back(reloc2);
4871 atomSection->fHasTextLocalRelocs = true;
4876 case ObjectFile::Atom::kExternalDefinition:
4877 case ObjectFile::Atom::kExternalWeakDefinition:
4878 case ObjectFile::Atom::kAbsoluteSymbol:
4885 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4887 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4888 switch ( ref.getTarget().getDefinitionKind() ) {
4889 case ObjectFile::Atom::kTentativeDefinition:
4890 case ObjectFile::Atom::kRegularDefinition:
4891 case ObjectFile::Atom::kWeakDefinition:
4892 // a reference to the absolute address of something in this same linkage unit can be
4893 // encoded as a local text reloc in a dylib or bundle
4895 macho_relocation_info<P> reloc;
4896 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4897 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4898 reloc.set_r_symbolnum(sectInfo->getIndex());
4899 reloc.set_r_pcrel(false);
4900 reloc.set_r_length();
4901 reloc.set_r_extern(false);
4902 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4903 fInternalRelocs.push_back(reloc);
4904 atomSection->fHasTextLocalRelocs = true;
4908 case ObjectFile::Atom::kExternalDefinition:
4909 case ObjectFile::Atom::kExternalWeakDefinition:
4910 case ObjectFile::Atom::kAbsoluteSymbol:
4919 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
4921 // text relocs not supported (usually never needed because of RIP addressing)
4926 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
4928 // text relocs not supported
4933 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4935 if ( ref.getKind() == x86::kAbsolute32 ) {
4936 macho_relocation_info<P> reloc;
4937 switch ( ref.getTarget().getDefinitionKind() ) {
4938 case ObjectFile::Atom::kTentativeDefinition:
4939 case ObjectFile::Atom::kRegularDefinition:
4940 case ObjectFile::Atom::kWeakDefinition:
4942 case ObjectFile::Atom::kExternalDefinition:
4943 case ObjectFile::Atom::kExternalWeakDefinition:
4944 // a reference to the absolute address of something in another linkage unit can be
4945 // encoded as an external text reloc in a dylib or bundle
4946 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4947 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4948 reloc.set_r_pcrel(false);
4949 reloc.set_r_length();
4950 reloc.set_r_extern(true);
4951 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4952 fExternalRelocs.push_back(reloc);
4953 atomSection->fHasTextExternalRelocs = true;
4955 case ObjectFile::Atom::kAbsoluteSymbol:
4963 bool Writer<x86_64>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4965 if ( fOptions.outputKind() == Options::kKextBundle ) {
4966 macho_relocation_info<P> reloc;
4967 switch ( ref.getTarget().getDefinitionKind() ) {
4968 case ObjectFile::Atom::kTentativeDefinition:
4969 case ObjectFile::Atom::kRegularDefinition:
4970 case ObjectFile::Atom::kWeakDefinition:
4971 case ObjectFile::Atom::kAbsoluteSymbol:
4973 case ObjectFile::Atom::kExternalDefinition:
4974 case ObjectFile::Atom::kExternalWeakDefinition:
4975 switch ( ref.getKind() ) {
4976 case x86_64::kBranchPCRel32:
4977 case x86_64::kBranchPCRel32WeakImport:
4978 // a branch to something in another linkage unit is
4979 // encoded as an external text reloc in a kext bundle
4980 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4981 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4982 reloc.set_r_pcrel(true);
4983 reloc.set_r_length(2);
4984 reloc.set_r_extern(true);
4985 reloc.set_r_type(X86_64_RELOC_BRANCH);
4986 fExternalRelocs.push_back(reloc);
4987 atomSection->fHasTextExternalRelocs = true;
4989 case x86_64::kPCRel32GOTLoad:
4990 case x86_64::kPCRel32GOTLoadWeakImport:
4991 // a load of the GOT entry for a symbol in another linkage unit is
4992 // encoded as an external text reloc in a kext bundle
4993 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4994 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4995 reloc.set_r_pcrel(true);
4996 reloc.set_r_length(2);
4997 reloc.set_r_extern(true);
4998 reloc.set_r_type(X86_64_RELOC_GOT_LOAD);
4999 fExternalRelocs.push_back(reloc);
5000 atomSection->fHasTextExternalRelocs = true;
5002 case x86_64::kPCRel32GOT:
5003 case x86_64::kPCRel32GOTWeakImport:
5004 // a use of the GOT entry for a symbol in another linkage unit is
5005 // encoded as an external text reloc in a kext bundle
5006 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5007 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
5008 reloc.set_r_pcrel(true);
5009 reloc.set_r_length(2);
5010 reloc.set_r_extern(true);
5011 reloc.set_r_type(X86_64_RELOC_GOT);
5012 fExternalRelocs.push_back(reloc);
5013 atomSection->fHasTextExternalRelocs = true;
5023 template <typename A>
5024 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5032 template <typename A>
5033 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
5035 switch ( target.getDefinitionKind() ) {
5036 case ObjectFile::Atom::kTentativeDefinition:
5037 case ObjectFile::Atom::kRegularDefinition:
5038 // in main executables, the only way regular symbols are indirected is if -interposable is used
5039 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
5040 if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
5041 return kRelocExternal;
5042 else if ( fSlideable )
5043 return kRelocInternal;
5047 // for flat-namespace or interposable two-level-namespace
5048 // all references to exported symbols get indirected
5049 else if ( this->shouldExport(target) &&
5050 ((fOptions.nameSpace() == Options::kFlatNameSpace)
5051 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
5052 || fOptions.interposable(target.getName()))
5053 && (target.getName() != NULL)
5054 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
5055 return kRelocExternal;
5056 else if ( fSlideable )
5057 return kRelocInternal;
5060 case ObjectFile::Atom::kWeakDefinition:
5061 // all calls to global weak definitions get indirected
5062 if ( this->shouldExport(target) )
5063 return kRelocExternal;
5064 else if ( fSlideable )
5065 return kRelocInternal;
5068 case ObjectFile::Atom::kExternalDefinition:
5069 case ObjectFile::Atom::kExternalWeakDefinition:
5070 return kRelocExternal;
5071 case ObjectFile::Atom::kAbsoluteSymbol:
5077 template <typename A>
5078 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5080 // for 32-bit architectures, the r_address field in relocs
5081 // for final linked images is the offset from the first segment
5082 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
5083 if ( fOptions.outputKind() == Options::kPreload ) {
5084 // kPreload uses a virtual __HEADER segment to cover the load commands
5085 result = address - fSegmentInfos[1]->fBaseAddress;
5087 // or the offset from the first writable segment if built split-seg
5088 if ( fOptions.splitSeg() )
5089 result = address - fFirstWritableSegment->fBaseAddress;
5090 if ( result > 0x7FFFFFFF ) {
5091 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
5092 atom->getDisplayName(), atom->getFile()->getPath());
5098 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5100 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
5101 // the 10.5 dyld, iterprets the r_address as:
5102 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
5103 // 2) an offset from the base address of the first writable segment
5104 // For dyld, r_address is always the offset from the base address
5106 bool badFor10_4 = false;
5107 if ( fWritableSegmentPastFirst4GB ) {
5108 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
5110 result = address - fFirstWritableSegment->fBaseAddress;
5111 if ( result > 0xFFFFFFFF ) {
5112 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
5113 atom->getDisplayName(), atom->getFile()->getPath());
5117 result = address - fSegmentInfos[0]->fBaseAddress;
5118 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
5122 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",
5123 atom->getDisplayName(), atom->getFile()->getPath());
5129 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
5130 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5131 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
5132 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5133 template <> bool Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
5135 template <typename A>
5136 void Writer<A>::buildExecutableFixups()
5138 if ( fIndirectTableAtom != NULL )
5139 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
5140 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
5141 const int segCount = segmentInfos.size();
5142 for(int i=0; i < segCount; ++i) {
5143 SegmentInfo* curSegment = segmentInfos[i];
5144 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5145 const int sectionCount = sectionInfos.size();
5146 for(int j=0; j < sectionCount; ++j) {
5147 SectionInfo* curSection = sectionInfos[j];
5148 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
5149 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5150 if ( ! curSection->fAllZeroFill ) {
5151 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers
5152 || curSection->fAllStubs || curSection->fAllSelfModifyingStubs ) {
5153 if ( fIndirectTableAtom != NULL )
5154 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
5156 const int atomCount = sectionAtoms.size();
5157 for (int k=0; k < atomCount; ++k) {
5158 ObjectFile::Atom* atom = sectionAtoms[k];
5159 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
5160 const int refCount = refs.size();
5161 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
5162 if ( curSection->fAllNonLazyPointers && (refCount == 0) ) {
5163 // handle imageloadercache GOT slot
5164 uint32_t offsetInSection = atom->getSectionOffset();
5165 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5166 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5167 // use INDIRECT_SYMBOL_ABS so 10.5 dyld will leave value as zero
5168 IndirectEntry entry = { indirectTableIndex, INDIRECT_SYMBOL_ABS };
5169 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5170 // indirectTableIndex, INDIRECT_SYMBOL_LOCAL, curSection->fSectionName);
5171 fIndirectTableAtom->fTable.push_back(entry);
5173 for (int l=0; l < refCount; ++l) {
5174 ObjectFile::Reference* ref = refs[l];
5175 if ( (fOptions.outputKind() != Options::kKextBundle) &&
5176 (curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers) ) {
5177 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
5178 if ( atom->getSize() != sizeof(pint_t) ) {
5179 warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
5181 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
5182 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5183 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
5185 uint32_t offsetInSection = atom->getSectionOffset();
5186 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5187 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
5188 if (atom == fFastStubGOTAtom)
5189 undefinedSymbolIndex = INDIRECT_SYMBOL_ABS;
5190 else if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
5191 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
5192 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5193 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5194 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5195 // indirectTableIndex, undefinedSymbolIndex, curSection->fSectionName);
5196 fIndirectTableAtom->fTable.push_back(entry);
5197 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5198 uint8_t preboundLazyType;
5199 if ( fOptions.prebind() && (fDyldClassicHelperAtom != NULL)
5200 && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
5201 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
5202 macho_scattered_relocation_info<P> pblaReloc;
5203 pblaReloc.set_r_scattered(true);
5204 pblaReloc.set_r_pcrel(false);
5205 pblaReloc.set_r_length();
5206 pblaReloc.set_r_type(preboundLazyType);
5207 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5208 pblaReloc.set_r_value(fDyldClassicHelperAtom->getAddress());
5209 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
5211 else if ( fSlideable ) {
5212 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
5213 macho_relocation_info<P> dyldHelperReloc;
5214 uint32_t sectionNum = 1;
5215 if ( fDyldClassicHelperAtom != NULL )
5216 sectionNum = ((SectionInfo*)(fDyldClassicHelperAtom->getSection()))->getIndex();
5217 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
5218 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5219 dyldHelperReloc.set_r_symbolnum(sectionNum);
5220 dyldHelperReloc.set_r_pcrel(false);
5221 dyldHelperReloc.set_r_length();
5222 dyldHelperReloc.set_r_extern(false);
5223 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
5224 fInternalRelocs.push_back(dyldHelperReloc);
5225 if ( fOptions.makeCompressedDyldInfo() ) {
5226 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5229 if ( fOptions.makeCompressedDyldInfo() ) {
5230 uint8_t type = BIND_TYPE_POINTER;
5231 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5232 if ( pointerTarget->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5233 // This is a referece to a weak def in some dylib (e.g. operator new)
5234 // need to bind into to directly bind this
5235 // later weak binding info may override
5236 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5237 fBindingInfo.push_back(BindingInfo(type, ordinal, pointerTarget->getName(), false, addresss, 0));
5239 if ( targetRequiresWeakBinding(*pointerTarget) ) {
5240 // note: lazy pointers to weak symbols are not bound lazily
5241 fWeakBindingInfo.push_back(BindingInfo(type, pointerTarget->getName(), false, addresss, 0));
5245 if ( curSection->fAllNonLazyPointers && fOptions.makeCompressedDyldInfo() ) {
5246 if ( pointerTarget != NULL ) {
5247 switch ( this->relocationNeededInFinalLinkedImage(*pointerTarget) ) {
5249 // no rebase or binding info needed
5251 case kRelocInternal:
5252 // a non-lazy pointer that has been optimized to LOCAL needs rebasing info
5253 // but not the magic fFastStubGOTAtom atom
5254 if (atom != fFastStubGOTAtom)
5255 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5257 case kRelocExternal:
5259 uint8_t type = BIND_TYPE_POINTER;
5260 uint64_t addresss = atom->getAddress();
5261 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5262 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, 0));
5263 // if this is a non-lazy pointer to a weak definition within this linkage unit
5264 // the pointer needs to initially point within linkage unit and have
5265 // rebase command to slide it.
5266 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5267 // unless if this is a hybrid format, in which case the non-lazy pointer
5268 // is zero on disk. So use a bind instead of a rebase to set initial value
5269 if ( fOptions.makeClassicDyldInfo() )
5270 fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, 0));
5272 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5274 // if this is a non-lazy pointer to a weak definition in a dylib,
5275 // the pointer needs to initially bind to the dylib
5276 else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5277 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5278 fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, pointerTarget->getName(), false, addresss, 0));
5282 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5283 bool weak_import = fWeakImportMap[pointerTarget];
5284 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, 0));
5291 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
5292 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
5293 if ( fOptions.allowTextRelocs() ) {
5294 if ( fOptions.warnAboutTextRelocs() )
5295 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5298 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
5299 atom->getDisplayName(), atom->getFile()->getPath());
5302 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
5306 case kRelocInternal:
5308 macho_relocation_info<P> internalReloc;
5309 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
5310 uint32_t sectionNum = sectInfo->getIndex();
5311 // special case _mh_dylib_header and friends which are not in any real section
5312 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
5314 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5315 internalReloc.set_r_symbolnum(sectionNum);
5316 internalReloc.set_r_pcrel(false);
5317 internalReloc.set_r_length();
5318 internalReloc.set_r_extern(false);
5319 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5320 fInternalRelocs.push_back(internalReloc);
5321 if ( fOptions.makeCompressedDyldInfo() ) {
5322 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, atom->getAddress() + ref->getFixUpOffset()));
5326 case kRelocExternal:
5328 macho_relocation_info<P> externalReloc;
5329 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5330 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
5331 externalReloc.set_r_pcrel(false);
5332 externalReloc.set_r_length();
5333 externalReloc.set_r_extern(true);
5334 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5335 fExternalRelocs.push_back(externalReloc);
5336 if ( fOptions.makeCompressedDyldInfo() ) {
5337 int64_t addend = ref->getTargetOffset();
5338 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5339 if ( !fOptions.makeClassicDyldInfo() ) {
5340 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5341 // pointers to internal weak defs need a rebase
5342 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, addresss));
5345 uint8_t type = BIND_TYPE_POINTER;
5346 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5347 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, addend));
5348 if ( fOptions.makeClassicDyldInfo() && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
5349 // hybrid linkedit puts addend in data, so we need bind phase to reset pointer to local definifion
5350 fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, addend));
5352 // if this is a pointer to a weak definition in a dylib,
5353 // the pointer needs to initially bind to the dylib
5354 else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5355 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5356 fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, ref->getTarget().getName(), false, addresss, addend));
5360 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5361 bool weak_import = fWeakImportMap[&(ref->getTarget())];
5362 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, addend));
5369 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
5370 // new x86 stubs always require text relocs
5371 if ( curSection->fAllStubs || curSection->fAllStubHelpers ) {
5372 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5373 // relocs added to fInternalRelocs
5376 else if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
5377 if ( fOptions.warnAboutTextRelocs() )
5378 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5379 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5380 // relocs added to fInternalRelocs
5382 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
5383 // relocs added to fExternalRelocs
5386 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
5390 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
5391 "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
5395 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
5396 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
5397 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
5398 uint32_t offsetInSection = atom->getSectionOffset();
5399 uint32_t indexInSection = offsetInSection / atom->getSize();
5400 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5401 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5402 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
5403 fIndirectTableAtom->fTable.push_back(entry);
5409 if ( fSplitCodeToDataContentAtom != NULL )
5410 fSplitCodeToDataContentAtom->encode();
5411 if ( fCompressedRebaseInfoAtom != NULL )
5412 fCompressedRebaseInfoAtom->encode();
5413 if ( fCompressedBindingInfoAtom != NULL )
5414 fCompressedBindingInfoAtom->encode();
5415 if ( fCompressedWeakBindingInfoAtom != NULL )
5416 fCompressedWeakBindingInfoAtom->encode();
5417 if ( fCompressedLazyBindingInfoAtom != NULL )
5418 fCompressedLazyBindingInfoAtom->encode();
5419 if ( fCompressedExportInfoAtom != NULL )
5420 fCompressedExportInfoAtom->encode();
5425 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5427 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
5428 case ppc::kPICBaseHigh16:
5429 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5431 case ppc::kPointerDiff32:
5432 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5434 case ppc::kPointerDiff64:
5435 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5438 case ppc::kGroupSubordinate:
5440 case ppc::kPointerWeakImport:
5441 case ppc::kPICBaseLow16:
5442 case ppc::kPICBaseLow14:
5446 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5447 fSplitCodeToDataContentAtom->setCantEncode();
5452 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5454 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
5455 case ppc64::kPICBaseHigh16:
5456 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5458 case ppc64::kPointerDiff32:
5459 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5461 case ppc64::kPointerDiff64:
5462 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5464 case ppc64::kNoFixUp:
5465 case ppc64::kGroupSubordinate:
5466 case ppc64::kPointer:
5467 case ppc64::kPointerWeakImport:
5468 case ppc64::kPICBaseLow16:
5469 case ppc64::kPICBaseLow14:
5473 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5474 fSplitCodeToDataContentAtom->setCantEncode();
5479 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5481 switch ( (x86::ReferenceKinds)ref->getKind() ) {
5482 case x86::kPointerDiff:
5483 case x86::kImageOffset32:
5484 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
5485 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5487 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5490 case x86::kGroupSubordinate:
5492 case x86::kPointerWeakImport:
5496 case x86::kPCRel32WeakImport:
5497 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
5498 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
5499 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5502 // fall into warning case
5504 if ( fOptions.makeCompressedDyldInfo() && (ref->getKind() == x86::kAbsolute32) ) {
5505 // will be encoded in rebase info
5508 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
5509 fSplitCodeToDataContentAtom->setCantEncode();
5515 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5517 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
5518 case x86_64::kPCRel32:
5519 case x86_64::kPCRel32_1:
5520 case x86_64::kPCRel32_2:
5521 case x86_64::kPCRel32_4:
5522 case x86_64::kPCRel32GOTLoad:
5523 case x86_64::kPCRel32GOTLoadWeakImport:
5524 case x86_64::kPCRel32GOT:
5525 case x86_64::kPCRel32GOTWeakImport:
5526 case x86_64::kPointerDiff32:
5527 case x86_64::kImageOffset32:
5528 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5530 case x86_64::kPointerDiff:
5531 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5533 case x86_64::kNoFixUp:
5534 case x86_64::kGroupSubordinate:
5535 case x86_64::kPointer:
5536 case x86_64::kGOTNoFixUp:
5540 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
5541 fSplitCodeToDataContentAtom->setCantEncode();
5546 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5548 switch ( (arm::ReferenceKinds)ref->getKind() ) {
5549 case arm::kPointerDiff:
5550 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5553 case arm::kGroupSubordinate:
5555 case arm::kPointerWeakImport:
5556 case arm::kReadOnlyPointer:
5560 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
5561 fSplitCodeToDataContentAtom->setCantEncode();
5565 template <typename A>
5566 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
5568 switch ( to.getDefinitionKind() ) {
5569 case ObjectFile::Atom::kExternalDefinition:
5570 case ObjectFile::Atom::kExternalWeakDefinition:
5571 case ObjectFile::Atom::kAbsoluteSymbol:
5573 case ObjectFile::Atom::kRegularDefinition:
5574 case ObjectFile::Atom::kWeakDefinition:
5575 case ObjectFile::Atom::kTentativeDefinition:
5576 // segments with same permissions slide together
5577 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
5578 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
5580 throw "ld64 internal error";
5585 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
5588 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5589 for (uint32_t p=from; p < to; p += 4)
5590 ::pwrite(fd, &ppcNop, 4, p);
5594 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5597 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5598 for (uint32_t p=from; p < to; p += 4)
5599 ::pwrite(fd, &ppcNop, 4, p);
5603 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
5605 uint8_t x86Nop = 0x90;
5606 for (uint32_t p=from; p < to; ++p)
5607 ::pwrite(fd, &x86Nop, 1, p);
5611 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5613 uint8_t x86Nop = 0x90;
5614 for (uint32_t p=from; p < to; ++p)
5615 ::pwrite(fd, &x86Nop, 1, p);
5619 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
5621 // FIXME: need thumb nop?
5623 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
5624 for (uint32_t p=from; p < to; p += 4)
5625 ::pwrite(fd, &armNop, 4, p);
5629 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
5631 for (uint8_t* p=from; p < to; p += 4)
5632 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5636 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
5638 for (uint8_t* p=from; p < to; p += 4)
5639 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5643 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
5645 for (uint8_t* p=from; p < to; ++p)
5650 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
5652 for (uint8_t* p=from; p < to; ++p)
5657 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
5659 // fixme: need thumb nop?
5660 for (uint8_t* p=from; p < to; p += 4)
5661 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
5664 static const char* stringName(const char* str)
5666 if ( strncmp(str, "cstring=", 8) == 0) {
5667 static char buffer[1024];
5670 for(const char*s = &str[8]; *s != '\0'; ++s) {
5684 if ( t > &buffer[1020] ) {
5703 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
5704 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
5705 template <> const char* Writer<x86>::getArchString() { return "i386"; }
5706 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
5707 template <> const char* Writer<arm>::getArchString() { return "arm"; }
5709 template <typename A>
5710 void Writer<A>::writeMap()
5712 if ( fOptions.generatedMapPath() != NULL ) {
5713 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
5714 if ( mapFile != NULL ) {
5715 // write output path
5716 fprintf(mapFile, "# Path: %s\n", fFilePath);
5717 // write output architecure
5718 fprintf(mapFile, "# Arch: %s\n", getArchString());
5720 if ( fUUIDAtom != NULL ) {
5721 const uint8_t* uuid = fUUIDAtom->getUUID();
5722 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
5723 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
5724 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
5726 // write table of object files
5727 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
5728 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
5729 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
5730 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5731 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5732 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5733 if ( ! (*secit)->fVirtualSection ) {
5734 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5735 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5736 ObjectFile::Reader* reader = (*ait)->getFile();
5737 uint32_t readerOrdinal = (*ait)->getOrdinal();
5738 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
5739 if ( pos == readerToOrdinal.end() ) {
5740 readerToOrdinal[reader] = readerOrdinal;
5741 ordinalToReader[readerOrdinal] = reader;
5747 fprintf(mapFile, "# Object files:\n");
5748 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
5749 uint32_t fileIndex = 0;
5750 readerToFileOrdinal[this] = fileIndex++;
5751 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
5752 if ( it->first != 0 ) {
5753 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
5754 readerToFileOrdinal[it->second] = fileIndex++;
5757 // write table of sections
5758 fprintf(mapFile, "# Sections:\n");
5759 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
5760 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5761 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5762 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5763 if ( ! (*secit)->fVirtualSection ) {
5764 SectionInfo* sect = *secit;
5765 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
5766 (*segit)->fName, sect->fSectionName);
5770 // write table of symbols
5771 fprintf(mapFile, "# Symbols:\n");
5772 fprintf(mapFile, "# Address\tSize \tFile Name\n");
5773 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5774 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5775 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5776 if ( ! (*secit)->fVirtualSection ) {
5777 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5778 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
5779 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5780 ObjectFile::Atom* atom = *ait;
5781 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
5782 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
5790 warning("could not write map file: %s\n", fOptions.generatedMapPath());
5795 static const char* sCleanupFile = NULL;
5796 static void cleanup(int sig)
5798 ::signal(sig, SIG_DFL);
5799 if ( sCleanupFile != NULL ) {
5800 ::unlink(sCleanupFile);
5802 if ( sig == SIGINT )
5807 template <typename A>
5808 uint64_t Writer<A>::writeAtoms()
5810 // for UNIX conformance, error if file exists and is not writable
5811 if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
5812 throwf("can't write output file: %s", fFilePath);
5814 int permissions = 0777;
5815 if ( fOptions.outputKind() == Options::kObjectFile )
5817 // Calling unlink first assures the file is gone so that open creates it with correct permissions
5818 // It also handles the case where fFilePath file is not writable but its directory is
5819 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
5820 (void)unlink(fFilePath);
5822 // try to allocate buffer for entire output file content
5824 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
5825 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
5826 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
5827 uint8_t* atomBuffer = NULL;
5828 bool streaming = false;
5829 if ( wholeBuffer == NULL ) {
5830 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
5832 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
5833 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
5835 // install signal handlers to delete output file if program is killed
5836 sCleanupFile = fFilePath;
5837 ::signal(SIGINT, cleanup);
5838 ::signal(SIGBUS, cleanup);
5839 ::signal(SIGSEGV, cleanup);
5844 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5845 SegmentInfo* curSegment = *segit;
5846 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5847 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5848 SectionInfo* curSection = *secit;
5849 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5850 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
5851 //fprintf(stderr, "writing %lu atoms for section %p %s at file offset 0x%08llX\n", sectionAtoms.size(), curSection, curSection->fSectionName, curSection->fFileOffset);
5852 if ( ! curSection->fAllZeroFill ) {
5853 bool needsNops = ((strcmp(curSection->fSegmentName, "__TEXT") == 0) && (strncmp(curSection->fSectionName, "__text", 6) == 0));
5854 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5855 ObjectFile::Atom* atom = *ait;
5856 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
5857 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
5858 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
5859 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
5860 if ( fileOffset != end ) {
5861 //fprintf(stderr, "writing %d pad bytes, needsNops=%d\n", fileOffset-end, needsNops);
5863 // fill gaps with no-ops
5865 writeNoOps(fd, end, fileOffset);
5867 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
5869 else if ( streaming ) {
5871 if ( (fileOffset-end) == 4 ) {
5873 ::pwrite(fd, &zero, 4, end);
5876 uint8_t zero = 0x00;
5877 for (uint32_t p=end; p < fileOffset; ++p)
5878 ::pwrite(fd, &zero, 1, p);
5882 uint64_t atomSize = atom->getSize();
5884 if ( atomSize > fLargestAtomSize )
5885 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
5886 atom->getDisplayName(), atomSize, fLargestAtomSize);
5889 if ( fileOffset > fileBufferSize )
5890 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
5891 atom->getDisplayName(), fileOffset, fileBufferSize);
5893 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
5894 end = fileOffset+atomSize;
5896 atom->copyRawContent(buffer);
5897 // apply any fix-ups
5899 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5900 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
5901 ObjectFile::Reference* ref = *it;
5902 if ( fOptions.outputKind() == Options::kObjectFile ) {
5904 // skip fix-ups for undefined targets
5905 if ( &(ref->getTarget()) != NULL )
5906 this->fixUpReferenceRelocatable(ref, atom, buffer);
5909 // producing final linked image
5910 this->fixUpReferenceFinal(ref, atom, buffer);
5914 catch (const char* msg) {
5915 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
5917 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %p %s from %s\n",
5918 // fileOffset, end, atom->getAddress(), atom->getSize(), atom, atom->getDisplayName(), atom->getFile()->getPath());
5921 ::pwrite(fd, buffer, atomSize, fileOffset);
5924 if ( (fileOffset + atomSize) > size )
5925 size = fileOffset + atomSize;
5933 // update content based UUID
5934 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
5935 uint8_t digest[CC_MD5_DIGEST_LENGTH];
5937 // if output file file did not fit in memory, re-read file to generate md5 hash
5938 uint32_t kMD5BufferSize = 16*1024;
5939 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
5940 if ( md5Buffer != NULL ) {
5941 CC_MD5_CTX md5State;
5942 CC_MD5_Init(&md5State);
5943 ::lseek(fd, 0, SEEK_SET);
5945 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
5946 CC_MD5_Update(&md5State, md5Buffer, len);
5947 CC_MD5_Final(digest, &md5State);
5951 // if malloc fails, fall back to random uuid
5952 ::uuid_generate_random(digest);
5954 fUUIDAtom->setContent(digest);
5955 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
5956 fUUIDAtom->copyRawContent(atomBuffer);
5957 ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
5960 // if output file fit in memory, just genrate an md5 hash in memory
5962 // temp hack for building on Tiger
5963 CC_MD5_CTX md5State;
5964 CC_MD5_Init(&md5State);
5965 CC_MD5_Update(&md5State, wholeBuffer, size);
5966 CC_MD5_Final(digest, &md5State);
5968 CC_MD5(wholeBuffer, size, digest);
5970 fUUIDAtom->setContent(digest);
5971 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
5972 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
5977 if ( sCleanupFile != NULL )
5978 ::unlink(sCleanupFile);
5984 delete [] atomBuffer;
5986 // restore default signal handlers
5987 sCleanupFile = NULL;
5988 ::signal(SIGINT, SIG_DFL);
5989 ::signal(SIGBUS, SIG_DFL);
5990 ::signal(SIGSEGV, SIG_DFL);
5993 // write whole output file in one chunk
5994 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
5996 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
5997 ::pwrite(fd, wholeBuffer, size, 0);
5999 delete [] wholeBuffer;
6006 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6008 int64_t displacement;
6010 uint32_t instruction;
6011 uint32_t newInstruction;
6012 uint64_t targetAddr = 0;
6015 uint32_t opcode = 0;
6016 bool relocateableExternal = false;
6021 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6022 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6023 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
6026 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6027 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6029 case arm::kFollowOn:
6030 case arm::kGroupSubordinate:
6033 case arm::kPointerWeakImport:
6035 // If this is the lazy pointers section, then set all lazy pointers to
6036 // point to the dyld stub binding helper.
6037 if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers
6038 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
6039 switch (ref->getTarget().getDefinitionKind()) {
6040 case ObjectFile::Atom::kExternalDefinition:
6041 case ObjectFile::Atom::kExternalWeakDefinition:
6042 // prebound lazy pointer to another dylib ==> pointer contains zero
6043 LittleEndian::set32(*fixUp, 0);
6045 case ObjectFile::Atom::kTentativeDefinition:
6046 case ObjectFile::Atom::kRegularDefinition:
6047 case ObjectFile::Atom::kWeakDefinition:
6048 case ObjectFile::Atom::kAbsoluteSymbol:
6049 // prebound lazy pointer to withing this dylib ==> pointer contains address
6050 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6052 LittleEndian::set32(*fixUp, targetAddr);
6056 else if ( relocateableExternal ) {
6057 if ( fOptions.prebind() ) {
6058 switch (ref->getTarget().getDefinitionKind()) {
6059 case ObjectFile::Atom::kExternalDefinition:
6060 case ObjectFile::Atom::kExternalWeakDefinition:
6061 // prebound external relocation ==> pointer contains addend
6062 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6064 case ObjectFile::Atom::kTentativeDefinition:
6065 case ObjectFile::Atom::kRegularDefinition:
6066 case ObjectFile::Atom::kWeakDefinition:
6067 // prebound external relocation to internal atom ==> pointer contains target address + addend
6068 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6070 LittleEndian::set32(*fixUp, targetAddr);
6072 case ObjectFile::Atom::kAbsoluteSymbol:
6077 // external relocation ==> pointer contains addend
6078 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6082 // pointer contains target address
6083 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6085 LittleEndian::set32(*fixUp, targetAddr);
6088 case arm::kPointerDiff:
6089 LittleEndian::set32(*fixUp,
6090 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6092 case arm::kReadOnlyPointer:
6093 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6095 switch ( ref->getTarget().getDefinitionKind() ) {
6096 case ObjectFile::Atom::kRegularDefinition:
6097 case ObjectFile::Atom::kWeakDefinition:
6098 case ObjectFile::Atom::kTentativeDefinition:
6099 // pointer contains target address
6100 LittleEndian::set32(*fixUp, targetAddr);
6102 case ObjectFile::Atom::kExternalDefinition:
6103 case ObjectFile::Atom::kExternalWeakDefinition:
6104 // external relocation ==> pointer contains addend
6105 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6107 case ObjectFile::Atom::kAbsoluteSymbol:
6108 // pointer contains target address
6109 LittleEndian::set32(*fixUp, targetAddr);
6113 case arm::kBranch24WeakImport:
6114 case arm::kBranch24:
6115 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6116 // The pc added will be +8 from the pc
6118 // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6119 // max positive displacement is 0x007FFFFF << 2
6120 // max negative displacement is 0xFF800000 << 2
6121 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6122 throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6123 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6124 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6126 instruction = LittleEndian::get32(*fixUp);
6127 // Make sure we are calling arm with bl, thumb with blx
6128 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6129 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6130 if ( is_bl && ref->getTarget().isThumb() ) {
6131 uint32_t opcode = 0xFA000000;
6132 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6133 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6134 newInstruction = opcode | h_bit | disp;
6136 else if ( is_blx && !ref->getTarget().isThumb() ) {
6137 uint32_t opcode = 0xEB000000;
6138 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6139 newInstruction = opcode | disp;
6141 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6142 throwf("don't know how to convert instruction %x referencing %s to thumb",
6143 instruction, ref->getTarget().getDisplayName());
6146 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6148 LittleEndian::set32(*fixUp, newInstruction);
6150 case arm::kThumbBranch22WeakImport:
6151 case arm::kThumbBranch22:
6152 instruction = LittleEndian::get32(*fixUp);
6153 is_bl = ((instruction & 0xD000F800) == 0xD000F000);
6154 is_blx = ((instruction & 0xD000F800) == 0xC000F000);
6155 targetIsThumb = ref->getTarget().isThumb();
6157 // The pc added will be +4 from the pc
6158 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6159 // If the target is not thumb, we will be generating a blx instruction
6160 // Since blx cannot have the low bit set, set bit[1] of the target to
6161 // bit[1] of the base address, so that the difference is a multiple of
6163 if ( !targetIsThumb ) {
6164 targetAddr &= -3ULL;
6165 targetAddr |= (baseAddr & 2LL);
6167 displacement = targetAddr - baseAddr;
6169 // max positive displacement is 0x003FFFFE
6170 // max negative displacement is 0xFFC00000
6171 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6172 // armv7 supports a larger displacement
6173 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6174 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6175 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6176 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6177 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6180 // The instruction is really two instructions:
6181 // The lower 16 bits are the first instruction, which contains the high
6182 // 11 bits of the displacement.
6183 // The upper 16 bits are the second instruction, which contains the low
6184 // 11 bits of the displacement, as well as differentiating bl and blx.
6185 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6186 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6187 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6188 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6189 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6190 uint32_t j1 = (i1 == s);
6191 uint32_t j2 = (i2 == s);
6193 if ( targetIsThumb )
6194 opcode = 0xD000F000; // keep bl
6196 opcode = 0xC000F000; // change to blx
6198 else if ( is_blx ) {
6199 if ( targetIsThumb )
6200 opcode = 0xD000F000; // change to bl
6202 opcode = 0xC000F000; // keep blx
6204 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6205 throwf("don't know how to convert instruction %x referencing %s to arm",
6206 instruction, ref->getTarget().getDisplayName());
6208 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6209 firstDisp = (s << 10) | imm10;
6210 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6211 //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",
6212 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6213 LittleEndian::set32(*fixUp, newInstruction);
6217 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6218 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6219 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6223 // The instruction is really two instructions:
6224 // The lower 16 bits are the first instruction, which contains the high
6225 // 11 bits of the displacement.
6226 // The upper 16 bits are the second instruction, which contains the low
6227 // 11 bits of the displacement, as well as differentiating bl and blx.
6228 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6229 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6230 if ( is_bl && !targetIsThumb ) {
6231 opcode = 0xE800F000;
6233 else if ( is_blx && targetIsThumb ) {
6234 opcode = 0xF800F000;
6236 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6237 throwf("don't know how to convert instruction %x referencing %s to arm",
6238 instruction, ref->getTarget().getDisplayName());
6241 opcode = instruction & 0xF800F800;
6243 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6244 LittleEndian::set32(*fixUp, newInstruction);
6247 case arm::kDtraceProbeSite:
6248 if ( inAtom->isThumb() ) {
6249 // change 32-bit blx call site to two thumb NOPs
6250 LittleEndian::set32(*fixUp, 0x46C046C0);
6253 // change call site to a NOP
6254 LittleEndian::set32(*fixUp, 0xE1A00000);
6257 case arm::kDtraceIsEnabledSite:
6258 if ( inAtom->isThumb() ) {
6259 // change 32-bit blx call site to 'nop', 'eor r0, r0'
6260 LittleEndian::set32(*fixUp, 0x46C04040);
6263 // change call site to 'eor r0, r0, r0'
6264 LittleEndian::set32(*fixUp, 0xE0200000);
6267 case arm::kDtraceTypeReference:
6268 case arm::kDtraceProbe:
6269 // nothing to fix up
6272 throw "boom shaka laka";
6277 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6279 int64_t displacement;
6280 uint32_t instruction;
6281 uint32_t newInstruction;
6282 uint64_t targetAddr = 0;
6286 uint32_t opcode = 0;
6287 bool relocateableExternal = false;
6292 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6293 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6294 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
6297 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6298 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6300 case arm::kFollowOn:
6301 case arm::kGroupSubordinate:
6305 case arm::kReadOnlyPointer:
6306 case arm::kPointerWeakImport:
6308 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6309 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
6310 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6311 LittleEndian::set32(*fixUp, targetAddr);
6313 LittleEndian::set32(*fixUp, 0);
6315 else if ( relocateableExternal ) {
6316 if ( fOptions.prebind() ) {
6317 switch (ref->getTarget().getDefinitionKind()) {
6318 case ObjectFile::Atom::kExternalDefinition:
6319 case ObjectFile::Atom::kExternalWeakDefinition:
6320 // prebound external relocation ==> pointer contains addend
6321 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6323 case ObjectFile::Atom::kTentativeDefinition:
6324 case ObjectFile::Atom::kRegularDefinition:
6325 case ObjectFile::Atom::kWeakDefinition:
6326 // prebound external relocation to internal atom ==> pointer contains target address + addend
6327 LittleEndian::set32(*fixUp, targetAddr);
6329 case ObjectFile::Atom::kAbsoluteSymbol:
6335 // internal relocation
6336 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6337 // pointer contains target address
6338 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6340 LittleEndian::set32(*fixUp, targetAddr);
6343 // pointer contains addend
6344 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6349 case arm::kPointerDiff:
6350 LittleEndian::set32(*fixUp,
6351 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6353 case arm::kDtraceProbeSite:
6354 case arm::kDtraceIsEnabledSite:
6355 case arm::kBranch24WeakImport:
6356 case arm::kBranch24:
6357 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6358 // The pc added will be +8 from the pc
6360 // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6361 if ( relocateableExternal ) {
6362 // doing "ld -r" to an external symbol
6363 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6364 displacement -= ref->getTarget().getAddress();
6367 // max positive displacement is 0x007FFFFF << 2
6368 // max negative displacement is 0xFF800000 << 2
6369 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6370 throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6371 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6372 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6375 instruction = LittleEndian::get32(*fixUp);
6376 // Make sure we are calling arm with bl, thumb with blx
6377 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6378 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6379 if ( is_bl && ref->getTarget().isThumb() ) {
6380 uint32_t opcode = 0xFA000000;
6381 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6382 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6383 newInstruction = opcode | h_bit | disp;
6385 else if ( is_blx && !ref->getTarget().isThumb() ) {
6386 uint32_t opcode = 0xEB000000;
6387 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6388 newInstruction = opcode | disp;
6390 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6391 throwf("don't know how to convert instruction %x referencing %s to thumb",
6392 instruction, ref->getTarget().getDisplayName());
6395 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6397 LittleEndian::set32(*fixUp, newInstruction);
6399 case arm::kThumbBranch22WeakImport:
6400 case arm::kThumbBranch22:
6401 instruction = LittleEndian::get32(*fixUp);
6402 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
6403 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
6404 targetIsThumb = ref->getTarget().isThumb();
6406 // The pc added will be +4 from the pc
6407 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6408 // If the target is not thumb, we will be generating a blx instruction
6409 // Since blx cannot have the low bit set, set bit[1] of the target to
6410 // bit[1] of the base address, so that the difference is a multiple of
6412 if (!targetIsThumb) {
6413 targetAddr &= -3ULL;
6414 targetAddr |= (baseAddr & 2LL);
6416 displacement = targetAddr - baseAddr;
6418 //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);
6419 if ( relocateableExternal ) {
6420 // doing "ld -r" to an external symbol
6421 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6422 displacement -= ref->getTarget().getAddress();
6425 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6426 // armv7 supports a larger displacement
6427 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6428 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6429 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6430 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6431 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6434 // The instruction is really two instructions:
6435 // The lower 16 bits are the first instruction, which contains the high
6436 // 11 bits of the displacement.
6437 // The upper 16 bits are the second instruction, which contains the low
6438 // 11 bits of the displacement, as well as differentiating bl and blx.
6439 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6440 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6441 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6442 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6443 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6444 uint32_t j1 = (i1 == s);
6445 uint32_t j2 = (i2 == s);
6447 if ( targetIsThumb )
6448 opcode = 0xD000F000; // keep bl
6450 opcode = 0xC000F000; // change to blx
6452 else if ( is_blx ) {
6453 if ( targetIsThumb )
6454 opcode = 0xD000F000; // change to bl
6456 opcode = 0xC000F000; // keep blx
6458 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6459 throwf("don't know how to convert instruction %x referencing %s to arm",
6460 instruction, ref->getTarget().getDisplayName());
6462 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6463 firstDisp = (s << 10) | imm10;
6464 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6465 //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",
6466 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6467 LittleEndian::set32(*fixUp, newInstruction);
6472 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6473 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6474 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6477 // The instruction is really two instructions:
6478 // The lower 16 bits are the first instruction, which contains the first
6479 // 11 bits of the displacement.
6480 // The upper 16 bits are the second instruction, which contains the next
6481 // 11 bits of the displacement, as well as differentiating bl and blx.
6482 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6483 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6484 if ( is_bl && !targetIsThumb ) {
6485 opcode = 0xE800F000;
6487 else if ( is_blx && targetIsThumb ) {
6488 opcode = 0xF800F000;
6490 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6491 throwf("don't know how to convert instruction %x referencing %s to arm",
6492 instruction, ref->getTarget().getDisplayName());
6495 opcode = instruction & 0xF800F800;
6497 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6498 LittleEndian::set32(*fixUp, newInstruction);
6500 case arm::kDtraceProbe:
6501 case arm::kDtraceTypeReference:
6502 // nothing to fix up
6508 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6510 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6511 uint8_t* dtraceProbeSite;
6512 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6513 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6514 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6515 const int64_t kOneTwentyEightLimit = 0x7F;
6516 int64_t displacement;
6518 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6521 case x86::kFollowOn:
6522 case x86::kGroupSubordinate:
6525 case x86::kPointerWeakImport:
6528 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6529 if ( fOptions.prebind() ) {
6530 switch (ref->getTarget().getDefinitionKind()) {
6531 case ObjectFile::Atom::kExternalDefinition:
6532 case ObjectFile::Atom::kExternalWeakDefinition:
6533 // prebound external relocation ==> pointer contains addend
6534 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6536 case ObjectFile::Atom::kTentativeDefinition:
6537 case ObjectFile::Atom::kRegularDefinition:
6538 case ObjectFile::Atom::kWeakDefinition:
6539 // prebound external relocation to internal atom ==> pointer contains target address + addend
6540 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6542 case ObjectFile::Atom::kAbsoluteSymbol:
6546 else if ( !fOptions.makeClassicDyldInfo()
6547 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6548 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
6549 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6552 // external relocation ==> pointer contains addend
6553 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6557 // pointer contains target address
6558 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6559 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6563 case x86::kPointerDiff:
6564 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6565 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6567 case x86::kPointerDiff16:
6568 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6569 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6570 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6571 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6573 case x86::kPointerDiff24:
6574 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6575 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6576 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6577 temp = LittleEndian::get32(*fixUp);
6579 temp |= (displacement & 0x00FFFFFF);
6580 LittleEndian::set32(*fixUp, temp);
6582 case x86::kSectionOffset24:
6583 displacement = ref->getTarget().getSectionOffset();
6584 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6585 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6586 temp = LittleEndian::get32(*fixUp);
6588 temp |= (displacement & 0x00FFFFFF);
6589 LittleEndian::set32(*fixUp, temp);
6591 case x86::kDtraceProbeSite:
6592 // change call site to a NOP
6593 dtraceProbeSite = (uint8_t*)fixUp;
6594 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6595 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6596 dtraceProbeSite[1] = 0x1F;
6597 dtraceProbeSite[2] = 0x40;
6598 dtraceProbeSite[3] = 0x00;
6600 case x86::kDtraceIsEnabledSite:
6601 // change call site to a clear eax
6602 dtraceProbeSite = (uint8_t*)fixUp;
6603 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
6604 dtraceProbeSite[0] = 0xC0;
6605 dtraceProbeSite[1] = 0x90; // 1-byte nop
6606 dtraceProbeSite[2] = 0x90; // 1-byte nop
6607 dtraceProbeSite[3] = 0x90; // 1-byte nop
6609 case x86::kPCRel32WeakImport:
6614 switch ( ref->getTarget().getDefinitionKind() ) {
6615 case ObjectFile::Atom::kRegularDefinition:
6616 case ObjectFile::Atom::kWeakDefinition:
6617 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6619 case ObjectFile::Atom::kExternalDefinition:
6620 case ObjectFile::Atom::kExternalWeakDefinition:
6621 throw "codegen problem, can't use rel32 to external symbol";
6622 case ObjectFile::Atom::kTentativeDefinition:
6625 case ObjectFile::Atom::kAbsoluteSymbol:
6626 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6629 if ( kind == x86::kPCRel8 ) {
6631 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6632 //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());
6633 throwf("rel8 out of range in %s", inAtom->getDisplayName());
6635 *(int8_t*)fixUp = (int8_t)displacement;
6637 else if ( kind == x86::kPCRel16 ) {
6639 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6640 //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());
6641 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6643 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6646 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6647 //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());
6648 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6650 LittleEndian::set32(*fixUp, (int32_t)displacement);
6653 case x86::kAbsolute32:
6654 switch ( ref->getTarget().getDefinitionKind() ) {
6655 case ObjectFile::Atom::kRegularDefinition:
6656 case ObjectFile::Atom::kWeakDefinition:
6657 case ObjectFile::Atom::kTentativeDefinition:
6658 // pointer contains target address
6659 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6661 case ObjectFile::Atom::kExternalDefinition:
6662 case ObjectFile::Atom::kExternalWeakDefinition:
6663 // external relocation ==> pointer contains addend
6664 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6666 case ObjectFile::Atom::kAbsoluteSymbol:
6667 // pointer contains target address
6668 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
6672 case x86::kImageOffset32:
6673 // offset of target atom from mach_header
6674 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6675 LittleEndian::set32(*fixUp, (int32_t)displacement);
6677 case x86::kDtraceTypeReference:
6678 case x86::kDtraceProbe:
6679 // nothing to fix up
6687 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6689 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6690 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6691 const int64_t kOneTwentyEightLimit = 0x7F;
6692 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6693 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
6694 int64_t displacement;
6695 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6698 case x86::kFollowOn:
6699 case x86::kGroupSubordinate:
6703 case x86::kPointerWeakImport:
6704 case x86::kAbsolute32:
6706 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6707 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
6708 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6709 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6711 LittleEndian::set32(*fixUp, 0);
6713 else if ( isExtern ) {
6714 // external relocation ==> pointer contains addend
6715 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6717 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6718 // internal relocation => pointer contains target address
6719 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6722 // internal relocation to tentative ==> pointer contains addend
6723 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6727 case x86::kPointerDiff:
6728 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6729 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6731 case x86::kPointerDiff16:
6732 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6733 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6734 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6735 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6740 case x86::kPCRel32WeakImport:
6741 case x86::kDtraceProbeSite:
6742 case x86::kDtraceIsEnabledSite:
6745 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6747 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6748 if ( kind == x86::kPCRel8 ) {
6750 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6751 //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());
6752 throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
6754 int8_t byte = (int8_t)displacement;
6755 *((int8_t*)fixUp) = byte;
6757 else if ( kind == x86::kPCRel16 ) {
6759 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6760 //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());
6761 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6763 int16_t word = (int16_t)displacement;
6764 LittleEndian::set16(*((uint16_t*)fixUp), word);
6767 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6768 //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement,
6769 // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6770 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6772 LittleEndian::set32(*fixUp, (int32_t)displacement);
6776 case x86::kPointerDiff24:
6777 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
6778 case x86::kImageOffset32:
6779 throw "internal linker error, kImageOffset32 can't be encoded into object files";
6780 case x86::kSectionOffset24:
6781 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
6782 case x86::kDtraceProbe:
6783 case x86::kDtraceTypeReference:
6784 // nothing to fix up
6790 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6792 const int64_t twoGigLimit = 0x7FFFFFFF;
6793 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6794 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
6795 uint8_t* dtraceProbeSite;
6796 int64_t displacement = 0;
6798 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
6799 case x86_64::kNoFixUp:
6800 case x86_64::kGOTNoFixUp:
6801 case x86_64::kFollowOn:
6802 case x86_64::kGroupSubordinate:
6805 case x86_64::kPointerWeakImport:
6806 case x86_64::kPointer:
6808 if ( &ref->getTarget() != NULL ) {
6809 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
6810 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal) {
6811 if ( !fOptions.makeClassicDyldInfo()
6812 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6813 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
6814 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6817 // external relocation ==> pointer contains addend
6818 LittleEndian::set64(*fixUp, ref->getTargetOffset());
6822 // internal relocation
6823 // pointer contains target address
6824 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6825 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6830 case x86_64::kPointer32:
6832 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
6833 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6834 // external relocation
6835 throwf("32-bit pointer to dylib or weak symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
6838 // internal relocation
6839 // pointer contains target address
6840 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6841 displacement = ref->getTarget().getAddress() + ref->getTargetOffset();
6842 switch ( fOptions.outputKind() ) {
6843 case Options::kObjectFile:
6844 case Options::kPreload:
6845 case Options::kDyld:
6846 case Options::kDynamicLibrary:
6847 case Options::kDynamicBundle:
6848 case Options::kKextBundle:
6849 throwf("32-bit pointer to symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
6850 case Options::kDynamicExecutable:
6851 // <rdar://problem/5855588> allow x86_64 main executables to use 32-bit pointers if program loads in load 2GB
6852 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
6853 throw "32-bit pointer out of range";
6855 case Options::kStaticExecutable:
6856 // <rdar://problem/5855588> allow x86_64 mach_kernel to truncate pointers
6859 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
6863 case x86_64::kPointerDiff32:
6864 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6865 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
6866 throw "32-bit pointer difference out of range";
6867 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
6869 case x86_64::kPointerDiff:
6870 LittleEndian::set64(*fixUp,
6871 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6873 case x86_64::kPointerDiff24:
6874 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6875 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6876 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6877 temp = LittleEndian::get32(*((uint32_t*)fixUp));
6879 temp |= (displacement & 0x00FFFFFF);
6880 LittleEndian::set32(*((uint32_t*)fixUp), temp);
6882 case x86_64::kSectionOffset24:
6883 displacement = ref->getTarget().getSectionOffset();
6884 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6885 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6886 temp = LittleEndian::get32(*((uint32_t*)fixUp));
6888 temp |= (displacement & 0x00FFFFFF);
6889 LittleEndian::set32(*((uint32_t*)fixUp), temp);
6891 case x86_64::kPCRel32GOTLoad:
6892 case x86_64::kPCRel32GOTLoadWeakImport:
6893 // if GOT entry was optimized away, change movq instruction to a leaq
6894 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
6895 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
6896 uint8_t* opcodes = (uint8_t*)fixUp;
6897 if ( opcodes[-2] != 0x8B )
6898 throw "GOT load reloc does not point to a movq instruction";
6901 // fall into general rel32 case
6902 case x86_64::kBranchPCRel32WeakImport:
6903 case x86_64::kBranchPCRel32:
6904 case x86_64::kBranchPCRel8:
6905 case x86_64::kPCRel32:
6906 case x86_64::kPCRel32_1:
6907 case x86_64::kPCRel32_2:
6908 case x86_64::kPCRel32_4:
6909 case x86_64::kPCRel32GOT:
6910 case x86_64::kPCRel32GOTWeakImport:
6911 switch ( ref->getTarget().getDefinitionKind() ) {
6912 case ObjectFile::Atom::kRegularDefinition:
6913 case ObjectFile::Atom::kWeakDefinition:
6914 case ObjectFile::Atom::kTentativeDefinition:
6915 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6917 case ObjectFile::Atom::kAbsoluteSymbol:
6918 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6920 case ObjectFile::Atom::kExternalDefinition:
6921 case ObjectFile::Atom::kExternalWeakDefinition:
6922 if ( fOptions.outputKind() == Options::kKextBundle )
6925 throwf("codegen problem, can't use rel32 to external symbol %s", ref->getTarget().getDisplayName());
6928 switch ( ref->getKind() ) {
6929 case x86_64::kPCRel32_1:
6932 case x86_64::kPCRel32_2:
6935 case x86_64::kPCRel32_4:
6938 case x86_64::kBranchPCRel8:
6942 if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
6943 if ( (displacement > 127) || (displacement < (-128)) ) {
6944 fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n",
6945 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
6946 throw "rel8 out of range";
6948 *((int8_t*)fixUp) = (int8_t)displacement;
6951 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
6952 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
6953 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
6954 throw "rel32 out of range";
6956 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
6959 case x86_64::kImageOffset32:
6960 // offset of target atom from mach_header
6961 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6962 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
6964 case x86_64::kDtraceProbeSite:
6965 // change call site to a NOP
6966 dtraceProbeSite = (uint8_t*)fixUp;
6967 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6968 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6969 dtraceProbeSite[1] = 0x1F;
6970 dtraceProbeSite[2] = 0x40;
6971 dtraceProbeSite[3] = 0x00;
6973 case x86_64::kDtraceIsEnabledSite:
6974 // change call site to a clear eax
6975 dtraceProbeSite = (uint8_t*)fixUp;
6976 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
6977 dtraceProbeSite[0] = 0x33;
6978 dtraceProbeSite[1] = 0xC0;
6979 dtraceProbeSite[2] = 0x90; // 1-byte nop
6980 dtraceProbeSite[3] = 0x90; // 1-byte nop
6982 case x86_64::kDtraceTypeReference:
6983 case x86_64::kDtraceProbe:
6984 // nothing to fix up
6990 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6992 const int64_t twoGigLimit = 0x7FFFFFFF;
6993 bool external = this->makesExternalRelocatableReference(ref->getTarget());
6994 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
6995 int64_t displacement = 0;
6997 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
6998 case x86_64::kNoFixUp:
6999 case x86_64::kGOTNoFixUp:
7000 case x86_64::kFollowOn:
7001 case x86_64::kGroupSubordinate:
7004 case x86_64::kPointer:
7005 case x86_64::kPointerWeakImport:
7008 // external relocation ==> pointer contains addend
7009 LittleEndian::set64(*fixUp, ref->getTargetOffset());
7012 // internal relocation ==> pointer contains target address
7013 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
7017 case x86_64::kPointer32:
7020 // external relocation ==> pointer contains addend
7021 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset());
7024 // internal relocation ==> pointer contains target address
7025 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTarget().getAddress() + ref->getTargetOffset());
7029 case x86_64::kPointerDiff32:
7030 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
7031 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7032 displacement += ref->getTarget().getAddress();
7033 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7034 displacement -= ref->getFromTarget().getAddress();
7035 LittleEndian::set32(*((uint32_t*)fixUp), displacement);
7037 case x86_64::kPointerDiff:
7038 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
7039 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7040 displacement += ref->getTarget().getAddress();
7041 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7042 displacement -= ref->getFromTarget().getAddress();
7043 LittleEndian::set64(*fixUp, displacement);
7045 case x86_64::kBranchPCRel32:
7046 case x86_64::kBranchPCRel32WeakImport:
7047 case x86_64::kDtraceProbeSite:
7048 case x86_64::kDtraceIsEnabledSite:
7049 case x86_64::kPCRel32:
7050 case x86_64::kPCRel32_1:
7051 case x86_64::kPCRel32_2:
7052 case x86_64::kPCRel32_4:
7053 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7054 temp32 = ref->getTargetOffset();
7056 // extern relocation contains addend
7057 displacement = temp32;
7060 // internal relocations contain delta to target address
7061 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7063 switch ( ref->getKind() ) {
7064 case x86_64::kPCRel32_1:
7067 case x86_64::kPCRel32_2:
7070 case x86_64::kPCRel32_4:
7074 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
7075 //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());
7076 throw "rel32 out of range";
7078 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
7080 case x86_64::kBranchPCRel8:
7081 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7082 temp32 = ref->getTargetOffset();
7084 // extern relocation contains addend
7085 displacement = temp32;
7088 // internal relocations contain delta to target address
7089 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
7091 if ( (displacement > 127) || (displacement < (-128)) ) {
7092 //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());
7093 throw "rel8 out of range";
7095 *((int8_t*)fixUp) = (int8_t)displacement;
7097 case x86_64::kPCRel32GOT:
7098 case x86_64::kPCRel32GOTLoad:
7099 case x86_64::kPCRel32GOTWeakImport:
7100 case x86_64::kPCRel32GOTLoadWeakImport:
7101 // contains addend (usually zero)
7102 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
7104 case x86_64::kPointerDiff24:
7105 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
7106 case x86_64::kImageOffset32:
7107 throw "internal linker error, kImageOffset32 can't be encoded into object files";
7108 case x86_64::kSectionOffset24:
7109 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
7110 case x86_64::kDtraceTypeReference:
7111 case x86_64::kDtraceProbe:
7112 // nothing to fix up
7118 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7120 fixUpReference_powerpc(ref, inAtom, buffer, true);
7124 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7126 fixUpReference_powerpc(ref, inAtom, buffer, true);
7130 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7132 fixUpReference_powerpc(ref, inAtom, buffer, false);
7136 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7138 fixUpReference_powerpc(ref, inAtom, buffer, false);
7142 // ppc and ppc64 are mostly the same, so they share a template specialzation
7144 template <typename A>
7145 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
7147 uint32_t instruction;
7148 uint32_t newInstruction;
7149 int64_t displacement;
7150 uint64_t targetAddr = 0;
7151 uint64_t picBaseAddr;
7152 uint16_t instructionLowHalf;
7153 uint16_t instructionHighHalf;
7154 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
7155 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
7156 bool relocateableExternal = false;
7157 const int64_t picbase_twoGigLimit = 0x80000000;
7159 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
7160 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
7161 if ( finalLinkedImage )
7162 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
7164 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
7167 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
7170 case A::kGroupSubordinate:
7173 case A::kPointerWeakImport:
7176 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
7177 if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers
7178 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
7179 switch (ref->getTarget().getDefinitionKind()) {
7180 case ObjectFile::Atom::kExternalDefinition:
7181 case ObjectFile::Atom::kExternalWeakDefinition:
7182 // prebound lazy pointer to another dylib ==> pointer contains zero
7183 P::setP(*fixUpPointer, 0);
7185 case ObjectFile::Atom::kTentativeDefinition:
7186 case ObjectFile::Atom::kRegularDefinition:
7187 case ObjectFile::Atom::kWeakDefinition:
7188 case ObjectFile::Atom::kAbsoluteSymbol:
7189 // prebound lazy pointer to withing this dylib ==> pointer contains address
7190 P::setP(*fixUpPointer, targetAddr);
7194 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
7195 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
7196 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
7197 P::setP(*fixUpPointer, targetAddr);
7199 P::setP(*fixUpPointer, 0);
7201 else if ( relocateableExternal ) {
7202 if ( fOptions.prebind() ) {
7203 switch (ref->getTarget().getDefinitionKind()) {
7204 case ObjectFile::Atom::kExternalDefinition:
7205 case ObjectFile::Atom::kExternalWeakDefinition:
7206 // prebound external relocation ==> pointer contains addend
7207 P::setP(*fixUpPointer, ref->getTargetOffset());
7209 case ObjectFile::Atom::kTentativeDefinition:
7210 case ObjectFile::Atom::kRegularDefinition:
7211 case ObjectFile::Atom::kWeakDefinition:
7212 // prebound external relocation to internal atom ==> pointer contains target address + addend
7213 P::setP(*fixUpPointer, targetAddr);
7215 case ObjectFile::Atom::kAbsoluteSymbol:
7220 // external relocation ==> pointer contains addend
7221 P::setP(*fixUpPointer, ref->getTargetOffset());
7225 // internal relocation
7226 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
7227 // pointer contains target address
7228 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
7229 P::setP(*fixUpPointer, targetAddr);
7232 // pointer contains addend
7233 P::setP(*fixUpPointer, ref->getTargetOffset());
7238 case A::kPointerDiff64:
7239 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7241 case A::kPointerDiff32:
7242 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7244 case A::kPointerDiff16:
7245 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7247 case A::kDtraceProbeSite:
7248 if ( finalLinkedImage ) {
7249 // change call site to a NOP
7250 BigEndian::set32(*fixUp, 0x60000000);
7253 // set bl instuction to branch to address zero in .o file
7254 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7255 instruction = BigEndian::get32(*fixUp);
7256 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7257 BigEndian::set32(*fixUp, newInstruction);
7260 case A::kDtraceIsEnabledSite:
7261 if ( finalLinkedImage ) {
7262 // change call site to a li r3,0
7263 BigEndian::set32(*fixUp, 0x38600000);
7266 // set bl instuction to branch to address zero in .o file
7267 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7268 instruction = BigEndian::get32(*fixUp);
7269 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7270 BigEndian::set32(*fixUp, newInstruction);
7273 case A::kBranch24WeakImport:
7276 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
7277 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7278 if ( relocateableExternal ) {
7279 // doing "ld -r" to an external symbol
7280 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7281 displacement -= ref->getTarget().getAddress();
7284 const int64_t bl_eightMegLimit = 0x00FFFFFF;
7285 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
7286 //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());
7287 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",
7288 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
7289 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
7292 instruction = BigEndian::get32(*fixUp);
7293 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7294 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7295 BigEndian::set32(*fixUp, newInstruction);
7300 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7301 if ( relocateableExternal ) {
7302 // doing "ld -r" to an external symbol
7303 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7304 displacement -= ref->getTarget().getAddress();
7306 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
7307 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
7308 //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());
7309 throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
7310 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
7311 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
7314 //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
7315 instruction = BigEndian::get32(*fixUp);
7316 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
7317 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7318 BigEndian::set32(*fixUp, newInstruction);
7321 case A::kPICBaseLow16:
7322 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7323 displacement = targetAddr - picBaseAddr;
7324 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7325 throw "32-bit pic-base out of range";
7326 instructionLowHalf = (displacement & 0xFFFF);
7327 instruction = BigEndian::get32(*fixUp);
7328 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7329 BigEndian::set32(*fixUp, newInstruction);
7331 case A::kPICBaseLow14:
7332 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7333 displacement = targetAddr - picBaseAddr;
7334 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7335 throw "32-bit pic-base out of range";
7336 if ( (displacement & 0x3) != 0 )
7337 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
7338 instructionLowHalf = (displacement & 0xFFFC);
7339 instruction = BigEndian::get32(*fixUp);
7340 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7341 BigEndian::set32(*fixUp, newInstruction);
7343 case A::kPICBaseHigh16:
7344 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7345 displacement = targetAddr - picBaseAddr;
7346 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7347 throw "32-bit pic-base out of range";
7348 instructionLowHalf = displacement >> 16;
7349 if ( (displacement & 0x00008000) != 0 )
7350 ++instructionLowHalf;
7351 instruction = BigEndian::get32(*fixUp);
7352 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7353 BigEndian::set32(*fixUp, newInstruction);
7356 if ( relocateableExternal && !finalLinkedImage )
7357 targetAddr -= ref->getTarget().getAddress();
7358 instructionLowHalf = (targetAddr & 0xFFFF);
7359 instruction = BigEndian::get32(*fixUp);
7360 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7361 BigEndian::set32(*fixUp, newInstruction);
7364 if ( relocateableExternal && !finalLinkedImage )
7365 targetAddr -= ref->getTarget().getAddress();
7366 if ( (targetAddr & 0x3) != 0 )
7367 throw "bad address for absolute lo14 instruction fix-up";
7368 instructionLowHalf = (targetAddr & 0xFFFF);
7369 instruction = BigEndian::get32(*fixUp);
7370 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7371 BigEndian::set32(*fixUp, newInstruction);
7374 if ( relocateableExternal ) {
7375 if ( finalLinkedImage ) {
7376 switch (ref->getTarget().getDefinitionKind()) {
7377 case ObjectFile::Atom::kExternalDefinition:
7378 case ObjectFile::Atom::kExternalWeakDefinition:
7379 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7381 case ObjectFile::Atom::kTentativeDefinition:
7382 case ObjectFile::Atom::kRegularDefinition:
7383 case ObjectFile::Atom::kWeakDefinition:
7384 // use target address
7386 case ObjectFile::Atom::kAbsoluteSymbol:
7387 targetAddr = ref->getTarget().getSectionOffset();
7392 targetAddr -= ref->getTarget().getAddress();
7395 instructionHighHalf = (targetAddr >> 16);
7396 instruction = BigEndian::get32(*fixUp);
7397 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
7398 BigEndian::set32(*fixUp, newInstruction);
7400 case A::kAbsHigh16AddLow:
7401 if ( relocateableExternal ) {
7402 if ( finalLinkedImage ) {
7403 switch (ref->getTarget().getDefinitionKind()) {
7404 case ObjectFile::Atom::kExternalDefinition:
7405 case ObjectFile::Atom::kExternalWeakDefinition:
7406 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7408 case ObjectFile::Atom::kTentativeDefinition:
7409 case ObjectFile::Atom::kRegularDefinition:
7410 case ObjectFile::Atom::kWeakDefinition:
7411 // use target address
7413 case ObjectFile::Atom::kAbsoluteSymbol:
7414 targetAddr = ref->getTarget().getSectionOffset();
7419 targetAddr -= ref->getTarget().getAddress();
7422 if ( targetAddr & 0x00008000 )
7423 targetAddr += 0x00010000;
7424 instruction = BigEndian::get32(*fixUp);
7425 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
7426 BigEndian::set32(*fixUp, newInstruction);
7428 case A::kDtraceTypeReference:
7429 case A::kDtraceProbe:
7430 // nothing to fix up
7436 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7438 uint8_t kind = ref->getKind();
7439 switch ( (ppc::ReferenceKinds)kind ) {
7441 case ppc::kFollowOn:
7442 case ppc::kGroupSubordinate:
7444 case ppc::kPointerWeakImport:
7445 case ppc::kPointerDiff16:
7446 case ppc::kPointerDiff32:
7447 case ppc::kPointerDiff64:
7448 case ppc::kDtraceProbe:
7449 case ppc::kDtraceProbeSite:
7450 case ppc::kDtraceIsEnabledSite:
7451 case ppc::kDtraceTypeReference:
7452 // these are never used to call external functions
7454 case ppc::kBranch24:
7455 case ppc::kBranch24WeakImport:
7456 case ppc::kBranch14:
7457 // these are used to call external functions
7459 case ppc::kPICBaseLow16:
7460 case ppc::kPICBaseLow14:
7461 case ppc::kPICBaseHigh16:
7462 case ppc::kAbsLow16:
7463 case ppc::kAbsLow14:
7464 case ppc::kAbsHigh16:
7465 case ppc::kAbsHigh16AddLow:
7466 // these are only used to call external functions
7467 // in -mlong-branch stubs
7468 switch ( ref->getTarget().getDefinitionKind() ) {
7469 case ObjectFile::Atom::kExternalDefinition:
7470 case ObjectFile::Atom::kExternalWeakDefinition:
7471 // if the .o file this atom came from has long-branch stubs,
7472 // then assume these instructions in a stub.
7473 // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
7474 return ( inAtom->getFile()->hasLongBranchStubs() );
7475 case ObjectFile::Atom::kTentativeDefinition:
7476 case ObjectFile::Atom::kRegularDefinition:
7477 case ObjectFile::Atom::kWeakDefinition:
7478 case ObjectFile::Atom::kAbsoluteSymbol:
7487 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7489 uint8_t kind = ref->getKind();
7490 switch ( (arm::ReferenceKinds)kind ) {
7491 case arm::kBranch24:
7492 case arm::kBranch24WeakImport:
7493 case arm::kThumbBranch22:
7494 case arm::kThumbBranch22WeakImport:
7497 case arm::kFollowOn:
7498 case arm::kGroupSubordinate:
7500 case arm::kReadOnlyPointer:
7501 case arm::kPointerWeakImport:
7502 case arm::kPointerDiff:
7503 case arm::kDtraceProbe:
7504 case arm::kDtraceProbeSite:
7505 case arm::kDtraceIsEnabledSite:
7506 case arm::kDtraceTypeReference:
7513 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7515 uint8_t kind = ref->getKind();
7516 switch ( (ppc64::ReferenceKinds)kind ) {
7518 case ppc::kFollowOn:
7519 case ppc::kGroupSubordinate:
7521 case ppc::kPointerWeakImport:
7522 case ppc::kPointerDiff16:
7523 case ppc::kPointerDiff32:
7524 case ppc::kPointerDiff64:
7525 case ppc::kPICBaseLow16:
7526 case ppc::kPICBaseLow14:
7527 case ppc::kPICBaseHigh16:
7528 case ppc::kAbsLow16:
7529 case ppc::kAbsLow14:
7530 case ppc::kAbsHigh16:
7531 case ppc::kAbsHigh16AddLow:
7532 case ppc::kDtraceProbe:
7533 case ppc::kDtraceProbeSite:
7534 case ppc::kDtraceIsEnabledSite:
7535 case ppc::kDtraceTypeReference:
7536 // these are never used to call external functions
7538 case ppc::kBranch24:
7539 case ppc::kBranch24WeakImport:
7540 case ppc::kBranch14:
7541 // these are used to call external functions
7548 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7550 uint8_t kind = ref->getKind();
7551 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
7555 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7557 uint8_t kind = ref->getKind();
7558 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
7563 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
7565 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
7569 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
7571 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
7575 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
7577 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
7581 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
7584 case x86_64::kPointerWeakImport:
7585 case x86_64::kBranchPCRel32WeakImport:
7586 case x86_64::kPCRel32GOTWeakImport:
7587 case x86_64::kPCRel32GOTLoadWeakImport:
7594 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
7596 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
7597 kind == arm::kPointerWeakImport);
7601 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
7607 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
7613 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
7619 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
7622 case x86_64::kPCRel32GOT:
7623 case x86_64::kPCRel32GOTWeakImport:
7624 case x86_64::kPCRel32GOTLoad:
7625 case x86_64::kPCRel32GOTLoadWeakImport:
7626 case x86_64::kGOTNoFixUp:
7633 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
7639 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
7645 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
7651 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
7657 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
7660 case x86_64::kPCRel32GOTLoad:
7661 case x86_64::kPCRel32GOTLoadWeakImport:
7668 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
7673 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
7674 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
7675 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
7676 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
7679 template <typename A>
7680 void Writer<A>::optimizeDylibReferences()
7682 //fprintf(stderr, "original ordinals table:\n");
7683 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7684 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7686 // find unused dylibs that can be removed
7687 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
7688 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
7689 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7690 ObjectFile::Reader* reader = it->first;
7691 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
7692 if ( aliasPos != fLibraryAliases.end() ) {
7693 // already noticed that this reader has same install name as another reader
7694 readerAliases[reader] = aliasPos->second;
7696 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || reader->deadStrippable() || fOptions.deadStripDylibs()) ) {
7697 // this reader can be optimized away
7698 it->second = 0xFFFFFFFF;
7699 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
7700 if ( pos != fLibraryToLoadCommand.end() )
7701 pos->second->optimizeAway();
7704 // mark this reader as using it ordinal
7705 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
7706 if ( pos == ordinalToReader.end() )
7707 ordinalToReader[it->second] = reader;
7709 readerAliases[reader] = pos->second;
7712 // renumber ordinals (depends on iterator walking in ordinal order)
7713 // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
7714 uint32_t newOrdinal = 0;
7715 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7716 if ( it->first <= fLibraryToOrdinal.size() ) {
7717 if ( ! it->second->isLazyLoadedDylib() )
7718 fLibraryToOrdinal[it->second] = ++newOrdinal;
7721 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7722 if ( it->first <= fLibraryToOrdinal.size() ) {
7723 if ( it->second->isLazyLoadedDylib() ) {
7724 fLibraryToOrdinal[it->second] = ++newOrdinal;
7729 // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
7730 if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
7731 throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
7733 // add aliases (e.g. -lm points to libSystem.dylib)
7734 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
7735 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
7738 //fprintf(stderr, "new ordinals table:\n");
7739 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7740 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7746 void Writer<arm>::scanForAbsoluteReferences()
7748 // arm codegen never has absolute references. FIXME: Is this correct?
7752 void Writer<x86_64>::scanForAbsoluteReferences()
7754 // x86_64 codegen never has absolute references
7758 void Writer<x86>::scanForAbsoluteReferences()
7760 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
7761 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
7762 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7763 ObjectFile::Atom* atom = *it;
7764 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7765 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7766 ObjectFile::Reference* ref = *rit;
7767 switch (ref->getKind()) {
7768 case x86::kAbsolute32:
7769 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
7778 void Writer<ppc>::scanForAbsoluteReferences()
7780 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
7781 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
7782 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7783 ObjectFile::Atom* atom = *it;
7784 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7785 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7786 ObjectFile::Reference* ref = *rit;
7787 switch (ref->getKind()) {
7788 case ppc::kAbsLow16:
7789 case ppc::kAbsLow14:
7790 case ppc::kAbsHigh16:
7791 case ppc::kAbsHigh16AddLow:
7792 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
7801 // for ppc64 look for any -mdynamic-no-pic codegen
7803 void Writer<ppc64>::scanForAbsoluteReferences()
7805 // only do this for main executable
7806 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
7807 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7808 ObjectFile::Atom* atom = *it;
7809 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7810 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7811 ObjectFile::Reference* ref = *rit;
7812 switch (ref->getKind()) {
7813 case ppc64::kAbsLow16:
7814 case ppc64::kAbsLow14:
7815 case ppc64::kAbsHigh16:
7816 case ppc64::kAbsHigh16AddLow:
7817 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
7818 // shrink page-zero and add pad segment to compensate
7819 fPadSegmentInfo = new SegmentInfo(4096);
7820 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
7821 fPageZeroAtom->setSize(0x1000);
7830 template <typename A>
7831 void Writer<A>::insertDummyStubs()
7833 // only needed for x86
7837 void Writer<x86>::insertDummyStubs()
7839 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
7840 std::vector<class StubAtom<x86>*> betterStubs;
7841 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
7842 switch (betterStubs.size() % 64 ) {
7843 case 12:// stub would occupy 0x3C->0x41
7844 case 25:// stub would occupy 0x7D->0x82
7845 case 38:// stub would occupy 0xBE->0xC3
7846 case 51:// stub would occupy 0xFF->0x04
7847 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
7850 betterStubs.push_back(*it);
7853 fAllSynthesizedStubs.clear();
7854 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
7858 template <typename A>
7859 void Writer<A>::synthesizeKextGOT()
7861 // walk every atom and reference
7862 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7863 ObjectFile::Atom* atom = *it;
7864 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7865 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7866 ObjectFile::Reference* ref = *rit;
7867 switch ( ref->getTargetBinding()) {
7868 case ObjectFile::Reference::kUnboundByName:
7869 case ObjectFile::Reference::kDontBind:
7871 case ObjectFile::Reference::kBoundByName:
7872 case ObjectFile::Reference::kBoundDirectly:
7873 ObjectFile::Atom& target = ref->getTarget();
7874 // create GOT slots (non-lazy pointers) as needed
7875 if ( this->GOTReferenceKind(ref->getKind()) ) {
7876 bool useGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
7877 // if this GOT usage cannot be optimized away then make a GOT enry
7878 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
7881 ObjectFile::Atom* nlp = NULL;
7882 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
7883 if ( pos == fGOTMap.end() ) {
7884 nlp = new NonLazyPointerAtom<A>(*this, target);
7885 fGOTMap[&target] = nlp;
7890 // alter reference to use non lazy pointer instead
7891 ref->setTarget(*nlp, ref->getTargetOffset());
7894 // build map of which symbols need weak importing
7895 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
7896 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
7897 if ( this->weakImportReferenceKind(ref->getKind()) ) {
7898 fWeakImportMap[&target] = true;
7906 // add non-lazy pointers to fAllAtoms
7907 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
7908 ObjectFile::Section* curSection = NULL;
7909 ObjectFile::Atom* prevAtom = NULL;
7910 bool inserted = false;
7911 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7912 ObjectFile::Atom* atom = *it;
7913 ObjectFile::Section* nextSection = atom->getSection();
7914 if ( nextSection != curSection ) {
7915 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__data") == 0) ) {
7916 // found end of __data section, insert lazy pointers here
7917 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
7921 curSection = nextSection;
7926 throw "can't insert non-lazy pointers, __data section not found";
7933 template <typename A>
7934 void Writer<A>::synthesizeStubs()
7936 switch ( fOptions.outputKind() ) {
7937 case Options::kObjectFile:
7938 case Options::kPreload:
7939 // these output kinds never have stubs
7941 case Options::kKextBundle:
7942 // new kext need a synthesized GOT only
7943 synthesizeKextGOT();
7945 case Options::kStaticExecutable:
7946 case Options::kDyld:
7947 case Options::kDynamicLibrary:
7948 case Options::kDynamicBundle:
7949 case Options::kDynamicExecutable:
7950 // try to synthesize stubs for these
7954 // walk every atom and reference
7955 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7956 ObjectFile::Atom* atom = *it;
7957 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7958 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7959 ObjectFile::Reference* ref = *rit;
7960 switch ( ref->getTargetBinding()) {
7961 case ObjectFile::Reference::kUnboundByName:
7962 case ObjectFile::Reference::kDontBind:
7964 case ObjectFile::Reference::kBoundByName:
7965 case ObjectFile::Reference::kBoundDirectly:
7966 ObjectFile::Atom& target = ref->getTarget();
7967 // build map of which symbols need weak importing
7968 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
7969 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
7970 bool weakImport = this->weakImportReferenceKind(ref->getKind());
7971 // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
7972 // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
7973 // in dylibs that are weakly linked.
7974 if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
7975 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
7976 pos = fLibraryToLoadCommand.find(target.getFile());
7977 if ( pos != fLibraryToLoadCommand.end() ) {
7978 if ( pos->second->linkedWeak() )
7982 // <rdar://problem/6186838> -weak_library no longer forces uses to be weak_import
7983 if ( fForcedWeakImportReaders.count(target.getFile()) != 0 ) {
7984 fWeakImportMap[&target] = true;
7988 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
7989 if ( pos == fWeakImportMap.end() ) {
7990 // target not in fWeakImportMap, so add
7991 fWeakImportMap[&target] = weakImport;
7994 // target in fWeakImportMap, check for weakness mismatch
7995 if ( pos->second != weakImport ) {
7997 switch ( fOptions.weakReferenceMismatchTreatment() ) {
7998 case Options::kWeakReferenceMismatchError:
7999 throwf("mismatching weak references for symbol: %s", target.getName());
8000 case Options::kWeakReferenceMismatchWeak:
8003 case Options::kWeakReferenceMismatchNonWeak:
8004 pos->second = false;
8009 // update if we use a weak_import or a strong import from this dylib
8010 if ( fWeakImportMap[&target] )
8011 fDylibReadersWithWeakImports.insert(target.getFile());
8013 fDylibReadersWithNonWeakImports.insert(target.getFile());
8015 // create stubs as needed
8016 if ( this->stubableReference(atom, ref)
8017 && (ref->getTargetOffset() == 0)
8018 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
8019 ObjectFile::Atom* stub = NULL;
8020 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
8021 if ( pos == fStubsMap.end() ) {
8022 bool forLazyDylib = false;
8023 switch ( target.getDefinitionKind() ) {
8024 case ObjectFile::Atom::kRegularDefinition:
8025 case ObjectFile::Atom::kWeakDefinition:
8026 case ObjectFile::Atom::kAbsoluteSymbol:
8027 case ObjectFile::Atom::kTentativeDefinition:
8029 case ObjectFile::Atom::kExternalDefinition:
8030 case ObjectFile::Atom::kExternalWeakDefinition:
8031 if ( target.getFile()->isLazyLoadedDylib() )
8032 forLazyDylib = true;
8035 // just-in-time, create GOT slot to dyld_stub_binder
8036 if ( fOptions.makeCompressedDyldInfo() && (fFastStubGOTAtom == NULL) ) {
8037 if ( fDyldCompressedHelperAtom == NULL )
8038 throw "missing symbol dyld_stub_binder";
8039 fFastStubGOTAtom = new NonLazyPointerAtom<A>(*this, *fDyldCompressedHelperAtom);
8041 stub = new StubAtom<A>(*this, target, forLazyDylib);
8042 fStubsMap[&target] = stub;
8047 // alter reference to use stub instead
8048 ref->setTarget(*stub, 0);
8050 else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
8051 throwf("illegal reference to %s in lazy loaded dylib from %s in %s",
8052 target.getDisplayName(), atom->getDisplayName(),
8053 atom->getFile()->getPath());
8055 // create GOT slots (non-lazy pointers) as needed
8056 else if ( this->GOTReferenceKind(ref->getKind()) ) {
8058 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
8060 if ( fBiggerThanTwoGigs ) {
8061 // in big images use GOT for all zero fill atoms
8062 // this is just a heuristic and may need to be re-examined
8063 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
8066 // < 2GB image so remove all GOT entries that we can
8067 useGOT = mustUseGOT;
8069 // if this GOT usage cannot be optimized away then make a GOT enry
8070 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
8073 ObjectFile::Atom* nlp = NULL;
8074 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
8075 if ( pos == fGOTMap.end() ) {
8076 nlp = new NonLazyPointerAtom<A>(*this, target);
8077 fGOTMap[&target] = nlp;
8082 // alter reference to use non lazy pointer instead
8083 ref->setTarget(*nlp, ref->getTargetOffset());
8091 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
8092 std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter());
8094 // add dummy self-modifying stubs (x86 only)
8095 if ( ! fOptions.makeCompressedDyldInfo() )
8096 this->insertDummyStubs();
8098 // sort lazy pointers
8099 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
8100 std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
8103 // add stubs to fAllAtoms
8104 if ( fAllSynthesizedStubs.size() != 0 ) {
8105 std::vector<ObjectFile::Atom*> textStubs;
8106 std::vector<ObjectFile::Atom*> importStubs;
8107 for (typename std::vector<class StubAtom<A>*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) {
8108 ObjectFile::Atom* stubAtom = *sit;
8109 if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 )
8110 textStubs.push_back(stubAtom);
8112 importStubs.push_back(stubAtom);
8114 // any helper stubs go right after regular stubs
8115 if ( fAllSynthesizedStubHelpers.size() != 0 )
8116 textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
8117 // insert text stubs right after __text section
8118 ObjectFile::Section* curSection = NULL;
8119 ObjectFile::Atom* prevAtom = NULL;
8120 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8121 ObjectFile::Atom* atom = *it;
8122 ObjectFile::Section* nextSection = atom->getSection();
8123 if ( nextSection != curSection ) {
8124 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
8125 // found end of __text section, insert stubs here
8126 fAllAtoms->insert(it, textStubs.begin(), textStubs.end());
8129 curSection = nextSection;
8133 if ( importStubs.size() != 0 ) {
8134 // insert __IMPORTS stubs right before __LINKEDIT
8135 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8136 ObjectFile::Atom* atom = *it;
8137 ObjectFile::Section* nextSection = atom->getSection();
8138 if ( nextSection != curSection ) {
8139 // for i386 where stubs are not in __TEXT segment
8140 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
8141 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
8142 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
8143 fAllAtoms->insert(it, importStubs.begin(), importStubs.end());
8146 curSection = nextSection;
8154 // add non-lazy pointers to fAllAtoms
8155 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
8156 ObjectFile::Section* curSection = NULL;
8157 ObjectFile::Atom* prevAtom = NULL;
8158 bool inserted = false;
8159 // first try to insert at end of __nl_symbol_ptr
8160 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8161 ObjectFile::Atom* atom = *it;
8162 ObjectFile::Section* nextSection = atom->getSection();
8163 if ( nextSection != curSection ) {
8164 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) {
8165 // found end of __nl_symbol_ptr section, insert non-lazy pointers at end of it
8166 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8170 curSection = nextSection;
8175 // next try to insert after __dyld section
8176 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8177 ObjectFile::Atom* atom = *it;
8178 ObjectFile::Section* nextSection = atom->getSection();
8179 if ( nextSection != curSection ) {
8180 if ( strcmp(atom->getSegment().getName(), "__DATA") == 0 ) {
8181 const char* prevSectionName = (prevAtom != NULL) ? prevAtom->getSectionName() : "";
8182 if ( (strcmp(prevSectionName, "__dyld") != 0)
8183 && (strcmp(prevSectionName, "__program_vars") != 0)
8184 && (strcmp(prevSectionName, "__mod_init_func") != 0) ) {
8185 // found end of __dyld section, insert non-lazy pointers here
8186 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8195 // might not be any __DATA sections, insert after end of __TEXT
8196 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8197 ObjectFile::Atom* atom = *it;
8198 ObjectFile::Section* nextSection = atom->getSection();
8199 if ( nextSection != curSection ) {
8200 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__TEXT") == 0) && (strcmp(atom->getSegment().getName(), "__TEXT") != 0)) {
8201 // found end of __TEXT segment, insert non-lazy pointers at end of it
8202 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8206 curSection = nextSection;
8212 throw "can't insert non-lazy pointers, __dyld section not found";
8216 // add lazy dylib pointers to fAllAtoms
8217 if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) {
8218 ObjectFile::Section* curSection = NULL;
8219 ObjectFile::Atom* prevAtom = NULL;
8220 bool inserted = false;
8221 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8222 ObjectFile::Atom* atom = *it;
8223 ObjectFile::Section* nextSection = atom->getSection();
8224 if ( nextSection != curSection ) {
8225 if ( (prevAtom != NULL) &&
8226 ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0)
8227 || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0)
8228 || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) {
8229 // found end of __dyld section, insert lazy pointers here
8230 fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
8234 curSection = nextSection;
8239 throw "can't insert lazy pointers, __dyld section not found";
8243 // add lazy pointers to fAllAtoms
8244 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
8245 ObjectFile::Section* curSection = NULL;
8246 ObjectFile::Atom* prevAtom = NULL;
8247 bool inserted = false;
8248 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8249 ObjectFile::Atom* atom = *it;
8250 ObjectFile::Section* nextSection = atom->getSection();
8251 if ( nextSection != curSection ) {
8252 if ( (prevAtom != NULL) &&
8253 ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0)
8254 || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0)
8255 || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) {
8256 // found end of __dyld section, insert lazy pointers here
8257 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
8261 curSection = nextSection;
8266 throw "can't insert lazy pointers, __dyld section not found";
8273 template <typename A>
8274 void Writer<A>::createSplitSegContent()
8276 // build LC_SEGMENT_SPLIT_INFO once all atoms exist
8277 if ( fSplitCodeToDataContentAtom != NULL ) {
8278 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8279 ObjectFile::Atom* atom = *it;
8280 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8281 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8282 ObjectFile::Reference* ref = *rit;
8283 switch ( ref->getTargetBinding()) {
8284 case ObjectFile::Reference::kUnboundByName:
8285 case ObjectFile::Reference::kDontBind:
8287 case ObjectFile::Reference::kBoundByName:
8288 case ObjectFile::Reference::kBoundDirectly:
8289 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
8290 this->addCrossSegmentRef(atom, ref);
8296 // bad codegen may cause LC_SEGMENT_SPLIT_INFO to be removed
8297 adjustLoadCommandsAndPadding();
8303 template <typename A>
8304 void Writer<A>::synthesizeUnwindInfoTable()
8306 if ( fUnwindInfoAtom != NULL ) {
8307 // walk every atom and gets its unwind info
8308 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8309 ObjectFile::Atom* atom = *it;
8310 if ( atom->beginUnwind() == atom->endUnwind() ) {
8311 // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
8312 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
8313 fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL, NULL);
8317 for ( ObjectFile::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
8318 fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getFDE(), atom->getLSDA(), atom->getPersonalityPointer());
8327 template <typename A>
8328 void Writer<A>::partitionIntoSections()
8330 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
8332 // for every atom, set its sectionInfo object and section offset
8333 // build up fSegmentInfos along the way
8334 ObjectFile::Section* curSection = (ObjectFile::Section*)(-1);
8335 SectionInfo* currentSectionInfo = NULL;
8336 SegmentInfo* currentSegmentInfo = NULL;
8337 SectionInfo* cstringSectionInfo = NULL;
8338 unsigned int sectionIndex = 1;
8339 fSegmentInfos.reserve(8);
8340 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
8341 ObjectFile::Atom* atom = (*fAllAtoms)[i];
8342 if ( ((atom->getSection() != curSection) || (curSection==NULL))
8343 && ((currentSectionInfo == NULL)
8344 || (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)
8345 || (strcmp(atom->getSegment().getName(),currentSectionInfo->fSegmentName) != 0)) ) {
8346 if ( oneSegmentCommand ) {
8347 if ( currentSegmentInfo == NULL ) {
8348 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8349 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8350 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8351 this->fSegmentInfos.push_back(currentSegmentInfo);
8353 currentSectionInfo = new SectionInfo();
8354 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8355 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8356 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8357 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8358 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
8359 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8360 currentSectionInfo->setIndex(sectionIndex++);
8361 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8362 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
8363 cstringSectionInfo = currentSectionInfo;
8366 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
8367 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8368 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
8369 uint32_t initprot = 0;
8370 if ( atom->getSegment().isContentReadable() )
8371 initprot |= VM_PROT_READ;
8372 if ( atom->getSegment().isContentWritable() )
8373 initprot |= VM_PROT_WRITE;
8374 if ( atom->getSegment().isContentExecutable() )
8375 initprot |= VM_PROT_EXECUTE;
8376 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
8377 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
8378 currentSegmentInfo->fInitProtection = initprot;
8379 if ( initprot == 0 )
8380 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
8381 else if ( fOptions.architecture() == CPU_TYPE_ARM )
8382 currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init
8384 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8385 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
8386 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
8387 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
8388 currentSegmentInfo->fInitProtection = it->init;
8389 currentSegmentInfo->fMaxProtection = it->max;
8392 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
8393 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
8394 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
8395 currentSegmentInfo->fIndependentAddress = true;
8396 if ( (fOptions.outputKind() == Options::kPreload) && (strcmp(currentSegmentInfo->fName, "__LINKEDIT")==0) )
8397 currentSegmentInfo->fHasLoadCommand = false;
8398 if ( strcmp(currentSegmentInfo->fName, "__HEADER")==0 )
8399 currentSegmentInfo->fHasLoadCommand = false;
8400 this->fSegmentInfos.push_back(currentSegmentInfo);
8402 currentSectionInfo = new SectionInfo();
8403 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
8404 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8405 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8406 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8407 // check for -sectalign override
8408 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
8409 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
8410 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
8411 currentSectionInfo->fAlignment = it->alignment;
8413 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8414 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
8415 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8416 currentSectionInfo->setIndex(sectionIndex++);
8417 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8419 //fprintf(stderr, "new section %s for atom %s\n", atom->getSectionName(), atom->getDisplayName());
8420 if ( strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0 ) {
8421 fLoadCommandsSection = currentSectionInfo;
8422 fLoadCommandsSegment = currentSegmentInfo;
8424 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
8425 currentSectionInfo->fAllLazyPointers = true;
8426 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
8427 currentSectionInfo->fAllLazyPointers = true;
8428 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) )
8429 currentSectionInfo->fAllLazyDylibPointers = true;
8430 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
8431 currentSectionInfo->fAllNonLazyPointers = true;
8432 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
8433 currentSectionInfo->fAllNonLazyPointers = true;
8434 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
8435 currentSectionInfo->fAllNonLazyPointers = true;
8436 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
8437 currentSectionInfo->fAllStubs = true;
8438 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
8439 currentSectionInfo->fAllStubs = true;
8440 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
8441 currentSectionInfo->fAllStubs = true;
8442 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
8443 currentSectionInfo->fAllStubs = true;
8444 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) )
8445 currentSectionInfo->fAllStubs = true;
8446 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) )
8447 currentSectionInfo->fAllStubs = true;
8448 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
8449 currentSectionInfo->fAllSelfModifyingStubs = true;
8450 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
8452 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__stub_helper") == 0) )
8453 currentSectionInfo->fAllStubHelpers = true;
8454 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) )
8455 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
8456 curSection = atom->getSection();
8457 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers
8458 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) {
8459 fSymbolTableCommands->needDynamicTable();
8462 // any non-zero fill atoms make whole section marked not-zero-fill
8463 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
8464 currentSectionInfo->fAllZeroFill = false;
8465 // change section object to be Writer's SectionInfo object
8466 atom->setSection(currentSectionInfo);
8467 // section alignment is that of a contained atom with the greatest alignment
8468 uint8_t atomAlign = atom->getAlignment().powerOf2;
8469 if ( currentSectionInfo->fAlignment < atomAlign )
8470 currentSectionInfo->fAlignment = atomAlign;
8471 // calculate section offset for this atom
8472 uint64_t offset = currentSectionInfo->fSize;
8473 uint64_t alignment = 1 << atomAlign;
8474 uint64_t currentModulus = (offset % alignment);
8475 uint64_t requiredModulus = atom->getAlignment().modulus;
8476 if ( currentModulus != requiredModulus ) {
8477 if ( requiredModulus > currentModulus )
8478 offset += requiredModulus-currentModulus;
8480 offset += requiredModulus+alignment-currentModulus;
8482 atom->setSectionOffset(offset);
8483 uint64_t curAtomSize = atom->getSize();
8484 currentSectionInfo->fSize = offset + curAtomSize;
8485 // add atom to section vector
8486 currentSectionInfo->fAtoms.push_back(atom);
8487 //fprintf(stderr, " adding atom %p %s size=0x%0llX to section %p %s from %s\n", atom, atom->getDisplayName(), atom->getSize(),
8488 // currentSectionInfo, currentSectionInfo->fSectionName, atom->getFile()->getPath());
8489 // update largest size
8490 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
8491 fLargestAtomSize = curAtomSize;
8493 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
8494 // when merging cstring sections in .o files, all strings need to use the max alignment
8495 uint64_t offset = 0;
8496 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
8497 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
8498 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
8499 ObjectFile::Atom* atom = *it;
8500 atom->setSectionOffset(offset);
8501 offset += atom->getSize();
8503 cstringSectionInfo->fSize = offset;
8508 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
8509 class TargetAndOffsetComparor
8512 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
8514 if ( left.atom != right.atom )
8515 return ( left.atom < right.atom );
8516 return ( left.offset < right.offset );
8521 bool Writer<ppc>::addBranchIslands()
8523 return this->addPPCBranchIslands();
8527 bool Writer<ppc64>::addBranchIslands()
8529 return this->addPPCBranchIslands();
8533 bool Writer<x86>::addBranchIslands()
8535 // x86 branches can reach entire 4G address space, so no need for branch islands
8540 bool Writer<x86_64>::addBranchIslands()
8542 // x86 branches can reach entire 4G size of largest image
8547 bool Writer<arm>::addBranchIslands()
8549 // arm branch islands not (yet) supported
8550 // you can instead compile with -mlong-call
8555 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
8558 case ppc::kBranch24:
8559 case ppc::kBranch24WeakImport:
8566 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
8569 case ppc64::kBranch24:
8570 case ppc64::kBranch24WeakImport:
8577 // PowerPC can do PC relative branches as far as +/-16MB.
8578 // If a branch target is >16MB then we insert one or more
8579 // "branch islands" between the branch and its target that
8580 // allows island hoping to the target.
8582 // Branch Island Algorithm
8584 // If the __TEXT segment < 16MB, then no branch islands needed
8585 // Otherwise, every 14MB into the __TEXT segment a region is
8586 // added which can contain branch islands. Every out of range
8587 // bl instruction is checked. If it crosses a region, an island
8588 // is added to that region with the same target and the bl is
8589 // adjusted to target the island instead.
8591 // In theory, if too many islands are added to one region, it
8592 // could grow the __TEXT enough that other previously in-range
8593 // bl branches could be pushed out of range. We reduce the
8594 // probability this could happen by placing the ranges every
8595 // 15MB which means the region would have to be 1MB (256K islands)
8596 // before any branches could be pushed out of range.
8598 template <typename A>
8599 bool Writer<A>::addPPCBranchIslands()
8602 bool result = false;
8603 // Can only possibly need branch islands if __TEXT segment > 16M
8604 if ( fLoadCommandsSegment->fSize > 16000000 ) {
8605 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
8606 const uint32_t kBetweenRegions = 14*1024*1024; // place regions of islands every 14MB in __text section
8607 SectionInfo* textSection = NULL;
8608 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
8609 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
8611 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
8615 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
8616 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
8617 AtomToIsland regionsMap[kIslandRegionsCount];
8618 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
8619 unsigned int islandCount = 0;
8620 if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
8622 // create islands for branch references that are out of range
8623 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8624 ObjectFile::Atom* atom = *it;
8625 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8626 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8627 ObjectFile::Reference* ref = *rit;
8628 if ( this->isBranch24Reference(ref->getKind()) ) {
8629 ObjectFile::Atom& target = ref->getTarget();
8630 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
8631 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
8632 int64_t displacement = dstAddr - srcAddr;
8633 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
8634 const int64_t kFifteenMegLimit = kBetweenRegions;
8635 if ( displacement > kFifteenMegLimit ) {
8636 // create forward branch chain
8637 ObjectFile::Atom* nextTarget = ⌖
8638 uint64_t nextTargetOffset = ref->getTargetOffset();
8639 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
8640 AtomToIsland* region = ®ionsMap[i];
8641 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
8642 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
8643 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8644 if ( pos == region->end() ) {
8645 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
8646 island->setSection(textSection);
8647 (*region)[finalTargetAndOffset] = island;
8648 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8649 regionsIslands[i].push_back(island);
8651 nextTarget = island;
8652 nextTargetOffset = 0;
8655 nextTarget = pos->second;
8656 nextTargetOffset = 0;
8660 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
8661 ref->setTarget(*nextTarget, nextTargetOffset);
8663 else if ( displacement < (-kFifteenMegLimit) ) {
8664 // create back branching chain
8665 ObjectFile::Atom* prevTarget = ⌖
8666 uint64_t prevTargetOffset = ref->getTargetOffset();
8667 for (int i=0; i < kIslandRegionsCount ; ++i) {
8668 AtomToIsland* region = ®ionsMap[i];
8669 int64_t islandRegionAddr = kBetweenRegions * (i+1);
8670 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
8671 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8672 if ( pos == region->end() ) {
8673 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
8674 island->setSection(textSection);
8675 (*region)[finalTargetAndOffset] = island;
8676 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8677 regionsIslands[i].push_back(island);
8679 prevTarget = island;
8680 prevTargetOffset = 0;
8683 prevTarget = pos->second;
8684 prevTargetOffset = 0;
8688 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
8689 ref->setTarget(*prevTarget, prevTargetOffset);
8695 // insert islands into __text section and adjust section offsets
8696 if ( islandCount > 0 ) {
8697 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
8698 std::vector<ObjectFile::Atom*> newAtomList;
8699 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
8700 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
8701 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
8702 int regionIndex = 0;
8703 uint64_t atomSlide = 0;
8704 uint64_t sectionOffset = 0;
8705 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
8706 ObjectFile::Atom* atom = *it;
8707 if ( (atom->getAddress()+atom->getSize()) > islandRegionAddr ) {
8708 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
8709 sectionOffset = islandStartOffset;
8710 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
8711 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8712 ObjectFile::Atom* islandAtom = *rit;
8713 newAtomList.push_back(islandAtom);
8714 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8715 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8716 islandAtom->setSectionOffset(sectionOffset);
8717 sectionOffset += islandAtom->getSize();
8720 islandRegionAddr += kBetweenRegions;
8721 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
8722 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
8724 newAtomList.push_back(atom);
8725 if ( atomSlide != 0 )
8726 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
8728 sectionOffset = textSection->fSize+atomSlide;
8729 // put any remaining islands at end of __text section
8730 if ( regionIndex < kIslandRegionsCount ) {
8731 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
8732 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8733 ObjectFile::Atom* islandAtom = *rit;
8734 newAtomList.push_back(islandAtom);
8735 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8736 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8737 islandAtom->setSectionOffset(sectionOffset);
8738 sectionOffset += islandAtom->getSize();
8742 textSection->fAtoms = newAtomList;
8743 textSection->fSize = sectionOffset;
8752 template <typename A>
8753 void Writer<A>::adjustLoadCommandsAndPadding()
8755 fSegmentCommands->computeSize();
8757 // recompute load command section offsets
8758 uint64_t offset = 0;
8759 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
8760 const unsigned int atomCount = loadCommandAtoms.size();
8761 for (unsigned int i=0; i < atomCount; ++i) {
8762 ObjectFile::Atom* atom = loadCommandAtoms[i];
8763 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
8764 offset = ( (offset+alignment-1) & (-alignment) );
8765 atom->setSectionOffset(offset);
8766 uint32_t atomSize = atom->getSize();
8767 if ( atomSize > fLargestAtomSize )
8768 fLargestAtomSize = atomSize;
8770 fLoadCommandsSection->fSize = offset;
8773 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
8774 const int sectionCount = sectionInfos.size();
8775 uint32_t totalSizeOfTEXTLessHeaderAndLoadCommands = 0;
8776 for(int j=0; j < sectionCount; ++j) {
8777 SectionInfo* curSection = sectionInfos[j];
8778 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8780 totalSizeOfTEXTLessHeaderAndLoadCommands += curSection->fSize;
8782 uint64_t paddingSize = 0;
8783 if ( fOptions.outputKind() == Options::kDyld ) {
8784 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
8785 paddingSize = 4096 - (totalSizeOfTEXTLessHeaderAndLoadCommands % 4096);
8787 else if ( fOptions.outputKind() == Options::kObjectFile ) {
8788 // mach-o .o files need no padding between load commands and first section
8789 // but leave enough room that the object file could be signed
8792 else if ( fOptions.outputKind() == Options::kPreload ) {
8793 // mach-o MH_PRELOAD files need no padding between load commands and first section
8796 else if ( fOptions.makeEncryptable() ) {
8797 // want load commands to end on a page boundary, so __text starts on page boundary
8798 paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
8799 fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfTEXTLessHeaderAndLoadCommands+paddingSize);
8802 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
8804 for(int j=sectionCount-1; j >=0; --j) {
8805 SectionInfo* curSection = sectionInfos[j];
8806 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
8807 addr -= (fLoadCommandsSection->fSize+fMachHeaderAtom->getSize());
8808 paddingSize = addr % fOptions.segmentAlignment();
8811 addr -= curSection->fSize;
8812 addr = addr & (0 - (1 << curSection->fAlignment));
8815 // if command line requires more padding than this
8816 uint32_t minPad = fOptions.minimumHeaderPad();
8817 if ( fOptions.maxMminimumHeaderPad() ) {
8818 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
8819 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
8820 if ( fOptions.outputKind() == Options::kDynamicLibrary )
8821 altMin += MAXPATHLEN;
8822 if ( altMin > minPad )
8825 if ( paddingSize < minPad ) {
8826 int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment();
8827 paddingSize += extraPages * fOptions.segmentAlignment();
8831 // adjust atom size and update section size
8832 fHeaderPadding->setSize(paddingSize);
8833 for(int j=0; j < sectionCount; ++j) {
8834 SectionInfo* curSection = sectionInfos[j];
8835 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8836 curSection->fSize = paddingSize;
8840 static uint64_t segmentAlign(uint64_t addr, uint64_t alignment)
8842 return ((addr+alignment-1) & (-alignment));
8845 // assign file offsets and logical address to all segments
8846 template <typename A>
8847 void Writer<A>::assignFileOffsets()
8849 const bool virtualSectionOccupyAddressSpace = ((fOptions.outputKind() != Options::kObjectFile)
8850 && (fOptions.outputKind() != Options::kPreload));
8851 bool haveFixedSegments = false;
8852 uint64_t fileOffset = 0;
8853 uint64_t nextContiguousAddress = fOptions.baseAddress();
8854 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
8855 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
8857 // process segments with fixed addresses (-segaddr)
8858 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
8859 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8860 SegmentInfo* curSegment = *segit;
8861 if ( strcmp(curSegment->fName, it->name) == 0 ) {
8862 curSegment->fBaseAddress = it->address;
8863 curSegment->fFixedAddress = true;
8869 // process segments with fixed addresses (-seg_page_size)
8870 for (std::vector<Options::SegmentSize>::iterator it = fOptions.customSegmentSizes().begin(); it != fOptions.customSegmentSizes().end(); ++it) {
8871 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8872 SegmentInfo* curSegment = *segit;
8873 if ( strcmp(curSegment->fName, it->name) == 0 ) {
8874 curSegment->fPageSize = it->size;
8880 // Run through the segments and each segment's sections to assign addresses
8881 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8882 SegmentInfo* curSegment = *segit;
8884 if ( fOptions.splitSeg() ) {
8885 if ( curSegment->fInitProtection & VM_PROT_WRITE )
8886 nextContiguousAddress = nextWritableAddress;
8888 nextContiguousAddress = nextReadOnlyAddress;
8891 if ( fOptions.outputKind() == Options::kPreload ) {
8892 if ( strcmp(curSegment->fName, "__HEADER") == 0 )
8893 nextContiguousAddress = 0;
8894 else if ( strcmp(curSegment->fName, "__TEXT") == 0 )
8895 nextContiguousAddress = fOptions.baseAddress();
8898 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
8899 curSegment->fFileOffset = fileOffset;
8901 // Set the segment base address
8902 if ( curSegment->fFixedAddress )
8903 haveFixedSegments = true;
8905 curSegment->fBaseAddress = segmentAlign(nextContiguousAddress, curSegment->fPageSize);
8907 // We've set the segment address, now run through each section.
8908 uint64_t address = curSegment->fBaseAddress;
8909 SectionInfo* firstZeroFillSection = NULL;
8910 SectionInfo* prevSection = NULL;
8912 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
8914 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
8915 SectionInfo* curSection = *it;
8917 // adjust section address based on alignment
8918 uint64_t alignment = 1 << curSection->fAlignment;
8919 if ( curSection->fAtoms.size() == 1 ) {
8920 // if there is only one atom in section, use modulus for even better layout
8921 ObjectFile::Alignment atomAlign = curSection->fAtoms[0]->getAlignment();
8922 uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
8923 uint64_t currentModulus = (address % atomAlignP2);
8924 if ( currentModulus != atomAlign.modulus ) {
8925 if ( atomAlign.modulus > currentModulus )
8926 address += atomAlign.modulus-currentModulus;
8928 address += atomAlign.modulus+atomAlignP2-currentModulus;
8932 address = ( (address+alignment-1) & (-alignment) );
8935 // adjust file offset to match address
8936 if ( prevSection != NULL ) {
8937 if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection )
8938 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
8940 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
8943 // update section info
8944 curSection->fFileOffset = fileOffset;
8945 curSection->setBaseAddress(address);
8946 //fprintf(stderr, "%s %s addr=0x%llX, fileoffset=0x%llX, size=0x%llX\n", curSegment->fName, curSection->fSectionName, address, fileOffset, curSection->fSize);
8948 // keep track of trailing zero fill sections
8949 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
8950 firstZeroFillSection = curSection;
8951 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && (fOptions.outputKind() != Options::kObjectFile) )
8952 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
8954 // update running pointers
8955 if ( virtualSectionOccupyAddressSpace || !curSection->fVirtualSection )
8956 address += curSection->fSize;
8957 fileOffset += curSection->fSize;
8959 // sanity check size of 32-bit binaries
8960 if ( address > maxAddress() )
8961 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
8963 // update segment info
8964 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
8965 curSegment->fSize = curSegment->fFileSize;
8966 prevSection = curSection;
8969 if ( fOptions.outputKind() == Options::kObjectFile ) {
8970 // don't page align .o files
8973 // optimize trailing zero-fill sections to not occupy disk space
8974 if ( firstZeroFillSection != NULL ) {
8975 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
8976 fileOffset = firstZeroFillSection->fFileOffset;
8978 // page align segment size
8979 curSegment->fFileSize = segmentAlign(curSegment->fFileSize, curSegment->fPageSize);
8980 curSegment->fSize = segmentAlign(curSegment->fSize, curSegment->fPageSize);
8981 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
8982 nextContiguousAddress = segmentAlign(curSegment->fBaseAddress+curSegment->fSize, curSegment->fPageSize);
8983 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
8984 if ( curSegment->fInitProtection & VM_PROT_WRITE )
8985 nextWritableAddress = nextContiguousAddress;
8987 nextReadOnlyAddress = nextContiguousAddress;
8990 //fprintf(stderr, "end of seg %s, fileoffset=0x%llX, nextContiguousAddress=0x%llX\n", curSegment->fName, fileOffset, nextContiguousAddress);
8993 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
8994 if ( haveFixedSegments ) {
8995 int segCount = fSegmentInfos.size();
8996 for(int i=0; i < segCount; ++i) {
8997 SegmentInfo* segment1 = fSegmentInfos[i];
8999 for(int j=0; j < segCount; ++j) {
9001 SegmentInfo* segment2 = fSegmentInfos[j];
9003 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
9004 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
9005 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9006 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9008 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
9009 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
9010 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9011 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9013 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
9014 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9015 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9022 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
9023 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9024 SegmentInfo* curSegment = *segit;
9025 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
9026 if ( fFirstWritableSegment == NULL )
9027 fFirstWritableSegment = curSegment;
9028 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
9029 fWritableSegmentPastFirst4GB = true;
9033 // record size of encrypted part of __TEXT segment
9034 if ( fOptions.makeEncryptable() ) {
9035 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9036 SegmentInfo* curSegment = *segit;
9037 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
9038 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
9046 template <typename A>
9047 void Writer<A>::adjustLinkEditSections()
9049 // link edit content is always in last segment
9050 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
9051 unsigned int firstLinkEditSectionIndex = 0;
9052 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
9053 ++firstLinkEditSectionIndex;
9055 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
9056 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
9057 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
9058 if ( fPadSegmentInfo != NULL ) {
9059 // insert __4GBFILL segment into segments vector before LINKEDIT
9060 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
9061 if ( *it == lastSeg ) {
9062 fSegmentInfos.insert(it, fPadSegmentInfo);
9066 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
9067 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
9068 fPadSegmentInfo->fBaseAddress = address;
9069 // adjust LINKEDIT to start at zeroPageSize
9070 address = fOptions.zeroPageSize();
9071 lastSeg->fBaseAddress = fOptions.zeroPageSize();
9073 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
9074 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
9075 // adjust section address based on alignment
9076 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
9077 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
9079 fileOffset += pad; // adjust file offset to match address
9080 lastSeg->fSections[i]->setBaseAddress(address);
9081 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
9082 lastSeg->fSections[i]->setBaseAddress(0);
9083 lastSeg->fSections[i]->fFileOffset = fileOffset;
9084 uint64_t sectionOffset = 0;
9085 for (unsigned int j=0; j < atoms.size(); ++j) {
9086 ObjectFile::Atom* atom = atoms[j];
9087 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
9088 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
9089 atom->setSectionOffset(sectionOffset);
9090 uint64_t size = atom->getSize();
9091 sectionOffset += size;
9092 if ( size > fLargestAtomSize )
9093 fLargestAtomSize = size;
9095 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
9096 lastSeg->fSections[i]->fSize = sectionOffset;
9097 fileOffset += sectionOffset;
9098 address += sectionOffset;
9100 if ( fOptions.outputKind() == Options::kObjectFile ) {
9101 //lastSeg->fBaseAddress = 0;
9102 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
9103 //lastSeg->fFileOffset = 0;
9104 //lastSeg->fFileSize =
9107 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
9108 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
9113 template <typename A>
9114 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
9116 switch ( fWriter.fOptions.outputKind() ) {
9117 case Options::kDynamicExecutable:
9118 case Options::kStaticExecutable:
9119 return ObjectFile::Atom::scopeGlobal;
9120 case Options::kDynamicLibrary:
9121 case Options::kDynamicBundle:
9122 case Options::kDyld:
9123 case Options::kObjectFile:
9124 case Options::kPreload:
9125 case Options::kKextBundle:
9126 return ObjectFile::Atom::scopeLinkageUnit;
9128 throw "unknown header type";
9131 template <typename A>
9132 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
9134 switch ( fWriter.fOptions.outputKind() ) {
9135 case Options::kDynamicExecutable:
9136 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
9137 case Options::kStaticExecutable:
9138 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
9139 case Options::kDynamicLibrary:
9140 case Options::kDynamicBundle:
9141 case Options::kDyld:
9142 return ObjectFile::Atom::kSymbolTableIn;
9143 case Options::kObjectFile:
9144 case Options::kPreload:
9145 case Options::kKextBundle:
9146 return ObjectFile::Atom::kSymbolTableNotIn;
9148 throw "unknown header type";
9151 template <typename A>
9152 const char* MachHeaderAtom<A>::getName() const
9154 switch ( fWriter.fOptions.outputKind() ) {
9155 case Options::kDynamicExecutable:
9156 case Options::kStaticExecutable:
9157 return "__mh_execute_header";
9158 case Options::kDynamicLibrary:
9159 return "__mh_dylib_header";
9160 case Options::kDynamicBundle:
9161 return "__mh_bundle_header";
9162 case Options::kObjectFile:
9163 case Options::kPreload:
9164 case Options::kKextBundle:
9166 case Options::kDyld:
9167 return "__mh_dylinker_header";
9169 throw "unknown header type";
9172 template <typename A>
9173 const char* MachHeaderAtom<A>::getDisplayName() const
9175 switch ( fWriter.fOptions.outputKind() ) {
9176 case Options::kDynamicExecutable:
9177 case Options::kStaticExecutable:
9178 case Options::kDynamicLibrary:
9179 case Options::kDynamicBundle:
9180 case Options::kDyld:
9181 return this->getName();
9182 case Options::kObjectFile:
9183 case Options::kPreload:
9184 case Options::kKextBundle:
9185 return "mach header";
9187 throw "unknown header type";
9190 template <typename A>
9191 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
9194 uint32_t fileType = 0;
9195 switch ( fWriter.fOptions.outputKind() ) {
9196 case Options::kDynamicExecutable:
9197 case Options::kStaticExecutable:
9198 fileType = MH_EXECUTE;
9200 case Options::kDynamicLibrary:
9201 fileType = MH_DYLIB;
9203 case Options::kDynamicBundle:
9204 fileType = MH_BUNDLE;
9206 case Options::kObjectFile:
9207 fileType = MH_OBJECT;
9209 case Options::kDyld:
9210 fileType = MH_DYLINKER;
9212 case Options::kPreload:
9213 fileType = MH_PRELOAD;
9215 case Options::kKextBundle:
9216 fileType = MH_KEXT_BUNDLE;
9222 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
9223 if ( fWriter.fCanScatter )
9224 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
9227 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
9228 flags |= MH_NOUNDEFS;
9230 else if ( fWriter.fOptions.outputKind() == Options::kPreload ) {
9231 flags |= MH_NOUNDEFS;
9232 if ( fWriter.fOptions.positionIndependentExecutable() )
9236 flags = MH_DYLDLINK;
9237 if ( fWriter.fOptions.bindAtLoad() )
9238 flags |= MH_BINDATLOAD;
9239 switch ( fWriter.fOptions.nameSpace() ) {
9240 case Options::kTwoLevelNameSpace:
9241 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
9243 case Options::kFlatNameSpace:
9245 case Options::kForceFlatNameSpace:
9246 flags |= MH_FORCE_FLAT;
9249 bool hasWeakDefines = fWriter.fHasWeakExports;
9250 if ( fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->size() != 0 ) {
9251 for(std::set<const ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
9252 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
9253 if ( fWriter.shouldExport(**it) ) {
9254 hasWeakDefines = true;
9259 if ( hasWeakDefines )
9260 flags |= MH_WEAK_DEFINES;
9261 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
9262 flags |= MH_BINDS_TO_WEAK;
9263 if ( fWriter.fOptions.prebind() )
9264 flags |= MH_PREBOUND;
9265 if ( fWriter.fOptions.splitSeg() )
9266 flags |= MH_SPLIT_SEGS;
9267 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
9268 flags |= MH_NO_REEXPORTED_DYLIBS;
9269 if ( fWriter.fOptions.positionIndependentExecutable() )
9271 if ( fWriter.fOptions.markAutoDeadStripDylib() )
9272 flags |= MH_DEAD_STRIPPABLE_DYLIB;
9274 if ( fWriter.fOptions.hasExecutableStack() )
9275 flags |= MH_ALLOW_STACK_EXECUTION;
9276 if ( fWriter.fOptions.readerOptions().fRootSafe )
9277 flags |= MH_ROOT_SAFE;
9278 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
9279 flags |= MH_SETUID_SAFE;
9282 // get commands info
9283 uint32_t commandsSize = 0;
9284 uint32_t commandsCount = 0;
9286 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
9287 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
9288 ObjectFile::Atom* atom = *it;
9289 commandsSize += atom->getSize();
9290 // segment and symbol table atoms can contain more than one load command
9291 if ( atom == fWriter.fSegmentCommands )
9292 commandsCount += fWriter.fSegmentCommands->commandCount();
9293 else if ( atom == fWriter.fSymbolTableCommands )
9294 commandsCount += fWriter.fSymbolTableCommands->commandCount();
9295 else if ( atom->getSize() != 0 )
9299 // fill out mach_header
9300 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
9302 mh->set_filetype(fileType);
9303 mh->set_ncmds(commandsCount);
9304 mh->set_sizeofcmds(commandsSize);
9305 mh->set_flags(flags);
9309 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
9311 header.set_magic(MH_MAGIC);
9312 header.set_cputype(CPU_TYPE_POWERPC);
9313 header.set_cpusubtype(fWriter.fCpuConstraint);
9317 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
9319 header.set_magic(MH_MAGIC_64);
9320 header.set_cputype(CPU_TYPE_POWERPC64);
9321 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9322 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
9324 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
9325 header.set_reserved(0);
9329 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
9331 header.set_magic(MH_MAGIC);
9332 header.set_cputype(CPU_TYPE_I386);
9333 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
9337 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
9339 header.set_magic(MH_MAGIC_64);
9340 header.set_cputype(CPU_TYPE_X86_64);
9341 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9342 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
9344 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
9345 header.set_reserved(0);
9349 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
9351 header.set_magic(MH_MAGIC);
9352 header.set_cputype(CPU_TYPE_ARM);
9353 header.set_cpusubtype(fWriter.fCpuConstraint);
9356 template <typename A>
9357 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
9358 : WriterAtom<A>(writer, Segment::fgStackSegment)
9360 if ( stackGrowsDown() )
9361 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
9363 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
9367 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
9368 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
9369 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
9370 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
9371 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
9373 template <typename A>
9374 void SegmentLoadCommandsAtom<A>::computeSize()
9377 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9379 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9380 SegmentInfo* seg = *it;
9381 if ( seg->fHasLoadCommand ) {
9383 size += sizeof(macho_segment_command<P>);
9384 std::vector<SectionInfo*>& sectionInfos = seg->fSections;
9385 const int sectionCount = sectionInfos.size();
9386 for(int j=0; j < sectionCount; ++j) {
9387 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
9388 size += sizeof(macho_section<P>);
9393 fCommandCount = segCount;
9394 if ( fWriter.fPadSegmentInfo != NULL ) {
9396 fSize += sizeof(macho_segment_command<P>);
9401 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
9403 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9407 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
9409 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9413 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
9415 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9419 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
9421 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9425 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
9427 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9430 template <typename A>
9431 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9433 uint64_t size = this->getSize();
9434 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
9435 bzero(buffer, size);
9436 uint8_t* p = buffer;
9437 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9438 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9439 SegmentInfo* segInfo = *it;
9440 if ( ! segInfo->fHasLoadCommand )
9442 const int sectionCount = segInfo->fSections.size();
9443 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
9444 cmd->set_cmd(macho_segment_command<P>::CMD);
9445 cmd->set_segname(segInfo->fName);
9446 cmd->set_vmaddr(segInfo->fBaseAddress);
9447 cmd->set_vmsize(oneSegment ? 0 : segInfo->fSize);
9448 cmd->set_fileoff(segInfo->fFileOffset);
9449 cmd->set_filesize(oneSegment ? 0 : segInfo->fFileSize);
9450 cmd->set_maxprot(segInfo->fMaxProtection);
9451 cmd->set_initprot(segInfo->fInitProtection);
9452 // add sections array
9453 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
9454 unsigned int sectionsEmitted = 0;
9455 for (int j=0; j < sectionCount; ++j) {
9456 SectionInfo* sectInfo = segInfo->fSections[j];
9457 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
9458 macho_section<P>* sect = §ions[sectionsEmitted++];
9460 // .o file segment does not cover load commands, so recalc at first real section
9461 if ( sectionsEmitted == 1 ) {
9462 cmd->set_vmaddr(sectInfo->getBaseAddress());
9463 cmd->set_fileoff(sectInfo->fFileOffset);
9465 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
9466 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
9468 sect->set_sectname(sectInfo->fSectionName);
9469 sect->set_segname(sectInfo->fSegmentName);
9470 sect->set_addr(sectInfo->getBaseAddress());
9471 sect->set_size(sectInfo->fSize);
9472 sect->set_offset(sectInfo->fFileOffset);
9473 sect->set_align(sectInfo->fAlignment);
9474 if ( sectInfo->fRelocCount != 0 ) {
9475 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
9476 sect->set_nreloc(sectInfo->fRelocCount);
9478 if ( sectInfo->fAllZeroFill ) {
9479 sect->set_flags(S_ZEROFILL);
9480 sect->set_offset(0);
9482 else if ( sectInfo->fAllLazyPointers ) {
9483 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
9484 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9486 else if ( sectInfo->fAllLazyDylibPointers ) {
9487 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
9488 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9490 else if ( sectInfo->fAllNonLazyPointers ) {
9491 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
9492 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9494 else if ( sectInfo->fAllStubs ) {
9495 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9496 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9497 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9498 if ( sectInfo->fHasTextLocalRelocs )
9499 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9501 else if ( sectInfo->fAllSelfModifyingStubs ) {
9502 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
9503 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9504 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9506 else if ( sectInfo->fAllStubHelpers ) {
9507 sect->set_flags(S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9508 if ( sectInfo->fHasTextLocalRelocs )
9509 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9511 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCStringType ) {
9512 sect->set_flags(S_CSTRING_LITERALS);
9514 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCFIType ) {
9515 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
9517 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9518 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
9520 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9521 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
9523 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9524 sect->set_flags(S_COALESCED);
9526 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9527 sect->set_flags(S_COALESCED);
9529 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9530 sect->set_flags(S_INTERPOSING);
9532 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9533 sect->set_flags(S_4BYTE_LITERALS);
9535 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9536 sect->set_flags(S_8BYTE_LITERALS);
9538 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9539 sect->set_flags(S_16BYTE_LITERALS);
9541 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9542 sect->set_flags(S_LITERAL_POINTERS);
9544 else if ( (strcmp(sectInfo->fSectionName, "__objc_selrefs") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9545 sect->set_flags(S_LITERAL_POINTERS);
9547 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9548 sect->set_flags(S_LITERAL_POINTERS);
9550 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9551 sect->set_flags(S_DTRACE_DOF);
9553 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9554 sect->set_flags(S_DTRACE_DOF);
9556 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9557 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9558 if ( sectInfo->fHasTextLocalRelocs )
9559 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9560 if ( sectInfo->fHasTextExternalRelocs )
9561 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
9563 //fprintf(stderr, "section %s flags=0x%08X\n", sectInfo->fSectionName, sect->flags());
9566 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
9567 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
9568 cmd->set_nsects(sectionsEmitted);
9573 template <typename A>
9574 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
9575 : LoadCommandAtom<A>(writer), fNeedsDynamicSymbolTable(false)
9577 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
9578 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
9579 switch ( fWriter.fOptions.outputKind() ) {
9580 case Options::kDynamicExecutable:
9581 case Options::kDynamicLibrary:
9582 case Options::kDynamicBundle:
9583 case Options::kDyld:
9584 case Options::kKextBundle:
9585 fNeedsDynamicSymbolTable = true;
9587 case Options::kObjectFile:
9588 case Options::kStaticExecutable:
9589 fNeedsDynamicSymbolTable = false;
9590 case Options::kPreload:
9591 fNeedsDynamicSymbolTable = fWriter.fOptions.positionIndependentExecutable();
9594 writer.fSymbolTableCommands = this;
9599 template <typename A>
9600 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
9602 fNeedsDynamicSymbolTable = true;
9606 template <typename A>
9607 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
9609 if ( fNeedsDynamicSymbolTable )
9610 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
9612 return this->alignedSize(sizeof(macho_symtab_command<P>));
9615 template <typename A>
9616 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9618 // build LC_SYMTAB command
9619 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
9620 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
9621 symbolTableCmd->set_cmd(LC_SYMTAB);
9622 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
9623 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
9624 symbolTableCmd->set_symoff(fWriter.fSymbolTableCount == 0 ? 0 : fWriter.fSymbolTableAtom->getFileOffset());
9625 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getSize() == 0 ? 0 : fWriter.fStringsAtom->getFileOffset());
9626 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
9628 // build LC_DYSYMTAB command
9629 if ( fNeedsDynamicSymbolTable ) {
9630 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
9631 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
9632 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
9633 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
9634 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
9635 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
9636 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
9637 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
9638 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
9639 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
9640 if ( fWriter.fModuleInfoAtom != NULL ) {
9641 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
9642 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
9643 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
9644 dynamicSymbolTableCmd->set_nmodtab(1);
9645 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
9646 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
9648 dynamicSymbolTableCmd->set_indirectsymoff((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->getFileOffset());
9649 dynamicSymbolTableCmd->set_nindirectsyms((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->fTable.size());
9650 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
9651 if ( fWriter.fExternalRelocationsAtom != 0 ) {
9652 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
9653 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
9655 if ( fWriter.fLocalRelocationsAtom != 0 ) {
9656 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
9657 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
9664 template <typename A>
9665 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
9667 return fNeedsDynamicSymbolTable ? 2 : 1;
9670 template <typename A>
9671 uint64_t DyldLoadCommandsAtom<A>::getSize() const
9673 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
9676 template <typename A>
9677 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9679 uint64_t size = this->getSize();
9680 bzero(buffer, size);
9681 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
9682 if ( fWriter.fOptions.outputKind() == Options::kDyld )
9683 cmd->set_cmd(LC_ID_DYLINKER);
9685 cmd->set_cmd(LC_LOAD_DYLINKER);
9686 cmd->set_cmdsize(this->getSize());
9687 cmd->set_name_offset();
9688 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
9691 template <typename A>
9692 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
9694 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
9697 template <typename A>
9698 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9700 uint64_t size = this->getSize();
9702 bzero(buffer, size);
9703 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
9704 cmd->set_cmd(LC_SUB_CLIENT);
9705 cmd->set_cmdsize(size);
9706 cmd->set_client_offset();
9707 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
9711 template <typename A>
9712 uint64_t DylibLoadCommandsAtom<A>::getSize() const
9714 if ( fOptimizedAway ) {
9718 const char* path = fInfo.reader->getInstallPath();
9719 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
9723 template <typename A>
9724 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9726 if ( fOptimizedAway )
9728 uint64_t size = this->getSize();
9729 bzero(buffer, size);
9730 const char* path = fInfo.reader->getInstallPath();
9731 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9732 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
9733 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
9734 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
9735 if ( fInfo.options.fLazyLoad )
9736 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
9737 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
9738 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
9739 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9740 cmd->set_cmd(LC_REEXPORT_DYLIB);
9742 cmd->set_cmd(LC_LOAD_DYLIB);
9743 cmd->set_cmdsize(this->getSize());
9744 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
9745 cmd->set_current_version(fInfo.reader->getCurrentVersion());
9746 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
9747 cmd->set_name_offset();
9748 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
9753 template <typename A>
9754 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
9756 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
9759 template <typename A>
9760 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9762 uint64_t size = this->getSize();
9763 bzero(buffer, size);
9764 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9765 cmd->set_cmd(LC_ID_DYLIB);
9766 cmd->set_cmdsize(this->getSize());
9767 cmd->set_name_offset();
9768 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
9769 cmd->set_current_version(fWriter.fOptions.currentVersion());
9770 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
9771 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
9775 template <typename A>
9776 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9778 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9779 if (fWriter.fEntryPoint->isThumb())
9781 bzero(buffer, sizeof(macho_routines_command<P>));
9782 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
9783 cmd->set_cmd(macho_routines_command<P>::CMD);
9784 cmd->set_cmdsize(this->getSize());
9785 cmd->set_init_address(initAddr);
9789 template <typename A>
9790 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
9792 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
9795 template <typename A>
9796 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9798 uint64_t size = this->getSize();
9799 bzero(buffer, size);
9800 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
9801 cmd->set_cmd(LC_SUB_UMBRELLA);
9802 cmd->set_cmdsize(this->getSize());
9803 cmd->set_sub_umbrella_offset();
9804 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
9807 template <typename A>
9808 void UUIDLoadCommandAtom<A>::generate()
9810 switch ( fWriter.fOptions.getUUIDMode() ) {
9811 case Options::kUUIDNone:
9814 case Options::kUUIDRandom:
9815 ::uuid_generate_random(fUUID);
9818 case Options::kUUIDContent:
9825 template <typename A>
9826 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
9828 memcpy(fUUID, uuid, 16);
9831 template <typename A>
9832 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
9835 uint64_t size = this->getSize();
9836 bzero(buffer, size);
9837 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
9838 cmd->set_cmd(LC_UUID);
9839 cmd->set_cmdsize(this->getSize());
9840 cmd->set_uuid((uint8_t*)fUUID);
9845 template <typename A>
9846 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
9848 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
9851 template <typename A>
9852 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9854 uint64_t size = this->getSize();
9855 bzero(buffer, size);
9856 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
9857 cmd->set_cmd(LC_SUB_LIBRARY);
9858 cmd->set_cmdsize(this->getSize());
9859 cmd->set_sub_library_offset();
9860 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
9861 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
9864 template <typename A>
9865 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
9867 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
9870 template <typename A>
9871 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9873 uint64_t size = this->getSize();
9874 bzero(buffer, size);
9875 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
9876 cmd->set_cmd(LC_SUB_FRAMEWORK);
9877 cmd->set_cmdsize(this->getSize());
9878 cmd->set_umbrella_offset();
9879 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
9883 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
9885 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
9889 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
9891 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
9895 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
9897 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
9901 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
9903 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
9906 // We should be picking it up from a header
9908 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
9910 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
9914 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
9916 uint64_t size = this->getSize();
9917 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9918 bzero(buffer, size);
9919 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
9920 cmd->set_cmd(LC_UNIXTHREAD);
9921 cmd->set_cmdsize(size);
9922 cmd->set_flavor(1); // PPC_THREAD_STATE
9923 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
9924 cmd->set_thread_register(0, start);
9925 if ( fWriter.fOptions.hasCustomStack() )
9926 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
9931 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
9933 uint64_t size = this->getSize();
9934 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9935 bzero(buffer, size);
9936 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
9937 cmd->set_cmd(LC_UNIXTHREAD);
9938 cmd->set_cmdsize(size);
9939 cmd->set_flavor(5); // PPC_THREAD_STATE64
9940 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
9941 cmd->set_thread_register(0, start);
9942 if ( fWriter.fOptions.hasCustomStack() )
9943 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
9947 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
9949 uint64_t size = this->getSize();
9950 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9951 bzero(buffer, size);
9952 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
9953 cmd->set_cmd(LC_UNIXTHREAD);
9954 cmd->set_cmdsize(size);
9955 cmd->set_flavor(1); // i386_THREAD_STATE
9956 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
9957 cmd->set_thread_register(10, start);
9958 if ( fWriter.fOptions.hasCustomStack() )
9959 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
9963 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
9965 uint64_t size = this->getSize();
9966 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9967 bzero(buffer, size);
9968 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
9969 cmd->set_cmd(LC_UNIXTHREAD);
9970 cmd->set_cmdsize(size);
9971 cmd->set_flavor(x86_THREAD_STATE64);
9972 cmd->set_count(x86_THREAD_STATE64_COUNT);
9973 cmd->set_thread_register(16, start); // rip
9974 if ( fWriter.fOptions.hasCustomStack() )
9975 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
9979 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
9981 uint64_t size = this->getSize();
9982 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9983 if ( fWriter.fEntryPoint->isThumb() )
9985 bzero(buffer, size);
9986 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
9987 cmd->set_cmd(LC_UNIXTHREAD);
9988 cmd->set_cmdsize(size);
9991 cmd->set_thread_register(15, start); // pc
9992 if ( fWriter.fOptions.hasCustomStack() )
9993 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
9996 template <typename A>
9997 uint64_t RPathLoadCommandsAtom<A>::getSize() const
9999 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
10002 template <typename A>
10003 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10005 uint64_t size = this->getSize();
10006 bzero(buffer, size);
10007 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
10008 cmd->set_cmd(LC_RPATH);
10009 cmd->set_cmdsize(this->getSize());
10010 cmd->set_path_offset();
10011 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
10016 template <typename A>
10017 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10019 uint64_t size = this->getSize();
10020 bzero(buffer, size);
10021 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
10022 cmd->set_cmd(LC_ENCRYPTION_INFO);
10023 cmd->set_cmdsize(this->getSize());
10024 cmd->set_cryptoff(fStartOffset);
10025 cmd->set_cryptsize(fEndOffset-fStartOffset);
10026 cmd->set_cryptid(0);
10031 template <typename A>
10032 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
10034 bzero(buffer, fSize);
10037 template <typename A>
10038 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
10041 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
10042 if ( fWriter.fLargestAtomSize < newSize )
10043 fWriter.fLargestAtomSize = newSize;
10046 template <typename A>
10047 void UnwindInfoAtom<A>::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
10048 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsdaRef,
10049 ObjectFile::Atom* personalityPointer)
10053 if ( fdeRef != NULL )
10054 info.fde = &fdeRef->getTarget();
10057 if ( lsdaRef != NULL ) {
10058 info.lsda = &lsdaRef->getTarget();
10059 info.lsdaOffset = lsdaRef->getTargetOffset();
10063 info.lsdaOffset = 0;
10065 info.personalityPointer = personalityPointer;
10066 info.encoding = encoding;
10067 fInfos.push_back(info);
10068 //fprintf(stderr, "addUnwindInfo() encoding=0x%08X, lsda=%p, lsdaOffset=%d, person=%p, func=%s\n",
10069 // encoding, info.lsda, info.lsdaOffset, personalityPointer, func->getDisplayName());
10073 bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10075 return ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
10079 bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10081 return ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
10084 template <typename A>
10085 bool UnwindInfoAtom<A>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10091 template <typename A>
10092 void UnwindInfoAtom<A>::compressDuplicates(std::vector<Info>& uniqueInfos)
10094 // build new list removing entries where next function has same encoding
10095 uniqueInfos.reserve(fInfos.size());
10099 last.lsdaOffset = 0;
10100 last.personalityPointer = NULL;
10101 last.encoding = 0xFFFFFFFF;
10102 for(typename std::vector<Info>::iterator it=fInfos.begin(); it != fInfos.end(); ++it) {
10103 Info& newInfo = *it;
10104 bool newNeedsDwarf = encodingMeansUseDwarf(newInfo.encoding);
10105 // remove infos which have same encoding and personalityPointer as last one
10106 if ( newNeedsDwarf || (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer)
10107 || (newInfo.lsda != NULL) || (last.lsda != NULL) ) {
10108 uniqueInfos.push_back(newInfo);
10112 //fprintf(stderr, "compressDuplicates() fInfos.size()=%lu, uniqueInfos.size()=%lu\n", fInfos.size(), uniqueInfos.size());
10115 template <typename A>
10116 void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings)
10118 // scan infos to get frequency counts for each encoding
10119 std::map<uint32_t, unsigned int> encodingsUsed;
10120 unsigned int mostCommonEncodingUsageCount = 0;
10121 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10122 // never put dwarf into common table
10123 if ( encodingMeansUseDwarf(it->encoding) )
10125 std::map<uint32_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
10126 if ( pos == encodingsUsed.end() ) {
10127 encodingsUsed[it->encoding] = 1;
10130 encodingsUsed[it->encoding] += 1;
10131 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
10132 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
10135 // put the most common encodings into the common table, but at most 127 of them
10136 for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
10137 for (std::map<uint32_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
10138 if ( euit->second == usages ) {
10139 unsigned int size = commonEncodings.size();
10140 if ( size < 127 ) {
10141 commonEncodings[euit->first] = size;
10148 template <typename A>
10149 void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap)
10151 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10152 lsdaIndexOffsetMap[it->func] = fLSDAIndex.size() * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10153 if ( it->lsda != NULL ) {
10155 entry.func = it->func;
10156 entry.lsda = it->lsda;
10157 entry.lsdaOffset = it->lsdaOffset;
10158 fLSDAIndex.push_back(entry);
10163 template <typename A>
10164 void UnwindInfoAtom<A>::makePersonalityIndex(std::vector<Info>& uniqueInfos)
10166 for(typename std::vector<Info>::iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10167 if ( it->personalityPointer != NULL ) {
10168 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fPersonalityIndexMap.find(it->personalityPointer);
10169 if ( pos == fPersonalityIndexMap.end() ) {
10170 const uint32_t nextIndex = fPersonalityIndexMap.size() + 1;
10171 fPersonalityIndexMap[it->personalityPointer] = nextIndex;
10173 uint32_t personalityIndex = fPersonalityIndexMap[it->personalityPointer];
10174 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
10179 template <typename A>
10180 unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize,
10181 unsigned int endIndex, uint8_t*& pageEnd)
10183 const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10184 const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
10185 uint8_t* pageStart = pageEnd
10186 - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
10187 - sizeof(unwind_info_regular_second_level_page_header);
10188 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
10189 page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
10190 page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
10191 page->set_entryCount(entriesToAdd);
10192 macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
10193 for (unsigned int i=0; i < entriesToAdd; ++i) {
10194 const Info& info = uniqueInfos[endIndex-entriesToAdd+i];
10195 entryTable[i].set_functionOffset(0);
10196 entryTable[i].set_encoding(info.encoding);
10198 fixup.contentPointer = (uint8_t*)(&entryTable[i]);
10199 fixup.func = info.func;
10200 fixup.fde = ( encodingMeansUseDwarf(info.encoding) ? info.fde : NULL );
10201 fRegFixUps.push_back(fixup);
10203 //fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
10204 pageEnd = pageStart;
10205 return endIndex - entriesToAdd;
10209 template <typename A>
10210 unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
10211 const std::map<uint32_t,unsigned int> commonEncodings,
10212 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
10214 const bool log = false;
10215 if (log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
10216 // first pass calculates how many compressed entries we could fit in this sized page
10217 // keep adding entries to page until:
10218 // 1) encoding table plus entry table plus header exceed page size
10219 // 2) the file offset delta from the first to last function > 24 bits
10220 // 3) custom encoding index reachs 255
10221 // 4) run out of uniqueInfos to encode
10222 std::map<uint32_t, unsigned int> pageSpecificEncodings;
10223 uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
10224 std::vector<uint8_t> encodingIndexes;
10225 int index = endIndex-1;
10226 int entryCount = 0;
10227 uint64_t lastEntryAddress = uniqueInfos[index].func->getAddress();
10229 while ( canDo && (index >= 0) ) {
10230 const Info& info = uniqueInfos[index--];
10231 // compute encoding index
10232 unsigned int encodingIndex;
10233 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10234 if ( pos != commonEncodings.end() ) {
10235 encodingIndex = pos->second;
10238 // no commmon entry, so add one on this page
10239 uint32_t encoding = info.encoding;
10240 if ( encodingMeansUseDwarf(encoding) ) {
10241 // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
10242 encoding += (index+1);
10244 std::map<uint32_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
10245 if ( ppos != pageSpecificEncodings.end() ) {
10246 encodingIndex = pos->second;
10249 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
10250 if ( encodingIndex <= 255 ) {
10251 pageSpecificEncodings[encoding] = encodingIndex;
10254 canDo = false; // case 3)
10255 if (log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
10256 entryCount, pageSpecificEncodings.size());
10261 encodingIndexes.push_back(encodingIndex);
10262 // compute function offset
10263 uint32_t funcOffsetWithInPage = lastEntryAddress - info.func->getAddress();
10264 if ( funcOffsetWithInPage > 0x00FFFF00 ) {
10265 // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
10266 canDo = false; // case 2)
10267 if (log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
10272 // check room for entry
10273 if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
10274 canDo = false; // case 1)
10276 if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
10278 //if (log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
10281 // check for cases where it would be better to use a regular (non-compressed) page
10282 const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
10283 + pageSpecificEncodings.size()*sizeof(uint32_t)
10284 + entryCount*sizeof(uint32_t);
10285 if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
10286 const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10287 if ( entryCount < regularEntriesPerPage ) {
10288 return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
10292 // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
10294 if ( compressPageUsed == (pageSize-4) )
10297 // second pass fills in page
10298 uint8_t* pageStart = pageEnd - compressPageUsed - pad;
10299 macho_unwind_info_compressed_second_level_page_header<P>* page = (macho_unwind_info_compressed_second_level_page_header<P>*)pageStart;
10300 page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
10301 page->set_entryPageOffset(sizeof(macho_unwind_info_compressed_second_level_page_header<P>));
10302 page->set_entryCount(entryCount);
10303 page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
10304 page->set_encodingsCount(pageSpecificEncodings.size());
10305 uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
10306 // fill in entry table
10307 uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
10308 ObjectFile::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
10309 for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
10310 const Info& info = uniqueInfos[i];
10311 uint8_t encodingIndex;
10312 if ( encodingMeansUseDwarf(info.encoding) ) {
10313 // dwarf entries are always in page specific encodings
10314 encodingIndex = pageSpecificEncodings[info.encoding+i];
10317 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10318 if ( pos != commonEncodings.end() )
10319 encodingIndex = pos->second;
10321 encodingIndex = pageSpecificEncodings[info.encoding];
10323 uint32_t entryIndex = i - endIndex + entryCount;
10324 A::P::E::set32(entiresArray[entryIndex], encodingIndex << 24);
10325 CompressedFixUp funcStartFixUp;
10326 funcStartFixUp.contentPointer = (uint8_t*)(&entiresArray[entryIndex]);
10327 funcStartFixUp.func = info.func;
10328 funcStartFixUp.fromFunc = firstFunc;
10329 fCompressedFixUps.push_back(funcStartFixUp);
10330 if ( encodingMeansUseDwarf(info.encoding) ) {
10331 CompressedEncodingFixUp dwarfStartFixup;
10332 dwarfStartFixup.contentPointer = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]);
10333 dwarfStartFixup.fde = info.fde;
10334 fCompressedEncodingFixUps.push_back(dwarfStartFixup);
10337 // fill in encodings table
10338 for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
10339 A::P::E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
10342 if (log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
10345 pageEnd = pageStart;
10346 return endIndex-entryCount; // endIndex for next page
10349 template <> void UnwindInfoAtom<ppc>::generate() { }
10350 template <> void UnwindInfoAtom<ppc64>::generate() { }
10351 template <> void UnwindInfoAtom<arm>::generate() { }
10354 template <typename A>
10355 void UnwindInfoAtom<A>::generate()
10357 // only generate table if there are functions with unwind info
10358 if ( fInfos.size() > 0 ) {
10359 // find offset of end of __unwind_info section
10360 SectionInfo* unwindSectionInfo = (SectionInfo*)this->getSection();
10362 // build new list that has proper offsetInImage and remove entries where next function has same encoding
10363 std::vector<Info> uniqueInfos;
10364 this->compressDuplicates(uniqueInfos);
10366 // build personality index, update encodings with personality index
10367 this->makePersonalityIndex(uniqueInfos);
10368 if ( fPersonalityIndexMap.size() > 3 )
10369 throw "too many personality routines for compact unwind to encode";
10371 // put the most common encodings into the common table, but at most 127 of them
10372 std::map<uint32_t, unsigned int> commonEncodings;
10373 this->findCommonEncoding(uniqueInfos, commonEncodings);
10375 // build lsda index
10376 std::map<ObjectFile::Atom*, uint32_t> lsdaIndexOffsetMap;
10377 this->makeLsdaIndex(uniqueInfos, lsdaIndexOffsetMap);
10379 // calculate worst case size for all unwind info pages when allocating buffer
10380 const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10381 const unsigned int pageCount = ((uniqueInfos.size() - 1)/entriesPerRegularPage) + 1;
10382 fPagesContentForDelete = (uint8_t*)calloc(pageCount,4096);
10384 if ( fPagesContentForDelete == NULL )
10385 throw "could not allocate space for compact unwind info";
10386 ObjectFile::Atom* secondLevelFirstFuncs[pageCount*3];
10387 uint8_t* secondLevelPagesStarts[pageCount*3];
10389 // make last second level page smaller so that all other second level pages can be page aligned
10390 uint32_t maxLastPageSize = unwindSectionInfo->fFileOffset % 4096;
10391 uint32_t tailPad = 0;
10392 if ( maxLastPageSize < 128 ) {
10393 tailPad = maxLastPageSize;
10394 maxLastPageSize = 4096;
10397 // fill in pages in reverse order
10398 unsigned int endIndex = uniqueInfos.size();
10399 unsigned int secondLevelPageCount = 0;
10400 uint8_t* pageEnd = &fPagesContentForDelete[pageCount*4096];
10401 uint32_t pageSize = maxLastPageSize;
10402 while ( endIndex > 0 ) {
10403 endIndex = makeCompressedSecondLevelPage(uniqueInfos, commonEncodings, pageSize, endIndex, pageEnd);
10404 secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
10405 secondLevelFirstFuncs[secondLevelPageCount] = uniqueInfos[endIndex].func;
10406 ++secondLevelPageCount;
10407 pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
10409 fPagesContent = pageEnd;
10410 fPagesSize = &fPagesContentForDelete[pageCount*4096] - pageEnd;
10412 // calculate section layout
10413 const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
10414 const uint32_t commonEncodingsArrayCount = commonEncodings.size();
10415 const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
10416 const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
10417 const uint32_t personalityArrayCount = fPersonalityIndexMap.size();
10418 const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
10419 const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
10420 const uint32_t indexCount = secondLevelPageCount+1;
10421 const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
10422 const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
10423 const uint32_t lsdaIndexArrayCount = fLSDAIndex.size();
10424 const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10425 const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
10428 // allocate and fill in section header
10429 fHeaderSize = headerEndSectionOffset;
10430 fHeaderContent = new uint8_t[fHeaderSize];
10431 bzero(fHeaderContent, fHeaderSize);
10432 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)fHeaderContent;
10433 sectionHeader->set_version(UNWIND_SECTION_VERSION);
10434 sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
10435 sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
10436 sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
10437 sectionHeader->set_personalityArrayCount(personalityArrayCount);
10438 sectionHeader->set_indexSectionOffset(indexSectionOffset);
10439 sectionHeader->set_indexCount(indexCount);
10441 // copy common encodings
10442 uint32_t* commonEncodingsTable = (uint32_t*)&fHeaderContent[commonEncodingsArraySectionOffset];
10443 for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
10444 A::P::E::set32(commonEncodingsTable[it->second], it->first);
10446 // make references for personality entries
10447 uint32_t* personalityArray = (uint32_t*)&fHeaderContent[sectionHeader->personalityArraySectionOffset()];
10448 for (std::map<ObjectFile::Atom*, unsigned int>::iterator it=fPersonalityIndexMap.begin(); it != fPersonalityIndexMap.end(); ++it) {
10449 uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - fHeaderContent;
10450 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->first));
10453 // build first level index and references
10454 macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&fHeaderContent[indexSectionOffset];
10455 for (unsigned int i=0; i < secondLevelPageCount; ++i) {
10456 unsigned int reverseIndex = secondLevelPageCount - 1 - i;
10457 indexTable[i].set_functionOffset(0);
10458 indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-fPagesContent+headerEndSectionOffset);
10459 indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
10460 uint32_t refOffset = (uint8_t*)&indexTable[i] - fHeaderContent;
10461 fReferences.push_back(new WriterReference<A>(refOffset, A::kImageOffset32, secondLevelFirstFuncs[reverseIndex]));
10463 indexTable[secondLevelPageCount].set_functionOffset(0);
10464 indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
10465 indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
10466 fReferences.push_back(new WriterReference<A>((uint8_t*)&indexTable[secondLevelPageCount] - fHeaderContent, A::kImageOffset32,
10467 fInfos.back().func, fInfos.back().func->getSize()+1));
10469 // build lsda references
10470 uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
10471 for (typename std::vector<LSDAEntry>::iterator it = fLSDAIndex.begin(); it != fLSDAIndex.end(); ++it) {
10472 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset, A::kImageOffset32, it->func));
10473 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset+4, A::kImageOffset32, it->lsda, it->lsdaOffset));
10474 lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
10477 // make references for regular second level entries
10478 for (typename std::vector<RegFixUp>::iterator it = fRegFixUps.begin(); it != fRegFixUps.end(); ++it) {
10479 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10480 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->func));
10481 if ( it->fde != NULL )
10482 fReferences.push_back(new WriterReference<A>(offset+4, A::kSectionOffset24, it->fde));
10484 // make references for compressed second level entries
10485 for (typename std::vector<CompressedFixUp>::iterator it = fCompressedFixUps.begin(); it != fCompressedFixUps.end(); ++it) {
10486 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10487 fReferences.push_back(new WriterReference<A>(offset, A::kPointerDiff24, it->func, 0, it->fromFunc, 0));
10489 for (typename std::vector<CompressedEncodingFixUp>::iterator it = fCompressedEncodingFixUps.begin(); it != fCompressedEncodingFixUps.end(); ++it) {
10490 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10491 fReferences.push_back(new WriterReference<A>(offset, A::kSectionOffset24, it->fde));
10494 // update section record with new size
10495 unwindSectionInfo->fSize = this->getSize();
10497 // alter alignment so this section lays out so second level tables are page aligned
10498 if ( secondLevelPageCount > 2 )
10499 fAlignment = ObjectFile::Alignment(12, (unwindSectionInfo->fFileOffset - this->getSize()) % 4096);
10507 template <typename A>
10508 void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10510 memcpy(buffer, fHeaderContent, fHeaderSize);
10511 memcpy(&buffer[fHeaderSize], fPagesContent, fPagesSize);
10516 template <typename A>
10517 uint64_t LinkEditAtom<A>::getFileOffset() const
10519 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
10523 template <typename A>
10524 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
10526 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
10529 template <typename A>
10530 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10532 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
10536 template <typename A>
10537 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
10539 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
10542 template <typename A>
10543 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10545 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
10550 template <typename A>
10551 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
10553 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
10556 template <typename A>
10557 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10559 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
10562 template <typename A>
10563 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
10565 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
10568 template <typename A>
10569 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10571 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
10572 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
10577 template <typename A>
10578 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
10580 return fTable.size() * sizeof(uint32_t);
10583 template <typename A>
10584 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10586 uint64_t size = this->getSize();
10587 bzero(buffer, size);
10588 const uint32_t indirectTableSize = fTable.size();
10589 uint32_t* indirectTable = (uint32_t*)buffer;
10590 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
10591 if ( it->indirectIndex < indirectTableSize )
10592 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
10594 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
10600 template <typename A>
10601 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
10603 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
10604 + sizeof(macho_dylib_module<P>)
10605 + this->getReferencesCount()*sizeof(uint32_t);
10608 template <typename A>
10609 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
10611 return this->getFileOffset();
10614 template <typename A>
10615 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
10617 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
10620 template <typename A>
10621 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
10623 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
10626 template <typename A>
10627 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
10629 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
10632 template <typename A>
10633 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10635 uint64_t size = this->getSize();
10636 bzero(buffer, size);
10637 // create toc. The symbols are already sorted, they are all in the smae module
10638 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
10639 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
10640 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
10641 p->set_module_index(0);
10643 // create module table (one entry)
10644 pint_t objcModuleSectionStart = 0;
10645 pint_t objcModuleSectionSize = 0;
10646 uint16_t numInits = 0;
10647 uint16_t numTerms = 0;
10648 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
10649 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
10650 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
10651 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
10652 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10653 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
10654 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10655 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
10656 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10659 else if ( strcmp((*segit)->fName, "__OBJC") == 0 ) {
10660 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10661 SectionInfo* sectInfo = (*sectit);
10662 if ( strcmp(sectInfo->fSectionName, "__module_info") == 0 ) {
10663 objcModuleSectionStart = sectInfo->getBaseAddress();
10664 objcModuleSectionSize = sectInfo->fSize;
10669 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
10670 module->set_module_name(fModuleNameOffset);
10671 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
10672 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
10673 module->set_irefsym(0);
10674 module->set_nrefsym(this->getReferencesCount());
10675 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
10676 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
10677 module->set_iextrel(0);
10678 module->set_nextrel(fWriter.fExternalRelocs.size());
10679 module->set_iinit_iterm(0,0);
10680 module->set_ninit_nterm(numInits,numTerms);
10681 module->set_objc_module_info_addr(objcModuleSectionStart);
10682 module->set_objc_module_info_size(objcModuleSectionSize);
10683 // create reference table
10684 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
10685 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
10686 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
10687 ref->set_flags(REFERENCE_FLAG_DEFINED);
10689 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
10690 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
10691 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
10692 if ( pos != fWriter.fStubsMap.end() )
10693 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
10695 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
10701 template <typename A>
10702 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
10703 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
10705 fCurrentBuffer = new char[kBufferSize];
10706 // burn first byte of string pool (so zero is never a valid string offset)
10707 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
10708 // make offset 1 always point to an empty string
10709 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
10712 template <typename A>
10713 uint64_t StringsLinkEditAtom<A>::getSize() const
10716 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
10719 template <typename A>
10720 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10722 uint64_t offset = 0;
10723 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
10724 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
10725 offset += kBufferSize;
10727 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
10728 // zero fill end to align
10729 offset += fCurrentBufferUsed;
10730 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
10731 buffer[offset++] = 0;
10734 template <typename A>
10735 int32_t StringsLinkEditAtom<A>::add(const char* name)
10737 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
10738 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
10739 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
10740 fCurrentBufferUsed += lenNeeded;
10743 int copied = kBufferSize-fCurrentBufferUsed-1;
10744 // change trailing '\0' that strlcpy added to real char
10745 fCurrentBuffer[kBufferSize-1] = name[copied];
10746 // alloc next buffer
10747 fFullBuffers.push_back(fCurrentBuffer);
10748 fCurrentBuffer = new char[kBufferSize];
10749 fCurrentBufferUsed = 0;
10750 // append rest of string
10751 this->add(&name[copied+1]);
10757 template <typename A>
10758 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
10760 StringToOffset::iterator pos = fUniqueStrings.find(name);
10761 if ( pos != fUniqueStrings.end() ) {
10762 return pos->second;
10765 int32_t offset = this->add(name);
10766 fUniqueStrings[name] = offset;
10772 template <typename A>
10773 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
10775 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
10776 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
10777 // check for out of bounds
10778 if ( index > maxIndex )
10780 // check for index in fCurrentBuffer
10781 if ( index > currentBufferStartIndex )
10782 return &fCurrentBuffer[index-currentBufferStartIndex];
10783 // otherwise index is in a full buffer
10784 uint32_t fullBufferIndex = index/kBufferSize;
10785 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
10790 template <typename A>
10791 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
10792 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
10794 char* buf = new char[strlen(name)+32];
10795 if ( targetOffset == 0 ) {
10796 if ( islandRegion == 0 )
10797 sprintf(buf, "%s$island", name);
10799 sprintf(buf, "%s$island_%d", name, islandRegion);
10802 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
10809 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
10811 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
10812 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10813 OSWriteBigInt32(buffer, 0, branchInstruction);
10817 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
10819 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
10820 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10821 OSWriteBigInt32(buffer, 0, branchInstruction);
10825 uint64_t BranchIslandAtom<ppc>::getSize() const
10831 uint64_t BranchIslandAtom<ppc64>::getSize() const
10838 template <typename A>
10839 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
10841 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
10842 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
10844 return 0; // a zero size causes the load command to be suppressed
10847 template <typename A>
10848 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10850 uint64_t size = this->getSize();
10852 bzero(buffer, size);
10853 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
10854 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
10855 cmd->set_cmdsize(size);
10856 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
10857 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
10862 template <typename A>
10863 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
10865 return fEncodedData.size();
10868 template <typename A>
10869 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
10871 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
10875 template <typename A>
10876 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
10878 pint_t addr = fWriter.fOptions.baseAddress();
10879 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
10880 pint_t nextAddr = it->atom->getAddress() + it->offset;
10881 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
10882 uint64_t delta = nextAddr - addr;
10884 throw "double split seg info for same address";
10888 byte = delta & 0x7F;
10892 fEncodedData.push_back(byte);
10893 delta = delta >> 7;
10895 while( byte >= 0x80 );
10900 template <typename A>
10901 void SegmentSplitInfoContentAtom<A>::encode()
10903 if ( ! fCantEncode ) {
10904 fEncodedData.reserve(8192);
10906 if ( fKind1Locations.size() != 0 ) {
10907 fEncodedData.push_back(1);
10908 //fprintf(stderr, "type 1:\n");
10909 this->uleb128EncodeAddresses(fKind1Locations);
10910 fEncodedData.push_back(0);
10913 if ( fKind2Locations.size() != 0 ) {
10914 fEncodedData.push_back(2);
10915 //fprintf(stderr, "type 2:\n");
10916 this->uleb128EncodeAddresses(fKind2Locations);
10917 fEncodedData.push_back(0);
10920 if ( fKind3Locations.size() != 0 ) {
10921 fEncodedData.push_back(3);
10922 //fprintf(stderr, "type 3:\n");
10923 this->uleb128EncodeAddresses(fKind3Locations);
10924 fEncodedData.push_back(0);
10927 if ( fKind4Locations.size() != 0 ) {
10928 fEncodedData.push_back(4);
10929 //fprintf(stderr, "type 4:\n");
10930 this->uleb128EncodeAddresses(fKind4Locations);
10931 fEncodedData.push_back(0);
10934 // always add zero byte to mark end
10935 fEncodedData.push_back(0);
10937 // add zeros to end to align size
10938 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
10939 fEncodedData.push_back(0);
10944 template <typename A>
10945 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
10946 : WriterAtom<A>(writer, getInfoSegment())
10949 uint32_t value = 0;
10950 // struct objc_image_info {
10951 // uint32_t version; // initially 0
10954 // #define OBJC_IMAGE_SUPPORTS_GC 2
10955 // #define OBJC_IMAGE_GC_ONLY 4
10957 if ( objcReplacementClasses )
10959 switch ( objcConstraint ) {
10960 case ObjectFile::Reader::kObjcNone:
10961 case ObjectFile::Reader::kObjcRetainRelease:
10963 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
10966 case ObjectFile::Reader::kObjcGC:
10970 A::P::E::set32(fContent[1], value);
10973 template <typename A>
10974 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10976 memcpy(buffer, &fContent[0], 8);
10980 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
10981 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
10982 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
10983 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
10984 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
10985 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
10987 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
10988 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
10989 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
10990 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
10991 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
10996 template <typename A>
10997 void DyldInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10999 // build LC_DYLD_INFO command
11000 macho_dyld_info_command<P>* cmd = (macho_dyld_info_command<P>*)buffer;
11001 bzero(cmd, sizeof(macho_dyld_info_command<P>));
11003 cmd->set_cmd( fWriter.fOptions.makeClassicDyldInfo() ? LC_DYLD_INFO : LC_DYLD_INFO_ONLY);
11004 cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
11005 if ( (fWriter.fCompressedRebaseInfoAtom != NULL) && (fWriter.fCompressedRebaseInfoAtom->getSize() != 0) ) {
11006 cmd->set_rebase_off(fWriter.fCompressedRebaseInfoAtom->getFileOffset());
11007 cmd->set_rebase_size(fWriter.fCompressedRebaseInfoAtom->getSize());
11009 if ( (fWriter.fCompressedBindingInfoAtom != NULL) && (fWriter.fCompressedBindingInfoAtom->getSize() != 0) ) {
11010 cmd->set_bind_off(fWriter.fCompressedBindingInfoAtom->getFileOffset());
11011 cmd->set_bind_size(fWriter.fCompressedBindingInfoAtom->getSize());
11013 if ( (fWriter.fCompressedWeakBindingInfoAtom != NULL) && (fWriter.fCompressedWeakBindingInfoAtom->getSize() != 0) ) {
11014 cmd->set_weak_bind_off(fWriter.fCompressedWeakBindingInfoAtom->getFileOffset());
11015 cmd->set_weak_bind_size(fWriter.fCompressedWeakBindingInfoAtom->getSize());
11017 if ( (fWriter.fCompressedLazyBindingInfoAtom != NULL) && (fWriter.fCompressedLazyBindingInfoAtom->getSize() != 0) ) {
11018 cmd->set_lazy_bind_off(fWriter.fCompressedLazyBindingInfoAtom->getFileOffset());
11019 cmd->set_lazy_bind_size(fWriter.fCompressedLazyBindingInfoAtom->getSize());
11021 if ( (fWriter.fCompressedExportInfoAtom != NULL) && (fWriter.fCompressedExportInfoAtom->getSize() != 0) ) {
11022 cmd->set_export_off(fWriter.fCompressedExportInfoAtom->getFileOffset());
11023 cmd->set_export_size(fWriter.fCompressedExportInfoAtom->getSize());
11030 rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
11037 template <typename A>
11038 void CompressedRebaseInfoLinkEditAtom<A>::encode()
11040 // sort rebase info by type, then address
11041 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11042 std::vector<RebaseInfo>& info = fWriter.fRebaseInfo;
11043 std::sort(info.begin(), info.end());
11045 // convert to temp encoding that can be more easily optimized
11046 std::vector<rebase_tmp> mid;
11047 const SegmentInfo* currentSegment = NULL;
11048 unsigned int segIndex = 0;
11050 uint64_t address = (uint64_t)(-1);
11051 for (std::vector<RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11052 if ( type != it->fType ) {
11053 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->fType));
11056 if ( address != it->fAddress ) {
11057 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11058 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= it->fAddress) ) {
11060 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11061 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11062 currentSegment = *segit;
11067 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11070 mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11072 address = it->fAddress;
11074 mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
11075 address += sizeof(pint_t);
11077 mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
11079 // optimize phase 1, compress packed runs of pointers
11080 rebase_tmp* dst = &mid[0];
11081 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11082 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
11084 while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
11085 dst->operand1 += src->operand1;
11095 dst->opcode = REBASE_OPCODE_DONE;
11097 // optimize phase 2, combine rebase/add pairs
11099 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11100 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
11101 && (src->operand1 == 1)
11102 && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
11103 dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
11104 dst->operand1 = src[1].operand1;
11112 dst->opcode = REBASE_OPCODE_DONE;
11114 // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
11115 // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
11117 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11118 uint64_t delta = src->operand1;
11119 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11120 && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11121 && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11122 && (src[1].operand1 == delta)
11123 && (src[2].operand1 == delta) ) {
11124 // found at least three in a row, this is worth compressing
11125 dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
11127 dst->operand2 = delta;
11129 while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11130 && (src->operand1 == delta) ) {
11141 dst->opcode = REBASE_OPCODE_DONE;
11143 // optimize phase 4, use immediate encodings
11144 for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11145 if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB)
11146 && (p->operand1 < (15*sizeof(pint_t)))
11147 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11148 p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
11149 p->operand1 = p->operand1/sizeof(pint_t);
11151 else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
11152 p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
11156 // convert to compressed encoding
11157 const static bool log = false;
11158 fEncodedData.reserve(info.size()*2);
11160 for (std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11161 switch ( it->opcode ) {
11162 case REBASE_OPCODE_DONE:
11163 if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
11166 case REBASE_OPCODE_SET_TYPE_IMM:
11167 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11168 fEncodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
11170 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11171 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11172 fEncodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11173 fEncodedData.append_uleb128(it->operand2);
11175 case REBASE_OPCODE_ADD_ADDR_ULEB:
11176 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11177 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
11178 fEncodedData.append_uleb128(it->operand1);
11180 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
11181 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11182 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
11184 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
11185 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
11186 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
11188 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
11189 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
11190 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
11191 fEncodedData.append_uleb128(it->operand1);
11193 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
11194 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11195 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
11196 fEncodedData.append_uleb128(it->operand1);
11198 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
11199 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11200 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
11201 fEncodedData.append_uleb128(it->operand1);
11202 fEncodedData.append_uleb128(it->operand2);
11208 // align to pointer size
11209 fEncodedData.pad_to_size(sizeof(pint_t));
11211 if (log) fprintf(stderr, "total rebase info size = %ld\n", fEncodedData.size());
11217 binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
11218 : opcode(op), operand1(p1), operand2(p2), name(s) {}
11227 template <typename A>
11228 void CompressedBindingInfoLinkEditAtom<A>::encode()
11230 // sort by library, symbol, type, then address
11231 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11232 std::vector<BindingInfo>& info = fWriter.fBindingInfo;
11233 std::sort(info.begin(), info.end());
11235 // convert to temp encoding that can be more easily optimized
11236 std::vector<binding_tmp> mid;
11237 const SegmentInfo* currentSegment = NULL;
11238 unsigned int segIndex = 0;
11239 int ordinal = 0x80000000;
11240 const char* symbolName = NULL;
11242 uint64_t address = (uint64_t)(-1);
11243 int64_t addend = 0;
11244 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11245 if ( ordinal != it->fLibraryOrdinal ) {
11246 if ( it->fLibraryOrdinal <= 0 ) {
11247 // special lookups are encoded as negative numbers in BindingInfo
11248 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->fLibraryOrdinal));
11251 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->fLibraryOrdinal));
11253 ordinal = it->fLibraryOrdinal;
11255 if ( symbolName != it->fSymbolName ) {
11256 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11257 symbolName = it->fSymbolName;
11259 if ( type != it->fType ) {
11260 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11263 if ( address != it->fAddress ) {
11264 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11265 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress)
11266 || (it->fAddress < address) ) {
11268 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11269 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11270 currentSegment = *segit;
11275 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11278 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11280 address = it->fAddress;
11282 if ( addend != it->fAddend ) {
11283 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11284 addend = it->fAddend;
11286 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11287 address += sizeof(pint_t);
11289 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11292 // optimize phase 1, combine bind/add pairs
11293 binding_tmp* dst = &mid[0];
11294 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11295 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11296 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11297 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11298 dst->operand1 = src[1].operand1;
11306 dst->opcode = BIND_OPCODE_DONE;
11308 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11309 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11311 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11312 uint64_t delta = src->operand1;
11313 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11314 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11315 && (src[1].operand1 == delta) ) {
11316 // found at least two in a row, this is worth compressing
11317 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11319 dst->operand2 = delta;
11321 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11322 && (src->operand1 == delta) ) {
11333 dst->opcode = BIND_OPCODE_DONE;
11335 // optimize phase 3, use immediate encodings
11336 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11337 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11338 && (p->operand1 < (15*sizeof(pint_t)))
11339 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11340 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11341 p->operand1 = p->operand1/sizeof(pint_t);
11343 else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
11344 p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
11347 dst->opcode = BIND_OPCODE_DONE;
11349 // convert to compressed encoding
11350 const static bool log = false;
11351 fEncodedData.reserve(info.size()*2);
11353 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11354 switch ( it->opcode ) {
11355 case BIND_OPCODE_DONE:
11356 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11359 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11360 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11361 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11363 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11364 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11365 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11366 fEncodedData.append_uleb128(it->operand1);
11368 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11369 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11370 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11372 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11373 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11374 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11375 fEncodedData.append_string(it->name);
11377 case BIND_OPCODE_SET_TYPE_IMM:
11378 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11379 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11381 case BIND_OPCODE_SET_ADDEND_SLEB:
11382 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11383 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11384 fEncodedData.append_sleb128(it->operand1);
11386 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11387 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11388 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11389 fEncodedData.append_uleb128(it->operand2);
11391 case BIND_OPCODE_ADD_ADDR_ULEB:
11392 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11393 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11394 fEncodedData.append_uleb128(it->operand1);
11396 case BIND_OPCODE_DO_BIND:
11397 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11398 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11400 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11401 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11402 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11403 fEncodedData.append_uleb128(it->operand1);
11405 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11406 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11407 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11409 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11410 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11411 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11412 fEncodedData.append_uleb128(it->operand1);
11413 fEncodedData.append_uleb128(it->operand2);
11418 // align to pointer size
11419 fEncodedData.pad_to_size(sizeof(pint_t));
11421 if (log) fprintf(stderr, "total binding info size = %ld\n", fEncodedData.size());
11427 struct WeakBindingSorter
11429 bool operator()(const BindingInfo& left, const BindingInfo& right)
11431 // sort by symbol, type, address
11432 if ( left.fSymbolName != right.fSymbolName )
11433 return ( strcmp(left.fSymbolName, right.fSymbolName) < 0 );
11434 if ( left.fType != right.fType )
11435 return (left.fType < right.fType);
11436 return (left.fAddress < right.fAddress);
11442 template <typename A>
11443 void CompressedWeakBindingInfoLinkEditAtom<A>::encode()
11445 // add regular atoms that override a dylib's weak definitions
11446 for(std::set<const class ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
11447 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
11448 if ( fWriter.shouldExport(**it) )
11449 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, (*it)->getName(), true, 0, 0));
11452 // add all exported weak definitions
11453 for(std::vector<class ObjectFile::Atom*>::iterator it = fWriter.fAllAtoms->begin(); it != fWriter.fAllAtoms->end(); ++it) {
11454 ObjectFile::Atom* atom = *it;
11455 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) && fWriter.shouldExport(*atom) ) {
11456 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, atom->getName(), false, 0, 0));
11460 // sort by symbol, type, address
11461 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11462 std::vector<BindingInfo>& info = fWriter.fWeakBindingInfo;
11463 if ( info.size() == 0 )
11465 std::sort(info.begin(), info.end(), WeakBindingSorter());
11467 // convert to temp encoding that can be more easily optimized
11468 std::vector<binding_tmp> mid;
11469 mid.reserve(info.size());
11470 const SegmentInfo* currentSegment = NULL;
11471 unsigned int segIndex = 0;
11472 const char* symbolName = NULL;
11474 uint64_t address = (uint64_t)(-1);
11475 int64_t addend = 0;
11476 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11477 if ( symbolName != it->fSymbolName ) {
11478 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11479 symbolName = it->fSymbolName;
11481 if ( it->fType != 0 ) {
11482 if ( type != it->fType ) {
11483 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11486 if ( address != it->fAddress ) {
11487 // non weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
11488 // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
11489 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11490 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress) ) {
11492 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11493 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11494 currentSegment = *segit;
11499 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11502 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11504 address = it->fAddress;
11506 if ( addend != it->fAddend ) {
11507 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11508 addend = it->fAddend;
11510 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11511 address += sizeof(pint_t);
11514 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11517 // optimize phase 1, combine bind/add pairs
11518 binding_tmp* dst = &mid[0];
11519 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11520 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11521 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11522 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11523 dst->operand1 = src[1].operand1;
11531 dst->opcode = BIND_OPCODE_DONE;
11533 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11534 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11536 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11537 uint64_t delta = src->operand1;
11538 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11539 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11540 && (src[1].operand1 == delta) ) {
11541 // found at least two in a row, this is worth compressing
11542 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11544 dst->operand2 = delta;
11546 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11547 && (src->operand1 == delta) ) {
11558 dst->opcode = BIND_OPCODE_DONE;
11560 // optimize phase 3, use immediate encodings
11561 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11562 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11563 && (p->operand1 < (15*sizeof(pint_t)))
11564 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11565 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11566 p->operand1 = p->operand1/sizeof(pint_t);
11569 dst->opcode = BIND_OPCODE_DONE;
11572 // convert to compressed encoding
11573 const static bool log = false;
11574 fEncodedData.reserve(info.size()*2);
11576 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11577 switch ( it->opcode ) {
11578 case BIND_OPCODE_DONE:
11579 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11580 fEncodedData.append_byte(BIND_OPCODE_DONE);
11583 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11584 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11585 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11587 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11588 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11589 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11590 fEncodedData.append_uleb128(it->operand1);
11592 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11593 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11594 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11596 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11597 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11598 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11599 fEncodedData.append_string(it->name);
11601 case BIND_OPCODE_SET_TYPE_IMM:
11602 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11603 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11605 case BIND_OPCODE_SET_ADDEND_SLEB:
11606 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11607 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11608 fEncodedData.append_sleb128(it->operand1);
11610 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11611 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11612 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11613 fEncodedData.append_uleb128(it->operand2);
11615 case BIND_OPCODE_ADD_ADDR_ULEB:
11616 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11617 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11618 fEncodedData.append_uleb128(it->operand1);
11620 case BIND_OPCODE_DO_BIND:
11621 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11622 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11624 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11625 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11626 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11627 fEncodedData.append_uleb128(it->operand1);
11629 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11630 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11631 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11633 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11634 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11635 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11636 fEncodedData.append_uleb128(it->operand1);
11637 fEncodedData.append_uleb128(it->operand2);
11642 // align to pointer size
11643 fEncodedData.pad_to_size(sizeof(pint_t));
11645 if (log) fprintf(stderr, "total weak binding info size = %ld\n", fEncodedData.size());
11649 template <typename A>
11650 void CompressedLazyBindingInfoLinkEditAtom<A>::encode()
11652 // stream all lazy bindings and record start offsets
11653 const SegmentInfo* currentSegment = NULL;
11654 uint8_t segIndex = 0;
11655 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11656 std::vector<class LazyPointerAtom<A>*>& allLazys = fWriter.fAllSynthesizedLazyPointers;
11657 for (typename std::vector<class LazyPointerAtom<A>*>::iterator it = allLazys.begin(); it != allLazys.end(); ++it) {
11658 LazyPointerAtom<A>* lazyPointerAtom = *it;
11659 ObjectFile::Atom* lazyPointerTargetAtom = lazyPointerAtom->getTarget();
11661 // skip lazy pointers that are bound non-lazily because they are coalesced
11662 if ( ! fWriter.targetRequiresWeakBinding(*lazyPointerTargetAtom) ) {
11663 // record start offset for use by stub helper
11664 lazyPointerAtom->setLazyBindingInfoOffset(fEncodedData.size());
11666 // write address to bind
11667 pint_t address = lazyPointerAtom->getAddress();
11668 if ( (currentSegment == NULL) || (address < currentSegment->fBaseAddress)
11669 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= address) ) {
11671 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11672 if ( ((*segit)->fBaseAddress <= address) && (address < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11673 currentSegment = *segit;
11679 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
11680 fEncodedData.append_uleb128(lazyPointerAtom->getAddress() - currentSegment->fBaseAddress);
11683 int ordinal = fWriter.compressedOrdinalForImortedAtom(lazyPointerTargetAtom);
11684 if ( ordinal <= 0 ) {
11685 // special lookups are encoded as negative numbers in BindingInfo
11686 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (ordinal & BIND_IMMEDIATE_MASK) );
11688 else if ( ordinal <= 15 ) {
11689 // small ordinals are encoded in opcode
11690 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
11693 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11694 fEncodedData.append_uleb128(ordinal);
11696 // write symbol name
11697 bool weak_import = fWriter.fWeakImportMap[lazyPointerTargetAtom];
11699 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | BIND_SYMBOL_FLAGS_WEAK_IMPORT);
11701 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
11702 fEncodedData.append_string(lazyPointerTargetAtom->getName());
11704 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11705 fEncodedData.append_byte(BIND_OPCODE_DONE);
11708 // align to pointer size
11709 fEncodedData.pad_to_size(sizeof(pint_t));
11711 //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", fEncodedData.size(), allLazys.size());
11714 struct TrieEntriesSorter
11716 TrieEntriesSorter(Options& o) : fOptions(o) {}
11718 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
11720 unsigned int leftOrder;
11721 unsigned int rightOrder;
11722 fOptions.exportedSymbolOrder(left.name, &leftOrder);
11723 fOptions.exportedSymbolOrder(right.name, &rightOrder);
11724 if ( leftOrder != rightOrder )
11725 return (leftOrder < rightOrder);
11727 return (left.address < right.address);
11734 template <typename A>
11735 void CompressedExportInfoLinkEditAtom<A>::encode()
11737 // make vector of mach_o::trie::Entry for all exported symbols
11738 std::vector<class ObjectFile::Atom*>& exports = fWriter.fExportedAtoms;
11739 uint64_t imageBaseAddress = fWriter.fMachHeaderAtom->getAddress();
11740 std::vector<mach_o::trie::Entry> entries;
11741 entries.reserve(exports.size());
11742 for (std::vector<ObjectFile::Atom*>::iterator it = exports.begin(); it != exports.end(); ++it) {
11743 ObjectFile::Atom* atom = *it;
11744 uint64_t flags = 0;
11745 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
11746 flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
11747 uint64_t address = atom->getAddress() - imageBaseAddress;
11748 if ( atom->isThumb() )
11750 mach_o::trie::Entry entry;
11751 entry.name = atom->getName();
11752 entry.flags = flags;
11753 entry.address = address;
11754 entries.push_back(entry);
11757 // sort vector by -exported_symbols_order, and any others by address
11758 std::sort(entries.begin(), entries.end(), TrieEntriesSorter(fWriter.fOptions));
11761 mach_o::trie::makeTrie(entries, fEncodedData.bytes());
11763 // align to pointer size
11764 fEncodedData.pad_to_size(sizeof(pint_t));
11771 }; // namespace executable
11772 }; // namespace mach_o
11775 #endif // __EXECUTABLE_MACH_O__