1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2008 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"
52 // To implement architecture xxx, you must write template specializations for the following methods:
53 // MachHeaderAtom<xxx>::setHeaderInfo()
54 // ThreadsLoadCommandsAtom<xxx>::getSize()
55 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
56 // Writer<xxx>::addObjectRelocs()
57 // Writer<xxx>::fixUpReferenceRelocatable()
58 // Writer<xxx>::fixUpReferenceFinal()
59 // Writer<xxx>::stubableReference()
60 // Writer<xxx>::weakImportReferenceKind()
61 // Writer<xxx>::GOTReferenceKind()
66 namespace executable {
69 template <typename A> class WriterAtom;
70 template <typename A> class PageZeroAtom;
71 template <typename A> class CustomStackAtom;
72 template <typename A> class MachHeaderAtom;
73 template <typename A> class SegmentLoadCommandsAtom;
74 template <typename A> class EncryptionLoadCommandsAtom;
75 template <typename A> class SymbolTableLoadCommandsAtom;
76 template <typename A> class ThreadsLoadCommandsAtom;
77 template <typename A> class DylibIDLoadCommandsAtom;
78 template <typename A> class RoutinesLoadCommandsAtom;
79 template <typename A> class DyldLoadCommandsAtom;
80 template <typename A> class UUIDLoadCommandAtom;
81 template <typename A> class LinkEditAtom;
82 template <typename A> class SectionRelocationsLinkEditAtom;
83 template <typename A> class LocalRelocationsLinkEditAtom;
84 template <typename A> class ExternalRelocationsLinkEditAtom;
85 template <typename A> class SymbolTableLinkEditAtom;
86 template <typename A> class SegmentSplitInfoLoadCommandsAtom;
87 template <typename A> class SegmentSplitInfoContentAtom;
88 template <typename A> class IndirectTableLinkEditAtom;
89 template <typename A> class ModuleInfoLinkEditAtom;
90 template <typename A> class StringsLinkEditAtom;
91 template <typename A> class LoadCommandsPaddingAtom;
92 template <typename A> class StubAtom;
93 template <typename A> class StubHelperAtom;
94 template <typename A> class LazyPointerAtom;
95 template <typename A> class NonLazyPointerAtom;
96 template <typename A> class DylibLoadCommandsAtom;
99 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
100 class SectionInfo : public ObjectFile::Section {
102 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0),
103 fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false),
104 fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false),
105 fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false),
106 fHasTextLocalRelocs(false), fHasTextExternalRelocs(false)
107 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
108 void setIndex(unsigned int index) { fIndex=index; }
109 std::vector<ObjectFile::Atom*> fAtoms;
110 char fSegmentName[20];
111 char fSectionName[20];
112 uint64_t fFileOffset;
114 uint32_t fRelocCount;
115 uint32_t fRelocOffset;
116 uint32_t fIndirectSymbolOffset;
118 bool fAllLazyPointers;
119 bool fAllLazyDylibPointers;
120 bool fAllNonLazyPointers;
122 bool fAllSelfModifyingStubs;
124 bool fVirtualSection;
125 bool fHasTextLocalRelocs;
126 bool fHasTextExternalRelocs;
129 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
133 SegmentInfo() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
134 fBaseAddress(0), fSize(0), fFixedAddress(false),
135 fIndependentAddress(false) { fName[0] = '\0'; }
136 std::vector<class SectionInfo*> fSections;
138 uint32_t fInitProtection;
139 uint32_t fMaxProtection;
140 uint64_t fFileOffset;
142 uint64_t fBaseAddress;
145 bool fIndependentAddress;
148 template <typename A>
149 class Writer : public ExecutableFile::Writer
152 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
155 virtual const char* getPath() { return fFilePath; }
156 virtual time_t getModificationTime() { return 0; }
157 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
158 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
159 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
160 virtual std::vector<Stab>* getStabs() { return NULL; }
162 virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint,
163 bool objcReplacementClasses);
164 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
165 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
166 std::vector<class ObjectFile::Reader::Stab>& stabs,
167 class ObjectFile::Atom* entryPointAtom,
168 class ObjectFile::Atom* dyldHelperAtom,
169 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
170 bool createUUID, bool canScatter,
171 ObjectFile::Reader::CpuConstraint cpuConstraint,
172 bool biggerThanTwoGigs, bool overridesDylibWeakDefines);
175 typedef typename A::P P;
176 typedef typename A::P::uint_t pint_t;
178 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
180 void assignFileOffsets();
181 void synthesizeStubs();
182 void insertDummyStubs();
183 void partitionIntoSections();
184 bool addBranchIslands();
185 bool addPPCBranchIslands();
186 bool isBranch24Reference(uint8_t kind);
187 void adjustLoadCommandsAndPadding();
188 void createDynamicLinkerCommand();
189 void createDylibCommands();
190 void buildLinkEdit();
191 const char* getArchString();
193 uint64_t writeAtoms();
194 void writeNoOps(int fd, uint32_t from, uint32_t to);
195 void copyNoOps(uint8_t* from, uint8_t* to);
196 bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
197 void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
198 void collectExportedAndImportedAndLocalAtoms();
199 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
200 void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
201 void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
202 void buildSymbolTable();
203 const char* symbolTableName(const ObjectFile::Atom* atom);
204 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
205 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
206 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
207 void copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
208 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
209 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
210 bool shouldExport(const ObjectFile::Atom& atom) const;
212 void adjustLinkEditSections();
213 void buildObjectFileFixups();
214 void buildExecutableFixups();
215 bool preboundLazyPointerType(uint8_t* type);
216 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
217 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
218 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
219 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
220 uint8_t buffer[], bool finalLinkedImage) const;
221 uint32_t symbolIndex(ObjectFile::Atom& atom);
222 bool makesExternalRelocatableReference(ObjectFile::Atom& target) const;
223 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
224 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
225 uint8_t getRelocPointerSize();
226 uint64_t maxAddress();
227 bool stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref);
228 bool GOTReferenceKind(uint8_t kind);
229 bool optimizableGOTReferenceKind(uint8_t kind);
230 bool weakImportReferenceKind(uint8_t kind);
231 unsigned int collectStabs();
232 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
233 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
234 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
235 void addStabs(uint32_t startIndex);
236 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
237 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
238 bool generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
239 bool generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
240 bool mightNeedPadSegment();
241 void scanForAbsoluteReferences();
242 bool needsModuleTable();
243 void optimizeDylibReferences();
244 bool indirectSymbolIsLocal(const ObjectFile::Reference* ref) const;
246 struct DirectLibrary {
247 class ObjectFile::Reader* fLibrary;
252 friend class WriterAtom<A>;
253 friend class PageZeroAtom<A>;
254 friend class CustomStackAtom<A>;
255 friend class MachHeaderAtom<A>;
256 friend class SegmentLoadCommandsAtom<A>;
257 friend class EncryptionLoadCommandsAtom<A>;
258 friend class SymbolTableLoadCommandsAtom<A>;
259 friend class ThreadsLoadCommandsAtom<A>;
260 friend class DylibIDLoadCommandsAtom<A>;
261 friend class RoutinesLoadCommandsAtom<A>;
262 friend class DyldLoadCommandsAtom<A>;
263 friend class UUIDLoadCommandAtom<A>;
264 friend class LinkEditAtom<A>;
265 friend class SectionRelocationsLinkEditAtom<A>;
266 friend class LocalRelocationsLinkEditAtom<A>;
267 friend class ExternalRelocationsLinkEditAtom<A>;
268 friend class SymbolTableLinkEditAtom<A>;
269 friend class SegmentSplitInfoLoadCommandsAtom<A>;
270 friend class SegmentSplitInfoContentAtom<A>;
271 // friend class IndirectTableLinkEditAtom<A>;
272 friend class ModuleInfoLinkEditAtom<A>;
273 friend class StringsLinkEditAtom<A>;
274 friend class LoadCommandsPaddingAtom<A>;
275 friend class StubAtom<A>;
276 friend class StubHelperAtom<A>;
277 friend class LazyPointerAtom<A>;
278 friend class NonLazyPointerAtom<A>;
279 friend class DylibLoadCommandsAtom<A>;
281 const char* fFilePath;
283 std::vector<class ObjectFile::Atom*>* fAllAtoms;
284 std::vector<class ObjectFile::Reader::Stab>* fStabs;
285 class SectionInfo* fLoadCommandsSection;
286 class SegmentInfo* fLoadCommandsSegment;
287 class EncryptionLoadCommandsAtom<A>* fEncryptionLoadCommand;
288 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
289 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
290 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
291 class UUIDLoadCommandAtom<A>* fUUIDAtom;
292 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
293 std::vector<SegmentInfo*> fSegmentInfos;
294 class SegmentInfo* fPadSegmentInfo;
295 class ObjectFile::Atom* fEntryPoint;
296 class ObjectFile::Atom* fDyldHelper;
297 class ObjectFile::Atom* fDyldLazyDylibHelper;
298 std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*> fLibraryToLoadCommand;
299 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
300 std::map<class ObjectFile::Reader*, class ObjectFile::Reader*> fLibraryAliases;
301 std::vector<class ObjectFile::Atom*> fExportedAtoms;
302 std::vector<class ObjectFile::Atom*> fImportedAtoms;
303 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
304 std::vector<macho_nlist<P> > fLocalExtraLabels;
305 std::vector<macho_nlist<P> > fGlobalExtraLabels;
306 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
307 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
308 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
309 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
310 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
311 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
312 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
313 class StringsLinkEditAtom<A>* fStringsAtom;
314 class PageZeroAtom<A>* fPageZeroAtom;
315 macho_nlist<P>* fSymbolTable;
316 std::vector<macho_relocation_info<P> > fSectionRelocs;
317 std::vector<macho_relocation_info<P> > fInternalRelocs;
318 std::vector<macho_relocation_info<P> > fExternalRelocs;
319 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
320 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
321 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
322 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
323 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
324 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyDylibPointers;
325 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
326 uint32_t fSymbolTableCount;
327 uint32_t fSymbolTableStabsCount;
328 uint32_t fSymbolTableStabsStartIndex;
329 uint32_t fSymbolTableLocalCount;
330 uint32_t fSymbolTableLocalStartIndex;
331 uint32_t fSymbolTableExportCount;
332 uint32_t fSymbolTableExportStartIndex;
333 uint32_t fSymbolTableImportCount;
334 uint32_t fSymbolTableImportStartIndex;
335 uint32_t fLargestAtomSize;
336 bool fEmitVirtualSections;
337 bool fHasWeakExports;
338 bool fReferencesWeakImports;
340 bool fWritableSegmentPastFirst4GB;
341 bool fNoReExportedDylibs;
342 bool fBiggerThanTwoGigs;
344 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
345 std::set<const ObjectFile::Reader*> fDylibReadersWithNonWeakImports;
346 std::set<const ObjectFile::Reader*> fDylibReadersWithWeakImports;
347 SegmentInfo* fFirstWritableSegment;
348 ObjectFile::Reader::CpuConstraint fCpuConstraint;
349 uint32_t fAnonNameIndex;
353 class Segment : public ObjectFile::Segment
356 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
357 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
358 virtual const char* getName() const { return fName; }
359 virtual bool isContentReadable() const { return fReadable; }
360 virtual bool isContentWritable() const { return fWritable; }
361 virtual bool isContentExecutable() const { return fExecutable; }
362 virtual bool hasFixedAddress() const { return fFixedAddress; }
364 static Segment fgTextSegment;
365 static Segment fgPageZeroSegment;
366 static Segment fgLinkEditSegment;
367 static Segment fgStackSegment;
368 static Segment fgImportSegment;
369 static Segment fgROImportSegment;
370 static Segment fgDataSegment;
371 static Segment fgObjCSegment;
376 const bool fReadable;
377 const bool fWritable;
378 const bool fExecutable;
379 const bool fFixedAddress;
382 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
383 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
384 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
385 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
386 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
387 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
388 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
389 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
392 template <typename A>
393 class WriterAtom : public ObjectFile::Atom
396 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
397 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
399 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
400 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
401 virtual const char* getName() const { return NULL; }
402 virtual const char* getDisplayName() const { return this->getName(); }
403 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
404 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
405 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
406 virtual bool dontDeadStrip() const { return true; }
407 virtual bool isZeroFill() const { return false; }
408 virtual bool isThumb() const { return false; }
409 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
410 virtual bool mustRemainInSection() const { return true; }
411 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
412 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
413 virtual uint32_t getOrdinal() const { return 0; }
414 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
415 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
416 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
417 virtual void setScope(Scope) { }
421 virtual ~WriterAtom() {}
422 typedef typename A::P P;
423 typedef typename A::P::E E;
425 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
431 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
434 template <typename A>
435 class PageZeroAtom : public WriterAtom<A>
438 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
439 fSize(fWriter.fOptions.zeroPageSize()) {}
440 virtual const char* getDisplayName() const { return "page zero content"; }
441 virtual bool isZeroFill() const { return true; }
442 virtual uint64_t getSize() const { return fSize; }
443 virtual const char* getSectionName() const { return "._zeropage"; }
444 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
445 void setSize(uint64_t size) { fSize = size; }
447 using WriterAtom<A>::fWriter;
448 typedef typename A::P P;
453 template <typename A>
454 class DsoHandleAtom : public WriterAtom<A>
457 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
458 virtual const char* getName() const { return "___dso_handle"; }
459 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
460 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
461 virtual uint64_t getSize() const { return 0; }
462 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
463 virtual const char* getSectionName() const { return "._mach_header"; }
464 virtual void copyRawContent(uint8_t buffer[]) const {}
468 template <typename A>
469 class MachHeaderAtom : public WriterAtom<A>
472 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
473 virtual const char* getName() const;
474 virtual const char* getDisplayName() const;
475 virtual ObjectFile::Atom::Scope getScope() const;
476 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
477 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
478 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
479 virtual const char* getSectionName() const { return "._mach_header"; }
480 virtual uint32_t getOrdinal() const { return 1; }
481 virtual void copyRawContent(uint8_t buffer[]) const;
483 using WriterAtom<A>::fWriter;
484 typedef typename A::P P;
485 void setHeaderInfo(macho_header<typename A::P>& header) const;
488 template <typename A>
489 class CustomStackAtom : public WriterAtom<A>
492 CustomStackAtom(Writer<A>& writer);
493 virtual const char* getDisplayName() const { return "custom stack content"; }
494 virtual bool isZeroFill() const { return true; }
495 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
496 virtual const char* getSectionName() const { return "._stack"; }
497 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
499 using WriterAtom<A>::fWriter;
500 typedef typename A::P P;
501 static bool stackGrowsDown();
504 template <typename A>
505 class LoadCommandAtom : public WriterAtom<A>
508 LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment), fOrdinal(fgCurrentOrdinal++) {}
509 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
510 virtual const char* getSectionName() const { return "._load_commands"; }
511 virtual uint32_t getOrdinal() const { return fOrdinal; }
512 static uint64_t alignedSize(uint64_t size);
515 static uint32_t fgCurrentOrdinal;
518 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
520 template <typename A>
521 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
524 SegmentLoadCommandsAtom(Writer<A>& writer)
525 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0)
526 { writer.fSegmentCommands = this; }
527 virtual const char* getDisplayName() const { return "segment load commands"; }
528 virtual uint64_t getSize() const { return fSize; }
529 virtual void copyRawContent(uint8_t buffer[]) const;
533 unsigned int commandCount() { return fCommandCount; }
535 using WriterAtom<A>::fWriter;
536 typedef typename A::P P;
537 unsigned int fCommandCount;
542 template <typename A>
543 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
546 SymbolTableLoadCommandsAtom(Writer<A>&);
547 virtual const char* getDisplayName() const { return "symbol table load commands"; }
548 virtual uint64_t getSize() const;
549 virtual void copyRawContent(uint8_t buffer[]) const;
550 unsigned int commandCount();
551 void needDynamicTable();
553 using WriterAtom<A>::fWriter;
554 typedef typename A::P P;
555 bool fNeedsDynamicSymbolTable;
556 macho_symtab_command<typename A::P> fSymbolTable;
557 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
560 template <typename A>
561 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
564 ThreadsLoadCommandsAtom(Writer<A>& writer)
565 : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
566 virtual const char* getDisplayName() const { return "thread load commands"; }
567 virtual uint64_t getSize() const;
568 virtual void copyRawContent(uint8_t buffer[]) const;
570 using WriterAtom<A>::fWriter;
571 typedef typename A::P P;
573 uint32_t fBufferSize;
576 template <typename A>
577 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
580 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
581 virtual const char* getDisplayName() const { return "dyld load command"; }
582 virtual uint64_t getSize() const;
583 virtual void copyRawContent(uint8_t buffer[]) const;
585 using WriterAtom<A>::fWriter;
586 typedef typename A::P P;
589 template <typename A>
590 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
593 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
594 virtual const char* getDisplayName() const { return "segment split info load command"; }
595 virtual uint64_t getSize() const;
596 virtual void copyRawContent(uint8_t buffer[]) const;
598 using WriterAtom<A>::fWriter;
599 typedef typename A::P P;
602 template <typename A>
603 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
606 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
607 LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
608 virtual const char* getDisplayName() const { return "allowable_client load command"; }
609 virtual uint64_t getSize() const;
610 virtual void copyRawContent(uint8_t buffer[]) const;
612 using WriterAtom<A>::fWriter;
613 typedef typename A::P P;
614 const char* clientString;
617 template <typename A>
618 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
621 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
622 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info),
623 fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
624 virtual const char* getDisplayName() const { return "dylib load command"; }
625 virtual uint64_t getSize() const;
626 virtual void copyRawContent(uint8_t buffer[]) const;
627 virtual void optimizeAway() { fOptimizedAway = true; }
628 bool linkedWeak() { return fInfo.options.fWeakImport; }
630 using WriterAtom<A>::fWriter;
631 typedef typename A::P P;
632 ExecutableFile::DyLibUsed fInfo;
636 template <typename A>
637 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
640 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
641 virtual const char* getDisplayName() const { return "dylib ID load command"; }
642 virtual uint64_t getSize() const;
643 virtual void copyRawContent(uint8_t buffer[]) const;
645 using WriterAtom<A>::fWriter;
646 typedef typename A::P P;
649 template <typename A>
650 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
653 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
654 virtual const char* getDisplayName() const { return "routines load command"; }
655 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
656 virtual void copyRawContent(uint8_t buffer[]) const;
658 using WriterAtom<A>::fWriter;
659 typedef typename A::P P;
662 template <typename A>
663 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
666 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
667 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
668 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
669 virtual uint64_t getSize() const;
670 virtual void copyRawContent(uint8_t buffer[]) const;
672 typedef typename A::P P;
676 template <typename A>
677 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
680 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
681 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
682 virtual const char* getDisplayName() const { return "sub-library load command"; }
683 virtual uint64_t getSize() const;
684 virtual void copyRawContent(uint8_t buffer[]) const;
686 using WriterAtom<A>::fWriter;
687 typedef typename A::P P;
688 const char* fNameStart;
692 template <typename A>
693 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
696 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
697 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
698 virtual const char* getDisplayName() const { return "umbrella load command"; }
699 virtual uint64_t getSize() const;
700 virtual void copyRawContent(uint8_t buffer[]) const;
702 using WriterAtom<A>::fWriter;
703 typedef typename A::P P;
707 template <typename A>
708 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
711 UUIDLoadCommandAtom(Writer<A>& writer)
712 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) {}
713 virtual const char* getDisplayName() const { return "uuid load command"; }
714 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
715 virtual void copyRawContent(uint8_t buffer[]) const;
716 virtual void generate();
717 void setContent(const uint8_t uuid[16]);
718 const uint8_t* getUUID() { return fUUID; }
720 using WriterAtom<A>::fWriter;
721 typedef typename A::P P;
727 template <typename A>
728 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
731 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
732 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fPath(path) {}
733 virtual const char* getDisplayName() const { return "rpath load command"; }
734 virtual uint64_t getSize() const;
735 virtual void copyRawContent(uint8_t buffer[]) const;
737 using WriterAtom<A>::fWriter;
738 typedef typename A::P P;
742 template <typename A>
743 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
746 EncryptionLoadCommandsAtom(Writer<A>& writer)
747 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fStartOffset(0),
749 virtual const char* getDisplayName() const { return "encryption info load command"; }
750 virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
751 virtual void copyRawContent(uint8_t buffer[]) const;
752 void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
753 void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
755 using WriterAtom<A>::fWriter;
756 typedef typename A::P P;
757 uint32_t fStartOffset;
761 template <typename A>
762 class LoadCommandsPaddingAtom : public WriterAtom<A>
765 LoadCommandsPaddingAtom(Writer<A>& writer)
766 : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
767 virtual const char* getDisplayName() const { return "header padding"; }
768 virtual uint64_t getSize() const { return fSize; }
769 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
770 virtual void copyRawContent(uint8_t buffer[]) const;
772 void setSize(uint64_t newSize);
774 using WriterAtom<A>::fWriter;
775 typedef typename A::P P;
779 template <typename A>
780 class LinkEditAtom : public WriterAtom<A>
783 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
784 uint64_t getFileOffset() const;
785 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
786 virtual uint32_t getOrdinal() const { return fOrdinal; }
789 static uint32_t fgCurrentOrdinal;
791 typedef typename A::P P;
794 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
796 template <typename A>
797 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
800 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
801 virtual const char* getDisplayName() const { return "section relocations"; }
802 virtual uint64_t getSize() const;
803 virtual const char* getSectionName() const { return "._section_relocs"; }
804 virtual void copyRawContent(uint8_t buffer[]) const;
806 using WriterAtom<A>::fWriter;
807 typedef typename A::P P;
810 template <typename A>
811 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
814 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
815 virtual const char* getDisplayName() const { return "local relocations"; }
816 virtual uint64_t getSize() const;
817 virtual const char* getSectionName() const { return "._local_relocs"; }
818 virtual void copyRawContent(uint8_t buffer[]) const;
820 using WriterAtom<A>::fWriter;
821 typedef typename A::P P;
824 template <typename A>
825 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
828 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
829 virtual const char* getDisplayName() const { return "symbol table"; }
830 virtual uint64_t getSize() const;
831 virtual const char* getSectionName() const { return "._symbol_table"; }
832 virtual void copyRawContent(uint8_t buffer[]) const;
834 using WriterAtom<A>::fWriter;
835 typedef typename A::P P;
838 template <typename A>
839 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
842 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
843 virtual const char* getDisplayName() const { return "external relocations"; }
844 virtual uint64_t getSize() const;
845 virtual const char* getSectionName() const { return "._extern_relocs"; }
846 virtual void copyRawContent(uint8_t buffer[]) const;
848 using WriterAtom<A>::fWriter;
849 typedef typename A::P P;
852 struct IndirectEntry {
853 uint32_t indirectIndex;
854 uint32_t symbolIndex;
858 template <typename A>
859 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
862 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
863 virtual const char* getDisplayName() const { return "split segment info"; }
864 virtual uint64_t getSize() const;
865 virtual const char* getSectionName() const { return "._split_info"; }
866 virtual void copyRawContent(uint8_t buffer[]) const;
867 bool canEncode() { return !fCantEncode; }
868 void setCantEncode() { fCantEncode = true; }
869 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
870 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
871 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
872 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
876 using WriterAtom<A>::fWriter;
877 typedef typename A::P P;
878 typedef typename A::P::uint_t pint_t;
879 struct AtomAndOffset {
880 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
881 const ObjectFile::Atom* atom;
884 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
886 std::vector<AtomAndOffset> fKind1Locations;
887 std::vector<AtomAndOffset> fKind2Locations;
888 std::vector<AtomAndOffset> fKind3Locations;
889 std::vector<AtomAndOffset> fKind4Locations;
890 std::vector<uint8_t> fEncodedData;
894 template <typename A>
895 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
898 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
899 virtual const char* getDisplayName() const { return "indirect symbol table"; }
900 virtual uint64_t getSize() const;
901 virtual const char* getSectionName() const { return "._indirect_syms"; }
902 virtual void copyRawContent(uint8_t buffer[]) const;
904 std::vector<IndirectEntry> fTable;
907 using WriterAtom<A>::fWriter;
908 typedef typename A::P P;
911 template <typename A>
912 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
915 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
916 virtual const char* getDisplayName() const { return "module table"; }
917 virtual uint64_t getSize() const;
918 virtual const char* getSectionName() const { return "._module_info"; }
919 virtual void copyRawContent(uint8_t buffer[]) const;
921 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
922 uint32_t getTableOfContentsFileOffset() const;
923 uint32_t getModuleTableFileOffset() const;
924 uint32_t getReferencesFileOffset() const;
925 uint32_t getReferencesCount() const;
928 using WriterAtom<A>::fWriter;
929 typedef typename A::P P;
930 uint32_t fModuleNameOffset;
937 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
940 template <typename A>
941 class StringsLinkEditAtom : public LinkEditAtom<A>
944 StringsLinkEditAtom(Writer<A>& writer);
945 virtual const char* getDisplayName() const { return "string pool"; }
946 virtual uint64_t getSize() const;
947 virtual const char* getSectionName() const { return "._string_pool"; }
948 virtual void copyRawContent(uint8_t buffer[]) const;
950 int32_t add(const char* name);
951 int32_t addUnique(const char* name);
952 int32_t emptyString() { return 1; }
953 const char* stringForIndex(int32_t) const;
956 using WriterAtom<A>::fWriter;
957 typedef typename A::P P;
958 enum { kBufferSize = 0x01000000 };
959 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
961 std::vector<char*> fFullBuffers;
962 char* fCurrentBuffer;
963 uint32_t fCurrentBufferUsed;
964 StringToOffset fUniqueStrings;
969 template <typename A>
970 class UndefinedSymbolProxyAtom : public WriterAtom<A>
973 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
974 virtual const char* getName() const { return fName; }
975 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
976 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
977 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
978 virtual uint64_t getSize() const { return 0; }
979 virtual const char* getSectionName() const { return "._imports"; }
981 using WriterAtom<A>::fWriter;
982 typedef typename A::P P;
986 template <typename A>
987 class BranchIslandAtom : public WriterAtom<A>
990 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
991 virtual const char* getName() const { return fName; }
992 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
993 virtual uint64_t getSize() const;
994 virtual const char* getSectionName() const { return "__text"; }
995 virtual void copyRawContent(uint8_t buffer[]) const;
997 using WriterAtom<A>::fWriter;
999 ObjectFile::Atom& fTarget;
1000 uint32_t fTargetOffset;
1003 template <typename A>
1004 class StubAtom : public WriterAtom<A>
1007 StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
1008 virtual const char* getName() const { return fName; }
1009 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1010 virtual uint64_t getSize() const;
1011 virtual ObjectFile::Alignment getAlignment() const;
1012 virtual const char* getSectionName() const { return "__symbol_stub1"; }
1013 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1014 virtual void copyRawContent(uint8_t buffer[]) const;
1015 ObjectFile::Atom* getTarget() { return &fTarget; }
1017 static const char* stubName(const char* importName);
1018 bool pic() const { return fWriter.fSlideable; }
1019 using WriterAtom<A>::fWriter;
1021 ObjectFile::Atom& fTarget;
1022 std::vector<ObjectFile::Reference*> fReferences;
1026 template <typename A>
1027 class StubHelperAtom : public WriterAtom<A>
1030 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer, bool forLazyDylib);
1031 virtual const char* getName() const { return fName; }
1032 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1033 virtual uint64_t getSize() const;
1034 virtual const char* getSectionName() const { return "__stub_helper"; }
1035 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1036 virtual void copyRawContent(uint8_t buffer[]) const;
1037 ObjectFile::Atom* getTarget() { return &fTarget; }
1039 static const char* stubName(const char* importName);
1040 using WriterAtom<A>::fWriter;
1042 ObjectFile::Atom& fTarget;
1043 std::vector<ObjectFile::Reference*> fReferences;
1046 template <typename A>
1047 class LazyPointerAtom : public WriterAtom<A>
1050 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target,
1051 StubAtom<A>& stub, bool forLazyDylib);
1052 virtual const char* getName() const { return fName; }
1053 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1054 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1055 virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; }
1056 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1057 virtual void copyRawContent(uint8_t buffer[]) const;
1058 ObjectFile::Atom* getTarget() { return &fExternalTarget; }
1060 using WriterAtom<A>::fWriter;
1061 static const char* lazyPointerName(const char* importName);
1063 ObjectFile::Atom& fTarget;
1064 ObjectFile::Atom& fExternalTarget;
1065 std::vector<ObjectFile::Reference*> fReferences;
1070 template <typename A>
1071 class NonLazyPointerAtom : public WriterAtom<A>
1074 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1075 virtual const char* getName() const { return fName; }
1076 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1077 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1078 virtual const char* getSectionName() const { return "__nl_symbol_ptr"; }
1079 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1080 virtual void copyRawContent(uint8_t buffer[]) const;
1081 ObjectFile::Atom* getTarget() { return &fTarget; }
1083 using WriterAtom<A>::fWriter;
1084 static const char* nonlazyPointerName(const char* importName);
1086 ObjectFile::Atom& fTarget;
1087 std::vector<ObjectFile::Reference*> fReferences;
1091 template <typename A>
1092 class ObjCInfoAtom : public WriterAtom<A>
1095 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1096 bool objcReplacementClasses);
1097 virtual const char* getName() const { return "objc$info"; }
1098 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1099 virtual uint64_t getSize() const { return 8; }
1100 virtual const char* getSectionName() const;
1101 virtual void copyRawContent(uint8_t buffer[]) const;
1103 Segment& getInfoSegment() const;
1104 uint32_t fContent[2];
1108 template <typename A>
1109 class WriterReference : public ObjectFile::Reference
1112 typedef typename A::ReferenceKinds Kinds;
1114 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1115 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1116 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target),
1117 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1119 virtual ~WriterReference() {}
1121 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return ObjectFile::Reference::kBoundDirectly; }
1122 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1123 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1124 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1125 virtual const char* getTargetName() const { return fTarget->getName(); }
1126 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1127 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1128 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1129 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1130 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = ⌖ fTargetOffset = offset; }
1131 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ }
1132 virtual void setFromTargetName(const char* name) { }
1133 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1134 virtual const char* getDescription() const { return "writer reference"; }
1135 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1139 uint32_t fFixUpOffsetInSrc;
1140 ObjectFile::Atom* fTarget;
1141 uint32_t fTargetOffset;
1142 ObjectFile::Atom* fFromTarget;
1143 uint32_t fFromTargetOffset;
1149 StubHelperAtom<x86_64>::StubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1150 ObjectFile::Atom& lazyPointer, bool forLazyDylib)
1151 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1153 writer.fAllSynthesizedStubHelpers.push_back(this);
1155 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &lazyPointer));
1156 if ( forLazyDylib ) {
1157 if ( writer.fDyldLazyDylibHelper == NULL )
1158 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1159 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldLazyDylibHelper));
1162 if ( writer.fDyldHelper == NULL )
1163 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1164 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldHelper));
1169 uint64_t StubHelperAtom<x86_64>::getSize() const
1175 void StubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1177 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1184 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1192 template <typename A>
1193 const char* StubHelperAtom<A>::stubName(const char* name)
1196 asprintf(&buf, "%s$stubHelper", name);
1201 // specialize lazy pointer for x86_64 to initially pointer to stub helper
1203 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
1204 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
1205 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
1208 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
1210 writer.fAllSynthesizedLazyPointers.push_back(this);
1212 StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
1213 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
1216 // specialize lazy pointer for x86 to initially pointer to second half of stub
1218 LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
1219 : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
1220 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
1223 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
1225 writer.fAllSynthesizedLazyPointers.push_back(this);
1227 // helper part of stub is 14 or 6 bytes into stub
1228 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, &stub, writer.fSlideable ? 14 : 6));
1231 template <typename A>
1232 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
1233 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
1234 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
1237 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
1239 writer.fAllSynthesizedLazyPointers.push_back(this);
1241 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
1246 template <typename A>
1247 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
1250 asprintf(&buf, "%s$lazy_pointer", name);
1254 template <typename A>
1255 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
1257 bzero(buffer, getSize());
1261 template <typename A>
1262 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
1263 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
1265 writer.fAllSynthesizedNonLazyPointers.push_back(this);
1267 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
1270 template <typename A>
1271 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
1274 asprintf(&buf, "%s$non_lazy_pointer", name);
1278 template <typename A>
1279 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
1281 bzero(buffer, getSize());
1287 bool StubAtom<ppc64>::pic() const
1289 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
1290 // Usually that only happens if page zero is very large
1291 return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
1296 bool StubAtom<arm>::pic() const
1298 return fWriter.fSlideable;
1302 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
1308 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
1314 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
1320 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1321 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1322 fTarget(target), fForLazyDylib(forLazyDylib)
1324 writer.fAllSynthesizedStubs.push_back(this);
1325 LazyPointerAtom<ppc>* lp;
1326 if ( fWriter.fOptions.prebind() ) {
1327 // for prebound ppc, lazy pointer starts out pointing to target symbol's address
1328 // if target is a weak definition within this linkage unit or zero if in some dylib
1329 lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
1332 // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
1333 if ( forLazyDylib ) {
1334 if ( writer.fDyldLazyDylibHelper == NULL )
1335 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1336 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
1339 if ( writer.fDyldHelper == NULL )
1340 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1341 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldHelper, *this, forLazyDylib);
1345 // picbase is 8 bytes into atom
1346 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
1347 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
1350 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
1351 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
1356 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1357 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1358 fTarget(target), fForLazyDylib(forLazyDylib)
1360 writer.fAllSynthesizedStubs.push_back(this);
1362 LazyPointerAtom<ppc64>* lp;
1363 if ( forLazyDylib ) {
1364 if ( writer.fDyldLazyDylibHelper == NULL )
1365 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1366 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
1369 if ( writer.fDyldHelper == NULL )
1370 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1371 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldHelper, *this, forLazyDylib);
1374 // picbase is 8 bytes into atom
1375 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
1376 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
1379 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
1380 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
1384 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
1386 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1387 : WriterAtom<x86>(writer, (writer.fOptions.slowx86Stubs() || forLazyDylib) ? Segment::fgTextSegment :
1388 ( writer.fOptions.readOnlyx86Stubs() ? Segment::fgROImportSegment : Segment::fgImportSegment)),
1389 fTarget(target), fForLazyDylib(forLazyDylib)
1391 if ( writer.fOptions.slowx86Stubs() || forLazyDylib ) {
1392 fName = stubName(target.getName());
1393 writer.fAllSynthesizedStubs.push_back(this);
1394 LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
1395 ObjectFile::Atom* helper;
1396 if ( forLazyDylib ) {
1397 if ( writer.fDyldLazyDylibHelper == NULL )
1398 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1399 helper = writer.fDyldLazyDylibHelper;
1402 if ( writer.fDyldHelper == NULL )
1403 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1404 helper = writer.fDyldHelper;
1407 // picbase is 5 bytes into atom
1408 fReferences.push_back(new WriterReference<x86>(8, x86::kPointerDiff, lp, 0, this, 5));
1409 fReferences.push_back(new WriterReference<x86>(16, x86::kPCRel32, helper));
1412 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
1413 fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, lp));
1414 fReferences.push_back(new WriterReference<x86>(12, x86::kPCRel32, helper));
1418 if ( &target == NULL )
1419 fName = "cache-line-crossing-stub";
1421 fName = stubName(target.getName());
1422 writer.fAllSynthesizedStubs.push_back(this);
1428 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1429 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1431 writer.fAllSynthesizedStubs.push_back(this);
1433 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
1434 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
1438 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1439 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1441 writer.fAllSynthesizedStubs.push_back(this);
1443 LazyPointerAtom<arm>* lp;
1444 if ( fWriter.fOptions.prebind() && !forLazyDylib ) {
1445 // for prebound arm, lazy pointer starts out pointing to target symbol's address
1446 // if target is a weak definition within this linkage unit or zero if in some dylib
1447 lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
1450 // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
1451 ObjectFile::Atom* helper;
1452 if ( forLazyDylib ) {
1453 if ( writer.fDyldLazyDylibHelper == NULL )
1454 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1455 helper = writer.fDyldLazyDylibHelper;
1458 if ( writer.fDyldHelper == NULL )
1459 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1460 helper = writer.fDyldHelper;
1462 lp = new LazyPointerAtom<arm>(writer, *helper, *this, forLazyDylib);
1465 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
1467 fReferences.push_back(new WriterReference<arm>(8, arm::kPointer, lp));
1470 template <typename A>
1471 const char* StubAtom<A>::stubName(const char* name)
1474 asprintf(&buf, "%s$stub", name);
1479 uint64_t StubAtom<ppc>::getSize() const
1481 return ( pic() ? 32 : 16 );
1485 uint64_t StubAtom<ppc64>::getSize() const
1487 return ( pic() ? 32 : 16 );
1492 uint64_t StubAtom<arm>::getSize() const
1494 return ( pic() ? 16 : 12 );
1498 uint64_t StubAtom<x86>::getSize() const
1500 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
1510 uint64_t StubAtom<x86_64>::getSize() const
1516 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
1518 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib )
1521 return 0; // special case x86 fast stubs to be byte aligned
1525 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
1528 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
1529 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
1530 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
1531 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
1532 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
1533 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
1534 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
1535 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
1538 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
1539 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
1540 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
1541 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
1546 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
1549 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
1550 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
1551 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
1552 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
1553 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
1554 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
1555 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
1556 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
1559 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
1560 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
1561 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
1562 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
1567 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
1569 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
1571 buffer[0] = 0xE8; // call picbase
1576 buffer[5] = 0x58; // pop eax
1577 buffer[6] = 0x8D; // lea foo$lazy_pointer-picbase(eax),eax
1583 buffer[12] = 0xFF; // jmp *(eax)
1585 buffer[14] = 0x50; // push eax
1586 buffer[15] = 0xE9; // jump dyld_stub_binding_helper
1593 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
1599 buffer[6] = 0x68; // pushl $foo$lazy_pointer
1604 buffer[11] = 0xE9; // jump dyld_stub_binding_helper
1612 if ( fWriter.fOptions.prebind() ) {
1613 uint32_t address = this->getAddress();
1614 int32_t rel32 = 0 - (address+5);
1616 buffer[1] = rel32 & 0xFF;
1617 buffer[2] = (rel32 >> 8) & 0xFF;
1618 buffer[3] = (rel32 >> 16) & 0xFF;
1619 buffer[4] = (rel32 >> 24) & 0xFF;
1632 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1634 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
1643 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
1646 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
1647 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
1648 OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
1649 OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
1652 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
1653 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
1654 OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
1658 // x86_64 stubs are 7 bytes and need no alignment
1660 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
1666 const char* StubAtom<ppc>::getSectionName() const
1668 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
1672 const char* StubAtom<ppc64>::getSectionName() const
1674 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
1678 const char* StubAtom<arm>::getSectionName() const
1680 return ( pic() ? "__picsymbolstub4" : "__symbol_stub4");
1684 const char* StubAtom<x86>::getSectionName() const
1686 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
1688 return "__picsymbol_stub";
1690 return "__symbol_stub";
1692 return "__jump_table";
1698 struct AtomByNameSorter
1700 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
1702 return (strcmp(left->getName(), right->getName()) < 0);
1706 template <typename P>
1707 struct ExternalRelocSorter
1709 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
1711 // sort first by symbol number
1712 if ( left.r_symbolnum() != right.r_symbolnum() )
1713 return (left.r_symbolnum() < right.r_symbolnum());
1714 // then sort all uses of the same symbol by address
1715 return (left.r_address() < right.r_address());
1720 template <typename A>
1721 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
1722 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
1723 fAllAtoms(NULL), fStabs(NULL), fLoadCommandsSection(NULL),
1724 fLoadCommandsSegment(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
1725 fSymbolTableCommands(NULL), fHeaderPadding(NULL),
1726 fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL), fDyldHelper(NULL), fDyldLazyDylibHelper(NULL),
1727 fSectionRelocationsAtom(NULL), fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
1728 fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
1729 fStringsAtom(NULL), fPageZeroAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0), fSymbolTableStabsCount(0),
1730 fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
1731 fLargestAtomSize(1),
1732 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
1733 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
1734 fBiggerThanTwoGigs(false), fSlideable(false),
1735 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
1737 switch ( fOptions.outputKind() ) {
1738 case Options::kDynamicExecutable:
1739 case Options::kStaticExecutable:
1740 if ( fOptions.zeroPageSize() != 0 )
1741 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
1742 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1743 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1744 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1745 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1746 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1747 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1748 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1749 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1750 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1751 if ( fOptions.hasCustomStack() )
1752 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
1753 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1754 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1755 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1756 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1757 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1758 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1759 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1761 case Options::kDynamicLibrary:
1762 case Options::kDynamicBundle:
1763 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1765 case Options::kObjectFile:
1766 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1767 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1768 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
1769 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
1770 if ( fOptions.initFunctionName() != NULL )
1771 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
1773 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1774 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1775 if ( fOptions.sharedRegionEligible() )
1776 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
1777 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1778 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1779 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1780 if ( fOptions.sharedRegionEligible() ) {
1781 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
1783 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1784 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1785 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1786 if ( this->needsModuleTable() )
1787 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
1788 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1790 case Options::kDyld:
1791 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1792 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1793 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1794 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1795 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1796 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1797 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1798 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1799 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1800 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1801 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1802 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1803 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1807 // add extra commmands
1808 bool hasReExports = false;
1809 uint32_t ordinal = 1;
1810 switch ( fOptions.outputKind() ) {
1811 case Options::kDynamicExecutable:
1812 if ( fOptions.makeEncryptable() ) {
1813 fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
1814 fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
1817 case Options::kDynamicLibrary:
1818 case Options::kDynamicBundle:
1820 // add dylib load command atoms for all dynamic libraries
1821 const unsigned int libCount = dynamicLibraries.size();
1822 for (unsigned int i=0; i < libCount; ++i) {
1823 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
1824 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
1826 if ( dylibInfo.options.fReExport ) {
1827 hasReExports = true;
1830 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
1831 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
1832 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
1833 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
1834 hasReExports = true;
1838 if ( dylibInfo.options.fBundleLoader ) {
1839 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
1842 // see if a DylibLoadCommandsAtom has already been created for this install path
1843 bool newDylib = true;
1844 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
1845 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
1846 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
1847 if ( !seenDylibInfo.options.fBundleLoader ) {
1848 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
1849 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
1850 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
1851 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
1852 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
1860 // assign new ordinal and check for other paired load commands
1861 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
1862 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
1863 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
1864 fWriterSynthesizedAtoms.push_back(dyliblc);
1865 if ( dylibInfo.options.fReExport
1866 && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
1867 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
1868 // see if child has sub-framework that is this
1869 bool isSubFramework = false;
1870 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
1871 if ( childInUmbrella != NULL ) {
1872 const char* myLeaf = strrchr(fOptions.installPath(), '/');
1873 if ( myLeaf != NULL ) {
1874 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
1875 isSubFramework = true;
1878 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
1879 if ( ! isSubFramework ) {
1880 // this dylib also needs a sub_x load command
1881 bool isFrameworkReExport = false;
1882 const char* lastSlash = strrchr(dylibInstallPath, '/');
1883 if ( lastSlash != NULL ) {
1884 char frameworkName[strlen(lastSlash)+20];
1885 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
1886 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
1888 if ( isFrameworkReExport ) {
1889 // needs a LC_SUB_UMBRELLA command
1890 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
1893 // needs a LC_SUB_LIBRARY command
1894 const char* nameStart = &lastSlash[1];
1895 if ( lastSlash == NULL )
1896 nameStart = dylibInstallPath;
1897 int len = strlen(nameStart);
1898 const char* dot = strchr(nameStart, '.');
1900 len = dot - nameStart;
1901 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
1908 // add umbrella command if needed
1909 if ( fOptions.umbrellaName() != NULL ) {
1910 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
1912 // add allowable client commands if used
1913 std::vector<const char*>& allowableClients = fOptions.allowableClients();
1914 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
1915 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
1918 case Options::kStaticExecutable:
1919 case Options::kObjectFile:
1920 case Options::kDyld:
1923 fNoReExportedDylibs = !hasReExports;
1925 // add any rpath load commands
1926 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
1927 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
1930 // set up fSlideable
1931 switch ( fOptions.outputKind() ) {
1932 case Options::kObjectFile:
1933 case Options::kStaticExecutable:
1936 case Options::kDynamicExecutable:
1937 fSlideable = fOptions.positionIndependentExecutable();
1939 case Options::kDyld:
1940 case Options::kDynamicLibrary:
1941 case Options::kDynamicBundle:
1946 //fprintf(stderr, "ordinals table:\n");
1947 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1948 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
1952 template <typename A>
1953 Writer<A>::~Writer()
1955 if ( fFilePath != NULL )
1956 free((void*)fFilePath);
1957 if ( fSymbolTable != NULL )
1958 delete [] fSymbolTable;
1962 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
1963 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
1964 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
1967 template <typename A>
1968 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
1970 if ( fOptions.outputKind() == Options::kObjectFile ) {
1971 // when doing -r -exported_symbols_list, don't creat proxy for a symbol
1972 // that is supposed to be exported. We want an error instead
1973 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
1974 if ( fOptions.hasExportRestrictList() && fOptions.shouldExport(name) )
1977 return new UndefinedSymbolProxyAtom<A>(*this, name);
1979 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
1980 return new UndefinedSymbolProxyAtom<A>(*this, name);
1985 template <typename A>
1986 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
1988 // flat namespace images use zero for all ordinals
1989 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
1992 // is an UndefinedSymbolProxyAtom
1994 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
1995 return DYNAMIC_LOOKUP_ORDINAL;
1997 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
1998 if ( pos != fLibraryToOrdinal.end() )
2001 throw "can't find ordinal for imported symbol";
2004 template <typename A>
2005 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
2007 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
2011 template <typename A>
2012 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
2013 std::vector<class ObjectFile::Reader::Stab>& stabs,
2014 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
2015 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
2016 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
2017 bool biggerThanTwoGigs, bool overridesDylibWeakDefines)
2021 fEntryPoint = entryPointAtom;
2022 fDyldHelper = dyldHelperAtom;
2023 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
2024 fCanScatter = canScatter;
2025 fCpuConstraint = cpuConstraint;
2026 fBiggerThanTwoGigs = biggerThanTwoGigs;
2027 fHasWeakExports = overridesDylibWeakDefines; // dyld needs to search this image as if it had weak exports
2030 // Set for create UUID
2032 fUUIDAtom->generate();
2034 // remove uneeded dylib load commands
2035 optimizeDylibReferences();
2037 // check for mdynamic-no-pic codegen
2038 scanForAbsoluteReferences();
2040 // create inter-library stubs
2043 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
2044 partitionIntoSections();
2046 // segment load command can now be sized and padding can be set
2047 adjustLoadCommandsAndPadding();
2049 // assign each section a file offset
2050 assignFileOffsets();
2052 // if need to add branch islands, reassign file offsets
2053 if ( addBranchIslands() )
2054 assignFileOffsets();
2056 // build symbol table and relocations
2059 // write map file if requested
2063 return writeAtoms();
2065 // clean up if any errors
2066 (void)unlink(fFilePath);
2071 template <typename A>
2072 void Writer<A>::buildLinkEdit()
2074 this->collectExportedAndImportedAndLocalAtoms();
2075 this->buildSymbolTable();
2076 this->buildFixups();
2077 this->adjustLinkEditSections();
2082 template <typename A>
2083 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
2085 return atom->getAddress();
2086 // SectionInfo* info = (SectionInfo*)atom->getSection();
2087 // return info->getBaseAddress() + atom->getSectionOffset();
2092 const char* Writer<x86_64>::symbolTableName(const ObjectFile::Atom* atom)
2094 static unsigned int counter = 0;
2095 const char* name = atom->getName();
2096 if ( strncmp(name, "cstring=", 8) == 0 )
2097 asprintf((char**)&name, "LC%u", counter++);
2101 template <typename A>
2102 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
2104 return atom->getName();
2107 template <typename A>
2108 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
2111 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
2114 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
2115 entry->set_n_type(N_EXT | N_ABS);
2118 entry->set_n_type(N_EXT | N_SECT);
2119 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
2120 if ( fOptions.keepPrivateExterns() )
2121 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
2125 // set n_sect (section number of implementation )
2126 uint8_t sectionIndex = atom->getSection()->getIndex();
2127 entry->set_n_sect(sectionIndex);
2129 // the __mh_execute_header is magic and must be an absolute symbol
2130 if ( (sectionIndex==0)
2131 && (fOptions.outputKind() == Options::kDynamicExecutable)
2132 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
2133 entry->set_n_type(N_EXT | N_ABS);
2137 if ( atom->isThumb() )
2138 desc |= N_ARM_THUMB_DEF;
2139 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
2140 desc |= REFERENCED_DYNAMICALLY;
2141 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
2143 fHasWeakExports = true;
2145 entry->set_n_desc(desc);
2147 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2148 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2149 entry->set_n_value(atom->getSectionOffset());
2151 entry->set_n_value(this->getAtomLoadAddress(atom));
2154 template <typename A>
2155 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
2158 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
2161 if ( (fOptions.outputKind() == Options::kObjectFile)
2162 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
2163 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
2164 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
2165 else if ( fOptions.prebind() )
2166 entry->set_n_type(N_PBUD | N_EXT);
2168 entry->set_n_type(N_UNDF | N_EXT);
2171 entry->set_n_sect(0);
2174 if ( fOptions.outputKind() != Options::kObjectFile ) {
2175 // set n_desc ( high byte is library ordinal, low byte is reference type )
2176 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
2177 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
2178 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
2180 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
2182 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
2183 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
2184 SET_LIBRARY_ORDINAL(desc, ordinal);
2186 catch (const char* msg) {
2187 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
2190 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
2191 uint8_t align = atom->getAlignment().powerOf2;
2192 // always record custom alignment of common symbols to match what compiler does
2193 SET_COMM_ALIGN(desc, align);
2195 if ( atom->isThumb() )
2196 desc |= N_ARM_THUMB_DEF;
2197 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
2198 desc |= REFERENCED_DYNAMICALLY;
2199 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
2200 desc |= N_REF_TO_WEAK;
2201 fReferencesWeakImports = true;
2203 // set weak_import attribute
2204 if ( fWeakImportMap[atom] )
2206 entry->set_n_desc(desc);
2208 // set n_value, zero for import proxy and size for tentative definition
2209 entry->set_n_value(atom->getSize());
2213 template <typename A>
2214 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
2217 const char* symbolName = this->symbolTableName(atom);
2219 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
2220 sprintf(anonName, "l%u", fAnonNameIndex++);
2221 symbolName = anonName;
2223 entry->set_n_strx(this->fStringsAtom->add(symbolName));
2226 uint8_t type = N_SECT;
2227 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2229 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
2231 entry->set_n_type(type);
2233 // set n_sect (section number of implementation )
2234 uint8_t sectIndex = atom->getSection()->getIndex();
2235 if ( sectIndex == 0 ) {
2236 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
2237 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
2240 entry->set_n_sect(sectIndex);
2244 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2246 if ( atom->isThumb() )
2247 desc |= N_ARM_THUMB_DEF;
2248 entry->set_n_desc(desc);
2250 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2251 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2252 entry->set_n_value(atom->getSectionOffset());
2254 entry->set_n_value(this->getAtomLoadAddress(atom));
2258 template <typename A>
2259 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
2261 macho_nlist<P> entry;
2264 entry.set_n_strx(fStringsAtom->add(name));
2267 entry.set_n_type(N_SECT);
2269 // set n_sect (section number of implementation )
2270 entry.set_n_sect(atom.getSection()->getIndex());
2273 entry.set_n_desc(0);
2275 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2276 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
2279 fLocalExtraLabels.push_back(entry);
2284 template <typename A>
2285 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
2287 macho_nlist<P> entry;
2290 entry.set_n_strx(fStringsAtom->add(name));
2293 entry.set_n_type(N_SECT|N_EXT);
2295 // set n_sect (section number of implementation )
2296 entry.set_n_sect(atom.getSection()->getIndex());
2299 entry.set_n_desc(0);
2301 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2302 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
2305 fGlobalExtraLabels.push_back(entry);
2308 template <typename A>
2309 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
2311 macho_nlist<P>* entry = &fSymbolTable[startIndex];
2312 for (uint32_t i=0; i < count; ++i, ++entry) {
2313 ObjectFile::Atom* atom = atoms[i];
2314 if ( &atoms == &fExportedAtoms ) {
2315 this->setExportNlist(atom, entry);
2317 else if ( &atoms == &fImportedAtoms ) {
2318 this->setImportNlist(atom, entry);
2321 this->setLocalNlist(atom, entry);
2326 template <typename A>
2327 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
2329 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
2330 fSymbolTable[startIndex++] = *it;
2334 template <typename A>
2335 struct NListNameSorter
2337 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
2339 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
2341 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
2344 StringsLinkEditAtom<A>* fStringPool;
2348 template <typename A>
2349 void Writer<A>::buildSymbolTable()
2351 fSymbolTableStabsStartIndex = 0;
2352 fSymbolTableStabsCount = fStabs->size();
2353 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
2354 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
2355 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
2356 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
2357 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
2358 fSymbolTableImportCount = fImportedAtoms.size();
2360 // allocate symbol table
2361 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
2362 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
2364 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
2365 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
2366 if ( fLocalExtraLabels.size() != 0 )
2367 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
2368 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
2369 if ( fGlobalExtraLabels.size() != 0 ) {
2370 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
2371 // re-sort combined range
2372 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
2373 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
2374 NListNameSorter<A>(fStringsAtom) );
2376 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
2377 addStabs(fSymbolTableStabsStartIndex);
2379 // set up module table
2380 if ( fModuleInfoAtom != NULL )
2381 fModuleInfoAtom->setName();
2386 template <typename A>
2387 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
2389 switch ( atom.getSymbolTableInclusion() ) {
2390 case ObjectFile::Atom::kSymbolTableNotIn:
2392 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
2394 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
2395 case ObjectFile::Atom::kSymbolTableIn:
2396 switch ( atom.getScope() ) {
2397 case ObjectFile::Atom::scopeGlobal:
2399 case ObjectFile::Atom::scopeLinkageUnit:
2400 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
2409 template <typename A>
2410 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
2412 const int atomCount = fAllAtoms->size();
2413 // guess at sizes of each bucket to minimize re-allocations
2414 fImportedAtoms.reserve(100);
2415 fExportedAtoms.reserve(atomCount/2);
2416 fLocalSymbolAtoms.reserve(atomCount);
2417 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2418 ObjectFile::Atom* atom = *it;
2419 // only named atoms go in symbol table
2420 if ( atom->getName() != NULL ) {
2421 // put atom into correct bucket: imports, exports, locals
2422 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
2423 switch ( atom->getDefinitionKind() ) {
2424 case ObjectFile::Atom::kExternalDefinition:
2425 case ObjectFile::Atom::kExternalWeakDefinition:
2426 fImportedAtoms.push_back(atom);
2428 case ObjectFile::Atom::kTentativeDefinition:
2429 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
2430 fImportedAtoms.push_back(atom);
2434 case ObjectFile::Atom::kRegularDefinition:
2435 case ObjectFile::Atom::kWeakDefinition:
2436 case ObjectFile::Atom::kAbsoluteSymbol:
2437 if ( this->shouldExport(*atom) )
2438 fExportedAtoms.push_back(atom);
2439 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
2440 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
2441 fLocalSymbolAtoms.push_back(atom);
2445 // when geneating a .o file, dtrace static probes become local labels
2446 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
2447 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2448 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2449 ObjectFile::Reference* ref = *rit;
2450 if ( ref->getKind() == A::kDtraceProbe ) {
2451 // dtrace probe points to be add back into generated .o file
2452 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
2456 // when linking kernel, old style dtrace static probes become global labels
2457 else if ( fOptions.readerOptions().fForStatic ) {
2458 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2459 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2460 ObjectFile::Reference* ref = *rit;
2461 if ( ref->getKind() == A::kDtraceProbe ) {
2462 // dtrace probe points to be add back into generated .o file
2463 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
2469 // sort exported atoms by name
2470 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
2471 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
2472 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
2476 template <typename A>
2477 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
2479 switch ( stab.type ) {
2481 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
2482 // end of function N_FUN has size
2483 return stab.atom->getSize();
2486 // start of function N_FUN has address
2487 return getAtomLoadAddress(stab.atom);
2492 if ( stab.atom == NULL )
2493 // some weird assembly files have slines not associated with a function
2496 // all these stab types need their value changed from an offset in the atom to an address
2497 return getAtomLoadAddress(stab.atom) + stab.value;
2501 // all these need address of atom
2502 return getAtomLoadAddress(stab.atom);;
2504 return stab.atom->getSize();
2506 if ( stab.atom == NULL ) {
2510 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
2511 // end of translation unit N_SO has address of end of last atom
2512 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
2515 // start of translation unit N_SO has address of end of first atom
2516 return getAtomLoadAddress(stab.atom);
2525 template <typename A>
2526 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
2528 switch (stab.type) {
2530 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
2531 return this->fStringsAtom->emptyString();
2534 // fall into uniquing case
2538 return this->fStringsAtom->addUnique(stab.string);
2541 if ( stab.string == NULL )
2543 else if ( stab.string[0] == '\0' )
2544 return this->fStringsAtom->emptyString();
2546 return this->fStringsAtom->add(stab.string);
2551 template <typename A>
2552 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
2554 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
2555 if ( stab.type == N_FUN )
2557 else if ( stab.atom != NULL )
2558 return stab.atom->getSection()->getIndex();
2563 template <typename A>
2564 void Writer<A>::addStabs(uint32_t startIndex)
2566 macho_nlist<P>* entry = &fSymbolTable[startIndex];
2567 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
2568 const ObjectFile::Reader::Stab& stab = *it;
2569 entry->set_n_type(stab.type);
2570 entry->set_n_sect(sectionIndexForStab(stab));
2571 entry->set_n_desc(stab.desc);
2572 entry->set_n_value(valueForStab(stab));
2573 entry->set_n_strx(stringOffsetForStab(stab));
2579 template <typename A>
2580 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
2584 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
2586 return i + fSymbolTableImportStartIndex;
2592 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
2594 return i + fSymbolTableLocalStartIndex;
2600 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
2602 return i + fSymbolTableExportStartIndex;
2606 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
2611 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
2613 switch ( target.getSymbolTableInclusion() ) {
2614 case ObjectFile::Atom::kSymbolTableNotIn:
2616 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
2617 case ObjectFile::Atom::kSymbolTableIn:
2618 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
2624 template <typename A>
2625 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
2627 switch ( target.getDefinitionKind() ) {
2628 case ObjectFile::Atom::kRegularDefinition:
2629 case ObjectFile::Atom::kWeakDefinition:
2630 case ObjectFile::Atom::kAbsoluteSymbol:
2632 case ObjectFile::Atom::kTentativeDefinition:
2633 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
2636 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
2637 case ObjectFile::Atom::kExternalDefinition:
2638 case ObjectFile::Atom::kExternalWeakDefinition:
2639 return shouldExport(target);
2644 template <typename A>
2645 void Writer<A>::buildFixups()
2647 if ( fOptions.outputKind() == Options::kObjectFile ) {
2648 this->buildObjectFileFixups();
2651 if ( fOptions.keepRelocations() )
2652 this->buildObjectFileFixups();
2653 this->buildExecutableFixups();
2658 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2660 ObjectFile::Atom& target = ref->getTarget();
2661 bool external = this->makesExternalRelocatableReference(target);
2662 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
2663 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2664 macho_relocation_info<P> reloc1;
2665 macho_relocation_info<P> reloc2;
2666 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
2669 case x86_64::kNoFixUp:
2670 case x86_64::kFollowOn:
2671 case x86_64::kGroupSubordinate:
2674 case x86_64::kPointer:
2675 case x86_64::kPointerWeakImport:
2676 reloc1.set_r_address(address);
2677 reloc1.set_r_symbolnum(symbolIndex);
2678 reloc1.set_r_pcrel(false);
2679 reloc1.set_r_length(3);
2680 reloc1.set_r_extern(external);
2681 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2682 fSectionRelocs.push_back(reloc1);
2685 case x86_64::kPointerDiff32:
2686 case x86_64::kPointerDiff:
2688 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2689 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2690 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
2691 reloc1.set_r_address(address);
2692 reloc1.set_r_symbolnum(symbolIndex);
2693 reloc1.set_r_pcrel(false);
2694 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2695 reloc1.set_r_extern(external);
2696 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2697 reloc2.set_r_address(address);
2698 reloc2.set_r_symbolnum(fromSymbolIndex);
2699 reloc2.set_r_pcrel(false);
2700 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2701 reloc2.set_r_extern(fromExternal);
2702 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
2703 fSectionRelocs.push_back(reloc1);
2704 fSectionRelocs.push_back(reloc2);
2708 case x86_64::kBranchPCRel32:
2709 case x86_64::kBranchPCRel32WeakImport:
2710 case x86_64::kDtraceProbeSite:
2711 case x86_64::kDtraceIsEnabledSite:
2712 reloc1.set_r_address(address);
2713 reloc1.set_r_symbolnum(symbolIndex);
2714 reloc1.set_r_pcrel(true);
2715 reloc1.set_r_length(2);
2716 reloc1.set_r_extern(external);
2717 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2718 fSectionRelocs.push_back(reloc1);
2721 case x86_64::kPCRel32:
2722 reloc1.set_r_address(address);
2723 reloc1.set_r_symbolnum(symbolIndex);
2724 reloc1.set_r_pcrel(true);
2725 reloc1.set_r_length(2);
2726 reloc1.set_r_extern(external);
2727 reloc1.set_r_type(X86_64_RELOC_SIGNED);
2728 fSectionRelocs.push_back(reloc1);
2731 case x86_64::kPCRel32_1:
2732 reloc1.set_r_address(address);
2733 reloc1.set_r_symbolnum(symbolIndex);
2734 reloc1.set_r_pcrel(true);
2735 reloc1.set_r_length(2);
2736 reloc1.set_r_extern(external);
2737 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
2738 fSectionRelocs.push_back(reloc1);
2741 case x86_64::kPCRel32_2:
2742 reloc1.set_r_address(address);
2743 reloc1.set_r_symbolnum(symbolIndex);
2744 reloc1.set_r_pcrel(true);
2745 reloc1.set_r_length(2);
2746 reloc1.set_r_extern(external);
2747 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
2748 fSectionRelocs.push_back(reloc1);
2751 case x86_64::kPCRel32_4:
2752 reloc1.set_r_address(address);
2753 reloc1.set_r_symbolnum(symbolIndex);
2754 reloc1.set_r_pcrel(true);
2755 reloc1.set_r_length(2);
2756 reloc1.set_r_extern(external);
2757 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
2758 fSectionRelocs.push_back(reloc1);
2761 case x86_64::kBranchPCRel8:
2762 reloc1.set_r_address(address);
2763 reloc1.set_r_symbolnum(symbolIndex);
2764 reloc1.set_r_pcrel(true);
2765 reloc1.set_r_length(0);
2766 reloc1.set_r_extern(external);
2767 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2768 fSectionRelocs.push_back(reloc1);
2771 case x86_64::kPCRel32GOT:
2772 case x86_64::kPCRel32GOTWeakImport:
2773 reloc1.set_r_address(address);
2774 reloc1.set_r_symbolnum(symbolIndex);
2775 reloc1.set_r_pcrel(true);
2776 reloc1.set_r_length(2);
2777 reloc1.set_r_extern(external);
2778 reloc1.set_r_type(X86_64_RELOC_GOT);
2779 fSectionRelocs.push_back(reloc1);
2782 case x86_64::kPCRel32GOTLoad:
2783 case x86_64::kPCRel32GOTLoadWeakImport:
2784 reloc1.set_r_address(address);
2785 reloc1.set_r_symbolnum(symbolIndex);
2786 reloc1.set_r_pcrel(true);
2787 reloc1.set_r_length(2);
2788 reloc1.set_r_extern(external);
2789 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
2790 fSectionRelocs.push_back(reloc1);
2793 case x86_64::kDtraceTypeReference:
2794 case x86_64::kDtraceProbe:
2795 // generates no relocs
2803 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2805 ObjectFile::Atom& target = ref->getTarget();
2806 bool isExtern = this->makesExternalRelocatableReference(target);
2807 uint32_t symbolIndex = 0;
2809 symbolIndex = this->symbolIndex(target);
2810 uint32_t sectionNum = target.getSection()->getIndex();
2811 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2812 macho_relocation_info<P> reloc1;
2813 macho_relocation_info<P> reloc2;
2814 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2815 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2816 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
2818 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2819 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
2820 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2825 case x86::kFollowOn:
2826 case x86::kGroupSubordinate:
2830 case x86::kPointerWeakImport:
2831 case x86::kAbsolute32:
2832 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2833 // use scattered reloc is target offset is non-zero
2834 sreloc1->set_r_scattered(true);
2835 sreloc1->set_r_pcrel(false);
2836 sreloc1->set_r_length(2);
2837 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2838 sreloc1->set_r_address(address);
2839 sreloc1->set_r_value(target.getAddress());
2842 reloc1.set_r_address(address);
2843 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2844 reloc1.set_r_pcrel(false);
2845 reloc1.set_r_length(2);
2846 reloc1.set_r_extern(isExtern);
2847 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2849 fSectionRelocs.push_back(reloc1);
2852 case x86::kPointerDiff16:
2853 case x86::kPointerDiff:
2855 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2856 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
2857 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
2858 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
2859 sreloc1->set_r_scattered(true);
2860 sreloc1->set_r_pcrel(false);
2861 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2862 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2863 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
2865 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
2866 sreloc1->set_r_address(address);
2867 sreloc1->set_r_value(target.getAddress());
2868 sreloc2->set_r_scattered(true);
2869 sreloc2->set_r_pcrel(false);
2870 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2871 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
2872 sreloc2->set_r_address(0);
2873 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
2874 fSectionRelocs.push_back(reloc2);
2875 fSectionRelocs.push_back(reloc1);
2879 case x86::kPCRel32WeakImport:
2883 case x86::kDtraceProbeSite:
2884 case x86::kDtraceIsEnabledSite:
2885 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2886 // use scattered reloc is target offset is non-zero
2887 sreloc1->set_r_scattered(true);
2888 sreloc1->set_r_pcrel(true);
2889 sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
2890 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2891 sreloc1->set_r_address(address);
2892 sreloc1->set_r_value(target.getAddress());
2895 reloc1.set_r_address(address);
2896 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2897 reloc1.set_r_pcrel(true);
2898 reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
2899 reloc1.set_r_extern(isExtern);
2900 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2902 fSectionRelocs.push_back(reloc1);
2905 case x86::kDtraceTypeReference:
2906 case x86::kDtraceProbe:
2907 // generates no relocs
2915 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2917 ObjectFile::Atom& target = ref->getTarget();
2918 bool isExtern = this->makesExternalRelocatableReference(target);
2919 uint32_t symbolIndex = 0;
2921 symbolIndex = this->symbolIndex(target);
2922 uint32_t sectionNum = target.getSection()->getIndex();
2923 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2924 macho_relocation_info<P> reloc1;
2925 macho_relocation_info<P> reloc2;
2926 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2927 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2928 arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
2930 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2931 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
2932 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2937 case arm::kFollowOn:
2938 case arm::kGroupSubordinate:
2942 case arm::kReadOnlyPointer:
2943 case arm::kPointerWeakImport:
2944 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2945 // use scattered reloc is target offset is non-zero
2946 sreloc1->set_r_scattered(true);
2947 sreloc1->set_r_pcrel(false);
2948 sreloc1->set_r_length(2);
2949 sreloc1->set_r_type(ARM_RELOC_VANILLA);
2950 sreloc1->set_r_address(address);
2951 sreloc1->set_r_value(target.getAddress());
2954 reloc1.set_r_address(address);
2955 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2956 reloc1.set_r_pcrel(false);
2957 reloc1.set_r_length(2);
2958 reloc1.set_r_extern(isExtern);
2959 reloc1.set_r_type(ARM_RELOC_VANILLA);
2961 fSectionRelocs.push_back(reloc1);
2964 case arm::kPointerDiff:
2966 sreloc1->set_r_scattered(true);
2967 sreloc1->set_r_pcrel(false);
2968 sreloc1->set_r_length(2);
2969 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2970 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
2972 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
2973 sreloc1->set_r_address(address);
2974 sreloc1->set_r_value(target.getAddress());
2975 sreloc2->set_r_scattered(true);
2976 sreloc2->set_r_pcrel(false);
2977 sreloc2->set_r_length(2);
2978 sreloc2->set_r_type(ARM_RELOC_PAIR);
2979 sreloc2->set_r_address(0);
2980 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
2981 fSectionRelocs.push_back(reloc2);
2982 fSectionRelocs.push_back(reloc1);
2986 case arm::kBranch24WeakImport:
2987 case arm::kBranch24:
2988 case arm::kDtraceProbeSite:
2989 case arm::kDtraceIsEnabledSite:
2990 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2991 // use scattered reloc is target offset is non-zero
2992 sreloc1->set_r_scattered(true);
2993 sreloc1->set_r_pcrel(true);
2994 sreloc1->set_r_length(2);
2995 sreloc1->set_r_type(ARM_RELOC_BR24);
2996 sreloc1->set_r_address(address);
2997 sreloc1->set_r_value(target.getAddress());
3000 reloc1.set_r_address(address);
3001 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3002 reloc1.set_r_pcrel(true);
3003 reloc1.set_r_length(2);
3004 reloc1.set_r_extern(isExtern);
3005 reloc1.set_r_type(ARM_RELOC_BR24);
3007 fSectionRelocs.push_back(reloc1);
3010 case arm::kThumbBranch22WeakImport:
3011 case arm::kThumbBranch22:
3012 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
3013 // use scattered reloc is target offset is non-zero
3014 sreloc1->set_r_scattered(true);
3015 sreloc1->set_r_pcrel(true);
3016 sreloc1->set_r_length(2);
3017 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
3018 sreloc1->set_r_address(address);
3019 sreloc1->set_r_value(target.getAddress());
3022 reloc1.set_r_address(address);
3023 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3024 reloc1.set_r_pcrel(true);
3025 reloc1.set_r_length(2);
3026 reloc1.set_r_extern(isExtern);
3027 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
3029 fSectionRelocs.push_back(reloc1);
3032 case arm::kDtraceTypeReference:
3033 case arm::kDtraceProbe:
3034 // generates no relocs
3041 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
3042 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
3043 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
3044 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
3045 template <> uint64_t Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
3048 uint8_t Writer<ppc>::getRelocPointerSize()
3054 uint8_t Writer<ppc64>::getRelocPointerSize()
3060 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3062 return addObjectRelocs_powerpc(atom, ref);
3066 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3068 return addObjectRelocs_powerpc(atom, ref);
3072 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
3073 // they use a common addObjectRelocs_powerpc() method.
3075 template <typename A>
3076 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3078 ObjectFile::Atom& target = ref->getTarget();
3079 bool isExtern = this->makesExternalRelocatableReference(target);
3080 uint32_t symbolIndex = 0;
3082 symbolIndex = this->symbolIndex(target);
3083 uint32_t sectionNum = target.getSection()->getIndex();
3084 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3085 macho_relocation_info<P> reloc1;
3086 macho_relocation_info<P> reloc2;
3087 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
3088 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
3089 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
3094 case A::kGroupSubordinate:
3098 case A::kPointerWeakImport:
3099 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
3100 // use scattered reloc is target offset is outside target
3101 sreloc1->set_r_scattered(true);
3102 sreloc1->set_r_pcrel(false);
3103 sreloc1->set_r_length(getRelocPointerSize());
3104 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
3105 sreloc1->set_r_address(address);
3106 sreloc1->set_r_value(target.getAddress());
3109 reloc1.set_r_address(address);
3111 reloc1.set_r_symbolnum(symbolIndex);
3113 reloc1.set_r_symbolnum(sectionNum);
3114 reloc1.set_r_pcrel(false);
3115 reloc1.set_r_length(getRelocPointerSize());
3116 reloc1.set_r_extern(isExtern);
3117 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3119 fSectionRelocs.push_back(reloc1);
3122 case A::kPointerDiff16:
3123 case A::kPointerDiff32:
3124 case A::kPointerDiff64:
3126 sreloc1->set_r_scattered(true);
3127 sreloc1->set_r_pcrel(false);
3128 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
3129 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
3130 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
3132 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
3133 sreloc1->set_r_address(address);
3134 sreloc1->set_r_value(target.getAddress());
3135 sreloc2->set_r_scattered(true);
3136 sreloc2->set_r_pcrel(false);
3137 sreloc2->set_r_length(sreloc1->r_length());
3138 sreloc2->set_r_type(PPC_RELOC_PAIR);
3139 sreloc2->set_r_address(0);
3140 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
3141 fSectionRelocs.push_back(reloc2);
3142 fSectionRelocs.push_back(reloc1);
3146 case A::kBranch24WeakImport:
3148 case A::kDtraceProbeSite:
3149 case A::kDtraceIsEnabledSite:
3150 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3151 reloc1.set_r_address(address);
3153 reloc1.set_r_symbolnum(symbolIndex);
3155 reloc1.set_r_symbolnum(sectionNum);
3156 reloc1.set_r_pcrel(true);
3157 reloc1.set_r_length(2);
3158 reloc1.set_r_type(PPC_RELOC_BR24);
3159 reloc1.set_r_extern(isExtern);
3162 sreloc1->set_r_scattered(true);
3163 sreloc1->set_r_pcrel(true);
3164 sreloc1->set_r_length(2);
3165 sreloc1->set_r_type(PPC_RELOC_BR24);
3166 sreloc1->set_r_address(address);
3167 sreloc1->set_r_value(target.getAddress());
3169 fSectionRelocs.push_back(reloc1);
3173 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3174 reloc1.set_r_address(address);
3176 reloc1.set_r_symbolnum(symbolIndex);
3178 reloc1.set_r_symbolnum(sectionNum);
3179 reloc1.set_r_pcrel(true);
3180 reloc1.set_r_length(2);
3181 reloc1.set_r_type(PPC_RELOC_BR14);
3182 reloc1.set_r_extern(isExtern);
3185 sreloc1->set_r_scattered(true);
3186 sreloc1->set_r_pcrel(true);
3187 sreloc1->set_r_length(2);
3188 sreloc1->set_r_type(PPC_RELOC_BR14);
3189 sreloc1->set_r_address(address);
3190 sreloc1->set_r_value(target.getAddress());
3192 fSectionRelocs.push_back(reloc1);
3195 case A::kPICBaseLow16:
3196 case A::kPICBaseLow14:
3198 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
3199 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3200 sreloc1->set_r_scattered(true);
3201 sreloc1->set_r_pcrel(false);
3202 sreloc1->set_r_length(2);
3203 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
3204 sreloc1->set_r_address(address);
3205 sreloc1->set_r_value(target.getAddress());
3206 sreloc2->set_r_scattered(true);
3207 sreloc2->set_r_pcrel(false);
3208 sreloc2->set_r_length(2);
3209 sreloc2->set_r_type(PPC_RELOC_PAIR);
3210 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
3211 sreloc2->set_r_value(fromAddr);
3212 fSectionRelocs.push_back(reloc2);
3213 fSectionRelocs.push_back(reloc1);
3217 case A::kPICBaseHigh16:
3219 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
3220 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3221 sreloc1->set_r_scattered(true);
3222 sreloc1->set_r_pcrel(false);
3223 sreloc1->set_r_length(2);
3224 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
3225 sreloc1->set_r_address(address);
3226 sreloc1->set_r_value(target.getAddress());
3227 sreloc2->set_r_scattered(true);
3228 sreloc2->set_r_pcrel(false);
3229 sreloc2->set_r_length(2);
3230 sreloc2->set_r_type(PPC_RELOC_PAIR);
3231 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
3232 sreloc2->set_r_value(fromAddr);
3233 fSectionRelocs.push_back(reloc2);
3234 fSectionRelocs.push_back(reloc1);
3241 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3242 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3243 reloc1.set_r_address(address);
3245 reloc1.set_r_symbolnum(symbolIndex);
3247 reloc1.set_r_symbolnum(sectionNum);
3248 reloc1.set_r_pcrel(false);
3249 reloc1.set_r_length(2);
3250 reloc1.set_r_extern(isExtern);
3251 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
3254 sreloc1->set_r_scattered(true);
3255 sreloc1->set_r_pcrel(false);
3256 sreloc1->set_r_length(2);
3257 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
3258 sreloc1->set_r_address(address);
3259 sreloc1->set_r_value(target.getAddress());
3262 reloc2.set_r_address(ref->getTargetOffset() >> 16);
3264 reloc2.set_r_address(toAddr >> 16);
3265 reloc2.set_r_symbolnum(0);
3266 reloc2.set_r_pcrel(false);
3267 reloc2.set_r_length(2);
3268 reloc2.set_r_extern(false);
3269 reloc2.set_r_type(PPC_RELOC_PAIR);
3270 fSectionRelocs.push_back(reloc2);
3271 fSectionRelocs.push_back(reloc1);
3277 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3278 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3279 reloc1.set_r_address(address);
3281 reloc1.set_r_symbolnum(symbolIndex);
3283 reloc1.set_r_symbolnum(sectionNum);
3284 reloc1.set_r_pcrel(false);
3285 reloc1.set_r_length(2);
3286 reloc1.set_r_extern(isExtern);
3287 reloc1.set_r_type(PPC_RELOC_HI16);
3290 sreloc1->set_r_scattered(true);
3291 sreloc1->set_r_pcrel(false);
3292 sreloc1->set_r_length(2);
3293 sreloc1->set_r_type(PPC_RELOC_HI16);
3294 sreloc1->set_r_address(address);
3295 sreloc1->set_r_value(target.getAddress());
3298 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
3300 reloc2.set_r_address(toAddr & 0xFFFF);
3301 reloc2.set_r_symbolnum(0);
3302 reloc2.set_r_pcrel(false);
3303 reloc2.set_r_length(2);
3304 reloc2.set_r_extern(false);
3305 reloc2.set_r_type(PPC_RELOC_PAIR);
3306 fSectionRelocs.push_back(reloc2);
3307 fSectionRelocs.push_back(reloc1);
3311 case A::kAbsHigh16AddLow:
3313 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3314 uint32_t overflow = 0;
3315 if ( (toAddr & 0x00008000) != 0 )
3317 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3318 reloc1.set_r_address(address);
3320 reloc1.set_r_symbolnum(symbolIndex);
3322 reloc1.set_r_symbolnum(sectionNum);
3323 reloc1.set_r_pcrel(false);
3324 reloc1.set_r_length(2);
3325 reloc1.set_r_extern(isExtern);
3326 reloc1.set_r_type(PPC_RELOC_HA16);
3329 sreloc1->set_r_scattered(true);
3330 sreloc1->set_r_pcrel(false);
3331 sreloc1->set_r_length(2);
3332 sreloc1->set_r_type(PPC_RELOC_HA16);
3333 sreloc1->set_r_address(address);
3334 sreloc1->set_r_value(target.getAddress());
3337 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
3339 reloc2.set_r_address(toAddr & 0xFFFF);
3340 reloc2.set_r_symbolnum(0);
3341 reloc2.set_r_pcrel(false);
3342 reloc2.set_r_length(2);
3343 reloc2.set_r_extern(false);
3344 reloc2.set_r_type(PPC_RELOC_PAIR);
3345 fSectionRelocs.push_back(reloc2);
3346 fSectionRelocs.push_back(reloc1);
3350 case A::kDtraceTypeReference:
3351 case A::kDtraceProbe:
3352 // generates no relocs
3361 // There are cases when an entry in the indirect symbol table is the magic value
3362 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
3363 // the content of the corresponding part of the __nl_symbol_pointer section
3364 // must also change.
3366 template <typename A>
3367 bool Writer<A>::indirectSymbolIsLocal(const ObjectFile::Reference* ref) const
3369 // use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3370 return ( !this->shouldExport(ref->getTarget()) || (ref->getTargetOffset() != 0) );
3374 template <typename A>
3375 void Writer<A>::buildObjectFileFixups()
3377 uint32_t relocIndex = 0;
3378 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3379 const int segCount = segmentInfos.size();
3380 for(int i=0; i < segCount; ++i) {
3381 SegmentInfo* curSegment = segmentInfos[i];
3382 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3383 const int sectionCount = sectionInfos.size();
3384 for(int j=0; j < sectionCount; ++j) {
3385 SectionInfo* curSection = sectionInfos[j];
3386 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
3387 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3388 if ( ! curSection->fAllZeroFill ) {
3389 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
3390 || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
3391 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3392 curSection->fRelocOffset = relocIndex;
3393 const int atomCount = sectionAtoms.size();
3394 for (int k=0; k < atomCount; ++k) {
3395 ObjectFile::Atom* atom = sectionAtoms[k];
3396 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
3397 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3398 const int refCount = refs.size();
3399 for (int l=0; l < refCount; ++l) {
3400 ObjectFile::Reference* ref = refs[l];
3401 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
3402 || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
3403 uint32_t offsetInSection = atom->getSectionOffset();
3404 uint32_t indexInSection = offsetInSection / atom->getSize();
3405 uint32_t undefinedSymbolIndex;
3406 if ( curSection->fAllStubs ) {
3407 ObjectFile::Atom& stubTarget =ref->getTarget();
3408 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
3409 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
3410 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
3412 else if ( curSection->fAllNonLazyPointers) {
3413 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3414 if ( this->indirectSymbolIsLocal(ref) )
3415 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3417 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
3420 // should never get here, fAllLazyPointers not used in generated .o files
3421 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3423 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3424 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3425 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
3426 fIndirectTableAtom->fTable.push_back(entry);
3427 if ( curSection->fAllLazyPointers ) {
3428 ObjectFile::Atom& target = ref->getTarget();
3429 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3430 if ( &fromTarget == NULL ) {
3431 warning("lazy pointer %s missing initial binding", atom->getDisplayName());
3434 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3435 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
3436 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
3437 macho_relocation_info<P> reloc1;
3438 reloc1.set_r_address(atom->getSectionOffset());
3439 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
3440 reloc1.set_r_pcrel(false);
3441 reloc1.set_r_length();
3442 reloc1.set_r_extern(isExtern);
3443 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3444 fSectionRelocs.push_back(reloc1);
3448 else if ( curSection->fAllStubs ) {
3449 relocIndex += this->addObjectRelocs(atom, ref);
3452 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
3453 relocIndex += this->addObjectRelocs(atom, ref);
3457 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
3462 // reverse the relocs
3463 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
3465 // now reverse section reloc offsets
3466 for(int i=0; i < segCount; ++i) {
3467 SegmentInfo* curSegment = segmentInfos[i];
3468 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3469 const int sectionCount = sectionInfos.size();
3470 for(int j=0; j < sectionCount; ++j) {
3471 SectionInfo* curSection = sectionInfos[j];
3472 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
3479 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3481 switch ( ref.getKind() ) {
3482 case ppc::kAbsLow16:
3483 case ppc::kAbsLow14:
3484 case ppc::kAbsHigh16:
3485 case ppc::kAbsHigh16AddLow:
3494 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3496 switch ( ref.getKind() ) {
3497 case ppc::kAbsLow16:
3498 case ppc::kAbsLow14:
3499 case ppc::kAbsHigh16:
3500 case ppc::kAbsHigh16AddLow:
3508 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3510 if ( ref.getKind() == x86::kAbsolute32 ) {
3511 switch ( ref.getTarget().getDefinitionKind() ) {
3512 case ObjectFile::Atom::kTentativeDefinition:
3513 case ObjectFile::Atom::kRegularDefinition:
3514 case ObjectFile::Atom::kWeakDefinition:
3515 // illegal in dylibs/bundles, until we support TEXT relocs
3517 case ObjectFile::Atom::kExternalDefinition:
3518 case ObjectFile::Atom::kExternalWeakDefinition:
3519 // illegal until we support TEXT relocs
3521 case ObjectFile::Atom::kAbsoluteSymbol:
3522 // absolute symbbols only allowed in static executables
3523 return ( fOptions.outputKind() != Options::kStaticExecutable);
3530 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3536 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3538 if ( ref.getKind() == arm::kReadOnlyPointer ) {
3539 switch ( ref.getTarget().getDefinitionKind() ) {
3540 case ObjectFile::Atom::kTentativeDefinition:
3541 case ObjectFile::Atom::kRegularDefinition:
3542 case ObjectFile::Atom::kWeakDefinition:
3543 // illegal in dylibs/bundles, until we support TEXT relocs
3545 case ObjectFile::Atom::kExternalDefinition:
3546 case ObjectFile::Atom::kExternalWeakDefinition:
3547 // illegal until we support TEXT relocs
3549 case ObjectFile::Atom::kAbsoluteSymbol:
3550 // absolute symbbols only allowed in static executables
3551 return ( fOptions.outputKind() != Options::kStaticExecutable);
3558 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3560 if ( ref.getKind() == x86::kAbsolute32 ) {
3561 switch ( ref.getTarget().getDefinitionKind() ) {
3562 case ObjectFile::Atom::kTentativeDefinition:
3563 case ObjectFile::Atom::kRegularDefinition:
3564 case ObjectFile::Atom::kWeakDefinition:
3565 // a reference to the absolute address of something in this same linkage unit can be
3566 // encoded as a local text reloc in a dylib or bundle
3568 macho_relocation_info<P> reloc;
3569 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3570 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3571 reloc.set_r_symbolnum(sectInfo->getIndex());
3572 reloc.set_r_pcrel(false);
3573 reloc.set_r_length();
3574 reloc.set_r_extern(false);
3575 reloc.set_r_type(GENERIC_RELOC_VANILLA);
3576 fInternalRelocs.push_back(reloc);
3577 atomSection->fHasTextLocalRelocs = true;
3581 case ObjectFile::Atom::kExternalDefinition:
3582 case ObjectFile::Atom::kExternalWeakDefinition:
3583 case ObjectFile::Atom::kAbsoluteSymbol:
3591 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3593 macho_relocation_info<P> reloc1;
3594 macho_relocation_info<P> reloc2;
3595 switch ( ref.getTarget().getDefinitionKind() ) {
3596 case ObjectFile::Atom::kTentativeDefinition:
3597 case ObjectFile::Atom::kRegularDefinition:
3598 case ObjectFile::Atom::kWeakDefinition:
3599 switch ( ref.getKind() ) {
3600 case ppc::kAbsLow16:
3601 case ppc::kAbsLow14:
3602 // a reference to the absolute address of something in this same linkage unit can be
3603 // encoded as a local text reloc in a dylib or bundle
3605 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3606 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
3607 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3608 reloc1.set_r_symbolnum(sectInfo->getIndex());
3609 reloc1.set_r_pcrel(false);
3610 reloc1.set_r_length(2);
3611 reloc1.set_r_extern(false);
3612 reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
3613 reloc2.set_r_address(targetAddr >> 16);
3614 reloc2.set_r_symbolnum(0);
3615 reloc2.set_r_pcrel(false);
3616 reloc2.set_r_length(2);
3617 reloc2.set_r_extern(false);
3618 reloc2.set_r_type(PPC_RELOC_PAIR);
3619 fInternalRelocs.push_back(reloc1);
3620 fInternalRelocs.push_back(reloc2);
3621 atomSection->fHasTextLocalRelocs = true;
3625 case ppc::kAbsHigh16:
3626 case ppc::kAbsHigh16AddLow:
3628 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3629 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
3630 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3631 reloc1.set_r_symbolnum(sectInfo->getIndex());
3632 reloc1.set_r_pcrel(false);
3633 reloc1.set_r_length(2);
3634 reloc1.set_r_extern(false);
3635 reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
3636 reloc2.set_r_address(targetAddr & 0xFFFF);
3637 reloc2.set_r_symbolnum(0);
3638 reloc2.set_r_pcrel(false);
3639 reloc2.set_r_length(2);
3640 reloc2.set_r_extern(false);
3641 reloc2.set_r_type(PPC_RELOC_PAIR);
3642 fInternalRelocs.push_back(reloc1);
3643 fInternalRelocs.push_back(reloc2);
3644 atomSection->fHasTextLocalRelocs = true;
3649 case ObjectFile::Atom::kExternalDefinition:
3650 case ObjectFile::Atom::kExternalWeakDefinition:
3651 case ObjectFile::Atom::kAbsoluteSymbol:
3658 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3660 if ( ref.getKind() == arm::kReadOnlyPointer ) {
3661 switch ( ref.getTarget().getDefinitionKind() ) {
3662 case ObjectFile::Atom::kTentativeDefinition:
3663 case ObjectFile::Atom::kRegularDefinition:
3664 case ObjectFile::Atom::kWeakDefinition:
3665 // a reference to the absolute address of something in this same linkage unit can be
3666 // encoded as a local text reloc in a dylib or bundle
3668 macho_relocation_info<P> reloc;
3669 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3670 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3671 reloc.set_r_symbolnum(sectInfo->getIndex());
3672 reloc.set_r_pcrel(false);
3673 reloc.set_r_length();
3674 reloc.set_r_extern(false);
3675 reloc.set_r_type(GENERIC_RELOC_VANILLA);
3676 fInternalRelocs.push_back(reloc);
3677 atomSection->fHasTextLocalRelocs = true;
3681 case ObjectFile::Atom::kExternalDefinition:
3682 case ObjectFile::Atom::kExternalWeakDefinition:
3683 case ObjectFile::Atom::kAbsoluteSymbol:
3692 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
3694 // text relocs not supported (usually never needed because of RIP addressing)
3699 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
3701 // text relocs not supported
3706 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3708 if ( ref.getKind() == x86::kAbsolute32 ) {
3709 macho_relocation_info<P> reloc;
3710 switch ( ref.getTarget().getDefinitionKind() ) {
3711 case ObjectFile::Atom::kTentativeDefinition:
3712 case ObjectFile::Atom::kRegularDefinition:
3713 case ObjectFile::Atom::kWeakDefinition:
3715 case ObjectFile::Atom::kExternalDefinition:
3716 case ObjectFile::Atom::kExternalWeakDefinition:
3717 // a reference to the absolute address of something in another linkage unit can be
3718 // encoded as an external text reloc in a dylib or bundle
3719 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3720 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
3721 reloc.set_r_pcrel(false);
3722 reloc.set_r_length();
3723 reloc.set_r_extern(true);
3724 reloc.set_r_type(GENERIC_RELOC_VANILLA);
3725 fExternalRelocs.push_back(reloc);
3726 atomSection->fHasTextExternalRelocs = true;
3728 case ObjectFile::Atom::kAbsoluteSymbol:
3735 template <typename A>
3736 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
3744 template <typename A>
3745 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
3747 switch ( target.getDefinitionKind() ) {
3748 case ObjectFile::Atom::kTentativeDefinition:
3749 case ObjectFile::Atom::kRegularDefinition:
3750 // in main executables, the only way regular symbols are indirected is if -interposable is used
3751 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
3752 if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
3753 return kRelocExternal;
3754 else if ( fSlideable )
3755 return kRelocInternal;
3759 // for flat-namespace or interposable two-level-namespace
3760 // all references to exported symbols get indirected
3761 else if ( this->shouldExport(target) &&
3762 ((fOptions.nameSpace() == Options::kFlatNameSpace)
3763 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
3764 || fOptions.interposable(target.getName()))
3765 && (target.getName() != NULL)
3766 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
3767 return kRelocExternal;
3768 else if ( fSlideable )
3769 return kRelocInternal;
3772 case ObjectFile::Atom::kWeakDefinition:
3773 // all calls to global weak definitions get indirected
3774 if ( this->shouldExport(target) )
3775 return kRelocExternal;
3776 else if ( fSlideable )
3777 return kRelocInternal;
3780 case ObjectFile::Atom::kExternalDefinition:
3781 case ObjectFile::Atom::kExternalWeakDefinition:
3782 return kRelocExternal;
3783 case ObjectFile::Atom::kAbsoluteSymbol:
3789 template <typename A>
3790 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3792 // for 32-bit architectures, the r_address field in relocs
3793 // for final linked images is the offset from the first segment
3794 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
3795 // or the offset from the first writable segment if built split-seg
3796 if ( fOptions.splitSeg() )
3797 result = address - fFirstWritableSegment->fBaseAddress;
3798 if ( result > 0x7FFFFFFF ) {
3799 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
3800 atom->getDisplayName(), atom->getFile()->getPath());
3806 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3808 // for x86_64, the r_address field in relocs for final linked images
3809 // is the offset from the start address of the first writable segment
3810 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
3811 if ( result > 0xFFFFFFFF ) {
3812 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3813 atom->getDisplayName(), atom->getFile()->getPath());
3819 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3821 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
3822 // the 10.5 dyld, iterprets the r_address as:
3823 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
3824 // 2) an offset from the base address of the first writable segment
3825 // For dyld, r_address is always the offset from the base address
3827 bool badFor10_4 = false;
3828 if ( fWritableSegmentPastFirst4GB ) {
3829 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
3831 result = address - fFirstWritableSegment->fBaseAddress;
3832 if ( result > 0xFFFFFFFF ) {
3833 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3834 atom->getDisplayName(), atom->getFile()->getPath());
3838 result = address - fSegmentInfos[0]->fBaseAddress;
3839 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
3843 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",
3844 atom->getDisplayName(), atom->getFile()->getPath());
3850 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
3851 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3852 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
3853 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3854 template <> bool Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
3856 template <typename A>
3857 void Writer<A>::buildExecutableFixups()
3859 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
3860 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3861 const int segCount = segmentInfos.size();
3862 for(int i=0; i < segCount; ++i) {
3863 SegmentInfo* curSegment = segmentInfos[i];
3864 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3865 const int sectionCount = sectionInfos.size();
3866 for(int j=0; j < sectionCount; ++j) {
3867 SectionInfo* curSection = sectionInfos[j];
3868 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
3869 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3870 if ( ! curSection->fAllZeroFill ) {
3871 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers
3872 || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
3873 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3874 const int atomCount = sectionAtoms.size();
3875 for (int k=0; k < atomCount; ++k) {
3876 ObjectFile::Atom* atom = sectionAtoms[k];
3877 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3878 const int refCount = refs.size();
3879 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
3880 for (int l=0; l < refCount; ++l) {
3881 ObjectFile::Reference* ref = refs[l];
3882 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
3883 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
3884 if ( atom->getSize() != sizeof(pint_t) ) {
3885 warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
3887 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
3888 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
3889 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
3891 uint32_t offsetInSection = atom->getSectionOffset();
3892 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
3893 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3894 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
3895 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
3896 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3897 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3898 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X), pointerTarget=%s\n",
3899 // indirectTableIndex, undefinedSymbolIndex, pointerTarget->getDisplayName());
3900 fIndirectTableAtom->fTable.push_back(entry);
3901 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
3902 uint8_t preboundLazyType;
3903 if ( fOptions.prebind() && (fDyldHelper != NULL)
3904 && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
3905 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
3906 macho_scattered_relocation_info<P> pblaReloc;
3907 pblaReloc.set_r_scattered(true);
3908 pblaReloc.set_r_pcrel(false);
3909 pblaReloc.set_r_length();
3910 pblaReloc.set_r_type(preboundLazyType);
3911 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3912 pblaReloc.set_r_value(fDyldHelper->getAddress());
3913 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
3915 else if ( fSlideable ) {
3916 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
3917 macho_relocation_info<P> dyldHelperReloc;
3918 uint32_t sectionNum = 1;
3919 if ( fDyldHelper != NULL )
3920 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
3921 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
3922 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3923 dyldHelperReloc.set_r_symbolnum(sectionNum);
3924 dyldHelperReloc.set_r_pcrel(false);
3925 dyldHelperReloc.set_r_length();
3926 dyldHelperReloc.set_r_extern(false);
3927 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
3928 fInternalRelocs.push_back(dyldHelperReloc);
3932 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
3933 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
3934 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
3935 atom->getDisplayName(), atom->getFile()->getPath());
3937 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
3941 case kRelocInternal:
3943 macho_relocation_info<P> internalReloc;
3944 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
3945 uint32_t sectionNum = sectInfo->getIndex();
3946 // special case _mh_dylib_header and friends which are not in any real section
3947 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
3949 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3950 internalReloc.set_r_symbolnum(sectionNum);
3951 internalReloc.set_r_pcrel(false);
3952 internalReloc.set_r_length();
3953 internalReloc.set_r_extern(false);
3954 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3955 fInternalRelocs.push_back(internalReloc);
3958 case kRelocExternal:
3960 macho_relocation_info<P> externalReloc;
3961 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3962 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
3963 externalReloc.set_r_pcrel(false);
3964 externalReloc.set_r_length();
3965 externalReloc.set_r_extern(true);
3966 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3967 fExternalRelocs.push_back(externalReloc);
3972 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
3973 if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
3974 if ( fOptions.warnAboutTextRelocs() )
3975 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
3976 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
3977 // relocs added to fInternalRelocs
3979 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
3980 // relocs added to fExternalRelocs
3983 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
3987 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
3988 "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
3992 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
3993 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
3994 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
3995 uint32_t offsetInSection = atom->getSectionOffset();
3996 uint32_t indexInSection = offsetInSection / atom->getSize();
3997 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3998 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3999 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
4000 fIndirectTableAtom->fTable.push_back(entry);
4006 if ( fSplitCodeToDataContentAtom != NULL )
4007 fSplitCodeToDataContentAtom->encode();
4012 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4014 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
4015 case ppc::kPICBaseHigh16:
4016 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
4018 case ppc::kPointerDiff32:
4019 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4021 case ppc::kPointerDiff64:
4022 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
4025 case ppc::kGroupSubordinate:
4027 case ppc::kPointerWeakImport:
4028 case ppc::kPICBaseLow16:
4029 case ppc::kPICBaseLow14:
4033 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
4034 fSplitCodeToDataContentAtom->setCantEncode();
4039 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4041 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
4042 case ppc64::kPICBaseHigh16:
4043 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
4045 case ppc64::kPointerDiff32:
4046 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4048 case ppc64::kPointerDiff64:
4049 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
4051 case ppc64::kNoFixUp:
4052 case ppc64::kGroupSubordinate:
4053 case ppc64::kPointer:
4054 case ppc64::kPointerWeakImport:
4055 case ppc64::kPICBaseLow16:
4056 case ppc64::kPICBaseLow14:
4060 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
4061 fSplitCodeToDataContentAtom->setCantEncode();
4066 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4068 switch ( (x86::ReferenceKinds)ref->getKind() ) {
4069 case x86::kPointerDiff:
4070 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
4071 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
4073 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4076 case x86::kGroupSubordinate:
4078 case x86::kPointerWeakImport:
4082 case x86::kPCRel32WeakImport:
4083 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
4084 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
4085 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
4088 // fall into warning case
4090 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
4091 fSplitCodeToDataContentAtom->setCantEncode();
4096 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4098 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
4099 case x86_64::kPCRel32:
4100 case x86_64::kPCRel32_1:
4101 case x86_64::kPCRel32_2:
4102 case x86_64::kPCRel32_4:
4103 case x86_64::kPCRel32GOTLoad:
4104 case x86_64::kPCRel32GOTLoadWeakImport:
4105 case x86_64::kPCRel32GOT:
4106 case x86_64::kPCRel32GOTWeakImport:
4107 case x86_64::kPointerDiff32:
4108 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4110 case x86_64::kPointerDiff:
4111 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
4113 case x86_64::kNoFixUp:
4114 case x86_64::kGroupSubordinate:
4115 case x86_64::kPointer:
4119 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
4120 fSplitCodeToDataContentAtom->setCantEncode();
4125 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4127 switch ( (arm::ReferenceKinds)ref->getKind() ) {
4128 case arm::kPointerDiff:
4129 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4132 case arm::kGroupSubordinate:
4134 case arm::kPointerWeakImport:
4135 case arm::kReadOnlyPointer:
4139 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
4140 fSplitCodeToDataContentAtom->setCantEncode();
4144 template <typename A>
4145 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
4147 switch ( to.getDefinitionKind() ) {
4148 case ObjectFile::Atom::kExternalDefinition:
4149 case ObjectFile::Atom::kExternalWeakDefinition:
4150 case ObjectFile::Atom::kAbsoluteSymbol:
4152 case ObjectFile::Atom::kRegularDefinition:
4153 case ObjectFile::Atom::kWeakDefinition:
4154 case ObjectFile::Atom::kTentativeDefinition:
4155 // segments with same permissions slide together
4156 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
4157 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
4159 throw "ld64 internal error";
4164 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
4167 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
4168 for (uint32_t p=from; p < to; p += 4)
4169 ::pwrite(fd, &ppcNop, 4, p);
4173 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
4176 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
4177 for (uint32_t p=from; p < to; p += 4)
4178 ::pwrite(fd, &ppcNop, 4, p);
4182 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
4184 uint8_t x86Nop = 0x90;
4185 for (uint32_t p=from; p < to; ++p)
4186 ::pwrite(fd, &x86Nop, 1, p);
4190 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
4192 uint8_t x86Nop = 0x90;
4193 for (uint32_t p=from; p < to; ++p)
4194 ::pwrite(fd, &x86Nop, 1, p);
4198 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
4200 // FIXME: need thumb nop?
4202 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
4203 for (uint32_t p=from; p < to; p += 4)
4204 ::pwrite(fd, &armNop, 4, p);
4208 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
4210 for (uint8_t* p=from; p < to; p += 4)
4211 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
4215 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
4217 for (uint8_t* p=from; p < to; p += 4)
4218 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
4222 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
4224 for (uint8_t* p=from; p < to; ++p)
4229 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
4231 for (uint8_t* p=from; p < to; ++p)
4236 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
4238 // fixme: need thumb nop?
4239 for (uint8_t* p=from; p < to; p += 4)
4240 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
4243 static const char* stringName(const char* str)
4245 if ( strncmp(str, "cstring=", 8) == 0) {
4246 static char buffer[1024];
4249 for(const char*s = &str[8]; *s != '\0'; ++s) {
4263 if ( t > &buffer[1020] ) {
4282 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
4283 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
4284 template <> const char* Writer<x86>::getArchString() { return "i386"; }
4285 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
4286 template <> const char* Writer<arm>::getArchString() { return "arm"; }
4288 template <typename A>
4289 void Writer<A>::writeMap()
4291 if ( fOptions.generatedMapPath() != NULL ) {
4292 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
4293 if ( mapFile != NULL ) {
4294 // write output path
4295 fprintf(mapFile, "# Path: %s\n", fFilePath);
4296 // write output architecure
4297 fprintf(mapFile, "# Arch: %s\n", getArchString());
4299 if ( fUUIDAtom != NULL ) {
4300 const uint8_t* uuid = fUUIDAtom->getUUID();
4301 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
4302 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
4303 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
4305 // write table of object files
4306 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
4307 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
4308 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
4309 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4310 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
4311 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4312 if ( ! (*secit)->fVirtualSection ) {
4313 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
4314 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
4315 ObjectFile::Reader* reader = (*ait)->getFile();
4316 uint32_t readerOrdinal = (*ait)->getOrdinal();
4317 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
4318 if ( pos == readerToOrdinal.end() ) {
4319 readerToOrdinal[reader] = readerOrdinal;
4320 ordinalToReader[readerOrdinal] = reader;
4326 fprintf(mapFile, "# Object files:\n");
4327 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
4328 uint32_t fileIndex = 0;
4329 readerToFileOrdinal[this] = fileIndex++;
4330 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
4331 if ( it->first != 0 ) {
4332 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
4333 readerToFileOrdinal[it->second] = fileIndex++;
4336 // write table of sections
4337 fprintf(mapFile, "# Sections:\n");
4338 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
4339 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4340 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
4341 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4342 if ( ! (*secit)->fVirtualSection ) {
4343 SectionInfo* sect = *secit;
4344 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
4345 (*segit)->fName, sect->fSectionName);
4349 // write table of symbols
4350 fprintf(mapFile, "# Symbols:\n");
4351 fprintf(mapFile, "# Address\tSize \tFile Name\n");
4352 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4353 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
4354 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4355 if ( ! (*secit)->fVirtualSection ) {
4356 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
4357 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
4358 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
4359 ObjectFile::Atom* atom = *ait;
4360 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
4361 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
4369 warning("could not write map file: %s\n", fOptions.generatedMapPath());
4374 static const char* sCleanupFile = NULL;
4375 static void cleanup(int sig)
4377 ::signal(sig, SIG_DFL);
4378 if ( sCleanupFile != NULL ) {
4379 ::unlink(sCleanupFile);
4381 if ( sig == SIGINT )
4386 template <typename A>
4387 uint64_t Writer<A>::writeAtoms()
4389 // for UNIX conformance, error if file exists and is not writable
4390 if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
4391 throwf("can't write output file: %s", fFilePath);
4393 int permissions = 0777;
4394 if ( fOptions.outputKind() == Options::kObjectFile )
4396 // Calling unlink first assures the file is gone so that open creates it with correct permissions
4397 // It also handles the case where fFilePath file is not writable but its directory is
4398 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
4399 (void)unlink(fFilePath);
4401 // try to allocate buffer for entire output file content
4403 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
4404 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
4405 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
4406 uint8_t* atomBuffer = NULL;
4407 bool streaming = false;
4408 if ( wholeBuffer == NULL ) {
4409 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
4411 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
4412 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
4414 // install signal handlers to delete output file if program is killed
4415 sCleanupFile = fFilePath;
4416 ::signal(SIGINT, cleanup);
4417 ::signal(SIGBUS, cleanup);
4418 ::signal(SIGSEGV, cleanup);
4423 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4424 SegmentInfo* curSegment = *segit;
4425 bool isTextSeg = (strcmp(curSegment->fName, "__TEXT") == 0);
4426 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4427 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4428 SectionInfo* curSection = *secit;
4429 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
4430 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
4431 //fprintf(stderr, "writing %lu atoms for section %s\n", sectionAtoms.size(), curSection->fSectionName);
4432 if ( ! curSection->fAllZeroFill ) {
4433 end = curSection->fFileOffset;
4434 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
4435 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
4436 ObjectFile::Atom* atom = *ait;
4437 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
4438 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
4439 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
4440 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
4441 if ( fileOffset != end ) {
4443 // fill gaps with no-ops
4445 writeNoOps(fd, end, fileOffset);
4447 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
4449 else if ( streaming ) {
4451 if ( (fileOffset-end) == 4 ) {
4453 ::pwrite(fd, &zero, 4, end);
4456 uint8_t zero = 0x00;
4457 for (uint32_t p=end; p < fileOffset; ++p)
4458 ::pwrite(fd, &zero, 1, p);
4462 uint64_t atomSize = atom->getSize();
4464 if ( atomSize > fLargestAtomSize )
4465 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
4466 atom->getDisplayName(), atomSize, fLargestAtomSize);
4469 if ( fileOffset > fileBufferSize )
4470 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
4471 atom->getDisplayName(), fileOffset, fileBufferSize);
4473 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
4474 end = fileOffset+atomSize;
4476 atom->copyRawContent(buffer);
4477 // apply any fix-ups
4479 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4480 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
4481 ObjectFile::Reference* ref = *it;
4482 if ( fOptions.outputKind() == Options::kObjectFile ) {
4484 // skip fix-ups for undefined targets
4485 if ( &(ref->getTarget()) != NULL )
4486 this->fixUpReferenceRelocatable(ref, atom, buffer);
4489 // producing final linked image
4490 this->fixUpReferenceFinal(ref, atom, buffer);
4494 catch (const char* msg) {
4495 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
4497 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
4498 // fileOffset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
4501 ::pwrite(fd, buffer, atomSize, fileOffset);
4504 if ( (fileOffset + atomSize) > size )
4505 size = fileOffset + atomSize;
4513 // update content based UUID
4514 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
4515 uint8_t digest[CC_MD5_DIGEST_LENGTH];
4517 // if output file file did not fit in memory, re-read file to generate md5 hash
4518 uint32_t kMD5BufferSize = 16*1024;
4519 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
4520 if ( md5Buffer != NULL ) {
4521 CC_MD5_CTX md5State;
4522 CC_MD5_Init(&md5State);
4523 ::lseek(fd, 0, SEEK_SET);
4525 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
4526 CC_MD5_Update(&md5State, md5Buffer, len);
4527 CC_MD5_Final(digest, &md5State);
4531 // if malloc fails, fall back to random uuid
4532 ::uuid_generate_random(digest);
4534 fUUIDAtom->setContent(digest);
4535 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
4536 fUUIDAtom->copyRawContent(atomBuffer);
4537 ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
4540 // if output file fit in memory, just genrate an md5 hash in memory
4542 // temp hack for building on Tiger
4543 CC_MD5_CTX md5State;
4544 CC_MD5_Init(&md5State);
4545 CC_MD5_Update(&md5State, wholeBuffer, size);
4546 CC_MD5_Final(digest, &md5State);
4548 CC_MD5(wholeBuffer, size, digest);
4550 fUUIDAtom->setContent(digest);
4551 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
4552 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
4557 if ( sCleanupFile != NULL )
4558 ::unlink(sCleanupFile);
4564 delete [] atomBuffer;
4566 // restore default signal handlers
4567 sCleanupFile = NULL;
4568 ::signal(SIGINT, SIG_DFL);
4569 ::signal(SIGBUS, SIG_DFL);
4570 ::signal(SIGSEGV, SIG_DFL);
4573 // write whole output file in one chunk
4574 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
4576 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
4577 ::pwrite(fd, wholeBuffer, size, 0);
4579 delete [] wholeBuffer;
4586 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4588 int64_t displacement;
4590 uint32_t instruction;
4591 uint32_t newInstruction;
4592 uint64_t targetAddr = 0;
4596 bool relocateableExternal = false;
4601 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4602 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4603 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
4606 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4607 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
4609 case arm::kFollowOn:
4610 case arm::kGroupSubordinate:
4613 case arm::kPointerWeakImport:
4615 // If this is the lazy pointers section, then set all lazy pointers to
4616 // point to the dyld stub binding helper.
4617 if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers
4618 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
4619 switch (ref->getTarget().getDefinitionKind()) {
4620 case ObjectFile::Atom::kExternalDefinition:
4621 case ObjectFile::Atom::kExternalWeakDefinition:
4622 // prebound lazy pointer to another dylib ==> pointer contains zero
4623 LittleEndian::set32(*fixUp, 0);
4625 case ObjectFile::Atom::kTentativeDefinition:
4626 case ObjectFile::Atom::kRegularDefinition:
4627 case ObjectFile::Atom::kWeakDefinition:
4628 case ObjectFile::Atom::kAbsoluteSymbol:
4629 // prebound lazy pointer to withing this dylib ==> pointer contains address
4630 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
4632 LittleEndian::set32(*fixUp, targetAddr);
4636 else if ( relocateableExternal ) {
4637 if ( fOptions.prebind() ) {
4638 switch (ref->getTarget().getDefinitionKind()) {
4639 case ObjectFile::Atom::kExternalDefinition:
4640 case ObjectFile::Atom::kExternalWeakDefinition:
4641 // prebound external relocation ==> pointer contains addend
4642 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4644 case ObjectFile::Atom::kTentativeDefinition:
4645 case ObjectFile::Atom::kRegularDefinition:
4646 case ObjectFile::Atom::kWeakDefinition:
4647 // prebound external relocation to internal atom ==> pointer contains target address + addend
4648 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
4650 LittleEndian::set32(*fixUp, targetAddr);
4652 case ObjectFile::Atom::kAbsoluteSymbol:
4657 // external relocation ==> pointer contains addend
4658 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4662 // pointer contains target address
4663 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
4665 LittleEndian::set32(*fixUp, targetAddr);
4668 case arm::kPointerDiff:
4669 LittleEndian::set32(*fixUp,
4670 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4672 case arm::kReadOnlyPointer:
4673 switch ( ref->getTarget().getDefinitionKind() ) {
4674 case ObjectFile::Atom::kRegularDefinition:
4675 case ObjectFile::Atom::kWeakDefinition:
4676 case ObjectFile::Atom::kTentativeDefinition:
4677 // pointer contains target address
4678 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4680 case ObjectFile::Atom::kExternalDefinition:
4681 case ObjectFile::Atom::kExternalWeakDefinition:
4682 // external relocation ==> pointer contains addend
4683 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4685 case ObjectFile::Atom::kAbsoluteSymbol:
4686 // pointer contains target address
4687 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
4691 case arm::kBranch24WeakImport:
4692 case arm::kBranch24:
4693 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4694 // The pc added will be +8 from the pc
4696 // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
4697 // max positive displacement is 0x007FFFFF << 2
4698 // max negative displacement is 0xFF800000 << 2
4699 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
4700 throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
4701 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4702 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4704 instruction = LittleEndian::get32(*fixUp);
4705 // Make sure we are calling arm with bl, thumb with blx
4706 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
4707 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
4708 if ( is_bl && ref->getTarget().isThumb() ) {
4709 uint32_t opcode = 0xFA000000;
4710 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4711 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
4712 newInstruction = opcode | h_bit | disp;
4714 else if ( is_blx && !ref->getTarget().isThumb() ) {
4715 uint32_t opcode = 0xEB000000;
4716 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4717 newInstruction = opcode | disp;
4719 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
4720 throwf("don't know how to convert instruction %x referencing %s to thumb",
4721 instruction, ref->getTarget().getDisplayName());
4724 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
4726 LittleEndian::set32(*fixUp, newInstruction);
4728 case arm::kThumbBranch22WeakImport:
4729 case arm::kThumbBranch22:
4730 instruction = LittleEndian::get32(*fixUp);
4731 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
4732 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
4733 targetIsThumb = ref->getTarget().isThumb();
4735 // The pc added will be +4 from the pc
4736 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
4737 // If the target is not thumb, we will be generating a blx instruction
4738 // Since blx cannot have the low bit set, set bit[1] of the target to
4739 // bit[1] of the base address, so that the difference is a multiple of
4741 if ( !targetIsThumb ) {
4742 targetAddr &= -3ULL;
4743 targetAddr |= (baseAddr & 2LL);
4745 displacement = targetAddr - baseAddr;
4747 // max positive displacement is 0x003FFFFE
4748 // max negative displacement is 0xFFC00000
4749 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
4750 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
4751 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4752 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4754 // The instruction is really two instructions:
4755 // The lower 16 bits are the first instruction, which contains the first
4756 // 11 bits of the displacement.
4757 // The upper 16 bits are the second instruction, which contains the next
4758 // 11 bits of the displacement, as well as differentiating bl and blx.
4760 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
4761 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
4762 if ( is_bl && !targetIsThumb ) {
4763 opcode = 0xE800F000;
4765 else if ( is_blx && targetIsThumb ) {
4766 opcode = 0xF800F000;
4768 else if ( !is_bl && !is_blx && !targetIsThumb ) {
4769 throwf("don't know how to convert instruction %x referencing %s to arm",
4770 instruction, ref->getTarget().getDisplayName());
4773 opcode = instruction & 0xF800F800;
4775 newInstruction = opcode | (nextDisp << 16) | firstDisp;
4776 LittleEndian::set32(*fixUp, newInstruction);
4779 case arm::kDtraceProbeSite:
4780 case arm::kDtraceIsEnabledSite:
4781 if ( inAtom->isThumb() ) {
4782 // change 32-bit blx call site to two thumb NOPs
4783 LittleEndian::set32(*fixUp, 0x46C046C0);
4786 // change call site to a NOP
4787 LittleEndian::set32(*fixUp, 0xE1A00000);
4790 case arm::kDtraceTypeReference:
4791 case arm::kDtraceProbe:
4792 // nothing to fix up
4795 throw "boom shaka laka";
4800 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4802 int64_t displacement;
4803 uint32_t instruction;
4804 uint32_t newInstruction;
4805 uint64_t targetAddr = 0;
4810 bool relocateableExternal = false;
4815 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4816 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4817 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
4820 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4821 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
4823 case arm::kFollowOn:
4824 case arm::kGroupSubordinate:
4828 case arm::kReadOnlyPointer:
4829 case arm::kPointerWeakImport:
4831 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4832 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
4833 if ( this->indirectSymbolIsLocal(ref) )
4834 LittleEndian::set32(*fixUp, targetAddr);
4836 LittleEndian::set32(*fixUp, 0);
4838 else if ( relocateableExternal ) {
4839 if ( fOptions.prebind() ) {
4840 switch (ref->getTarget().getDefinitionKind()) {
4841 case ObjectFile::Atom::kExternalDefinition:
4842 case ObjectFile::Atom::kExternalWeakDefinition:
4843 // prebound external relocation ==> pointer contains addend
4844 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4846 case ObjectFile::Atom::kTentativeDefinition:
4847 case ObjectFile::Atom::kRegularDefinition:
4848 case ObjectFile::Atom::kWeakDefinition:
4849 // prebound external relocation to internal atom ==> pointer contains target address + addend
4850 LittleEndian::set32(*fixUp, targetAddr);
4852 case ObjectFile::Atom::kAbsoluteSymbol:
4858 // internal relocation
4859 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
4860 // pointer contains target address
4861 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
4863 LittleEndian::set32(*fixUp, targetAddr);
4866 // pointer contains addend
4867 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4872 case arm::kPointerDiff:
4873 LittleEndian::set32(*fixUp,
4874 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4876 case arm::kDtraceProbeSite:
4877 case arm::kDtraceIsEnabledSite:
4878 case arm::kBranch24WeakImport:
4879 case arm::kBranch24:
4880 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4881 // The pc added will be +8 from the pc
4883 // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
4884 if ( relocateableExternal ) {
4885 // doing "ld -r" to an external symbol
4886 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4887 displacement -= ref->getTarget().getAddress();
4890 // max positive displacement is 0x007FFFFF << 2
4891 // max negative displacement is 0xFF800000 << 2
4892 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
4893 throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
4894 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4895 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4898 instruction = LittleEndian::get32(*fixUp);
4899 // Make sure we are calling arm with bl, thumb with blx
4900 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
4901 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
4902 if ( is_bl && ref->getTarget().isThumb() ) {
4903 uint32_t opcode = 0xFA000000;
4904 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4905 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
4906 newInstruction = opcode | h_bit | disp;
4908 else if ( is_blx && !ref->getTarget().isThumb() ) {
4909 uint32_t opcode = 0xEB000000;
4910 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4911 newInstruction = opcode | disp;
4913 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
4914 throwf("don't know how to convert instruction %x referencing %s to thumb",
4915 instruction, ref->getTarget().getDisplayName());
4918 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
4920 LittleEndian::set32(*fixUp, newInstruction);
4922 case arm::kThumbBranch22WeakImport:
4923 case arm::kThumbBranch22:
4924 instruction = LittleEndian::get32(*fixUp);
4925 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
4926 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
4927 targetIsThumb = ref->getTarget().isThumb();
4929 // The pc added will be +4 from the pc
4930 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
4931 // If the target is not thumb, we will be generating a blx instruction
4932 // Since blx cannot have the low bit set, set bit[1] of the target to
4933 // bit[1] of the base address, so that the difference is a multiple of
4935 if (!targetIsThumb) {
4936 targetAddr &= -3ULL;
4937 targetAddr |= (baseAddr & 2LL);
4939 displacement = targetAddr - baseAddr;
4941 //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);
4942 if ( relocateableExternal ) {
4943 // doing "ld -r" to an external symbol
4944 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4945 displacement -= ref->getTarget().getAddress();
4948 // max positive displacement is 0x003FFFFE
4949 // max negative displacement is 0xFFC00000
4950 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
4951 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
4952 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4953 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4956 // The instruction is really two instructions:
4957 // The lower 16 bits are the first instruction, which contains the first
4958 // 11 bits of the displacement.
4959 // The upper 16 bits are the second instruction, which contains the next
4960 // 11 bits of the displacement, as well as differentiating bl and blx.
4961 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
4962 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
4963 if ( is_bl && !targetIsThumb ) {
4964 opcode = 0xE800F000;
4966 else if ( is_blx && targetIsThumb ) {
4967 opcode = 0xF800F000;
4969 else if ( !is_bl && !is_blx && !targetIsThumb ) {
4970 throwf("don't know how to convert instruction %x referencing %s to arm",
4971 instruction, ref->getTarget().getDisplayName());
4974 opcode = instruction & 0xF800F800;
4976 newInstruction = opcode | (nextDisp << 16) | firstDisp;
4977 LittleEndian::set32(*fixUp, newInstruction);
4979 case arm::kDtraceProbe:
4980 case arm::kDtraceTypeReference:
4981 // nothing to fix up
4987 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4989 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4990 uint8_t* dtraceProbeSite;
4991 const int64_t kTwoGigLimit = 0x7FFFFFFF;
4992 const int64_t kSixtyFourKiloLimit = 0x7FFF;
4993 const int64_t kOneTwentyEightLimit = 0x7F;
4994 int64_t displacement;
4995 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
4998 case x86::kFollowOn:
4999 case x86::kGroupSubordinate:
5002 case x86::kPointerWeakImport:
5005 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
5006 if ( fOptions.prebind() ) {
5007 switch (ref->getTarget().getDefinitionKind()) {
5008 case ObjectFile::Atom::kExternalDefinition:
5009 case ObjectFile::Atom::kExternalWeakDefinition:
5010 // prebound external relocation ==> pointer contains addend
5011 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5013 case ObjectFile::Atom::kTentativeDefinition:
5014 case ObjectFile::Atom::kRegularDefinition:
5015 case ObjectFile::Atom::kWeakDefinition:
5016 // prebound external relocation to internal atom ==> pointer contains target address + addend
5017 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5019 case ObjectFile::Atom::kAbsoluteSymbol:
5024 // external relocation ==> pointer contains addend
5025 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5029 // pointer contains target address
5030 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
5031 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5035 case x86::kPointerDiff:
5036 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5037 LittleEndian::set32(*fixUp, (uint32_t)displacement);
5039 case x86::kPointerDiff16:
5040 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5041 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
5042 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
5043 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
5045 case x86::kDtraceProbeSite:
5046 // change call site to a NOP
5047 dtraceProbeSite = (uint8_t*)fixUp;
5048 dtraceProbeSite[-1] = 0x90; // 1-byte nop
5049 dtraceProbeSite[0] = 0x0F; // 4-byte nop
5050 dtraceProbeSite[1] = 0x1F;
5051 dtraceProbeSite[2] = 0x40;
5052 dtraceProbeSite[3] = 0x00;
5054 case x86::kDtraceIsEnabledSite:
5055 // change call site to a clear eax
5056 dtraceProbeSite = (uint8_t*)fixUp;
5057 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
5058 dtraceProbeSite[0] = 0xC0;
5059 dtraceProbeSite[1] = 0x90; // 1-byte nop
5060 dtraceProbeSite[2] = 0x90; // 1-byte nop
5061 dtraceProbeSite[3] = 0x90; // 1-byte nop
5063 case x86::kPCRel32WeakImport:
5068 switch ( ref->getTarget().getDefinitionKind() ) {
5069 case ObjectFile::Atom::kRegularDefinition:
5070 case ObjectFile::Atom::kWeakDefinition:
5071 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5073 case ObjectFile::Atom::kExternalDefinition:
5074 case ObjectFile::Atom::kExternalWeakDefinition:
5075 throw "codegen problem, can't use rel32 to external symbol";
5076 case ObjectFile::Atom::kTentativeDefinition:
5079 case ObjectFile::Atom::kAbsoluteSymbol:
5080 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5083 if ( kind == x86::kPCRel8 ) {
5084 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
5085 //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());
5086 throwf("rel8 out of range in %s", inAtom->getDisplayName());
5088 *(int8_t*)fixUp = (int8_t)displacement;
5090 else if ( kind == x86::kPCRel16 ) {
5091 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
5092 //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());
5093 throwf("rel16 out of range in %s", inAtom->getDisplayName());
5095 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
5098 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
5099 //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());
5100 throwf("rel32 out of range in %s", inAtom->getDisplayName());
5102 LittleEndian::set32(*fixUp, (int32_t)displacement);
5105 case x86::kAbsolute32:
5106 switch ( ref->getTarget().getDefinitionKind() ) {
5107 case ObjectFile::Atom::kRegularDefinition:
5108 case ObjectFile::Atom::kWeakDefinition:
5109 case ObjectFile::Atom::kTentativeDefinition:
5110 // pointer contains target address
5111 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5113 case ObjectFile::Atom::kExternalDefinition:
5114 case ObjectFile::Atom::kExternalWeakDefinition:
5115 // external relocation ==> pointer contains addend
5116 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5118 case ObjectFile::Atom::kAbsoluteSymbol:
5119 // pointer contains target address
5120 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
5124 case x86::kDtraceTypeReference:
5125 case x86::kDtraceProbe:
5126 // nothing to fix up
5134 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5136 const int64_t kTwoGigLimit = 0x7FFFFFFF;
5137 const int64_t kSixtyFourKiloLimit = 0x7FFF;
5138 const int64_t kOneTwentyEightLimit = 0x7F;
5139 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
5140 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
5141 int64_t displacement;
5142 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
5145 case x86::kFollowOn:
5146 case x86::kGroupSubordinate:
5150 case x86::kPointerWeakImport:
5151 case x86::kAbsolute32:
5154 // external relocation ==> pointer contains addend
5155 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5157 else if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
5158 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
5159 if ( this->indirectSymbolIsLocal(ref) )
5160 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5162 LittleEndian::set32(*fixUp, 0);
5164 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
5165 // internal relocation => pointer contains target address
5166 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5169 // internal relocation to tentative ==> pointer contains addend
5170 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5174 case x86::kPointerDiff:
5175 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5176 LittleEndian::set32(*fixUp, (uint32_t)displacement);
5178 case x86::kPointerDiff16:
5179 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5180 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
5181 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
5182 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
5187 case x86::kPCRel32WeakImport:
5188 case x86::kDtraceProbeSite:
5189 case x86::kDtraceIsEnabledSite:
5192 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5194 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5195 if ( kind == x86::kPCRel8 ) {
5197 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
5198 //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());
5199 throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
5201 int8_t byte = (int8_t)displacement;
5202 *((int8_t*)fixUp) = byte;
5204 else if ( kind == x86::kPCRel16 ) {
5206 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
5207 //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());
5208 throwf("rel16 out of range in %s", inAtom->getDisplayName());
5210 int16_t word = (int16_t)displacement;
5211 LittleEndian::set16(*((uint16_t*)fixUp), word);
5214 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
5215 //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement,
5216 // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
5217 throwf("rel32 out of range in %s", inAtom->getDisplayName());
5219 LittleEndian::set32(*fixUp, (int32_t)displacement);
5223 case x86::kDtraceProbe:
5224 case x86::kDtraceTypeReference:
5225 // nothing to fix up
5231 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5233 const int64_t twoGigLimit = 0x7FFFFFFF;
5234 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
5235 uint8_t* dtraceProbeSite;
5236 int64_t displacement = 0;
5237 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
5238 case x86_64::kNoFixUp:
5239 case x86_64::kFollowOn:
5240 case x86_64::kGroupSubordinate:
5243 case x86_64::kPointerWeakImport:
5244 case x86_64::kPointer:
5246 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
5247 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
5248 // external relocation ==> pointer contains addend
5249 LittleEndian::set64(*fixUp, ref->getTargetOffset());
5252 // internal relocation
5253 // pointer contains target address
5254 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
5255 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5259 case x86_64::kPointerDiff32:
5260 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5261 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
5262 throw "32-bit pointer difference out of range";
5263 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
5265 case x86_64::kPointerDiff:
5266 LittleEndian::set64(*fixUp,
5267 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5269 case x86_64::kPCRel32GOTLoad:
5270 case x86_64::kPCRel32GOTLoadWeakImport:
5271 // if GOT entry was optimized away, change movq instruction to a leaq
5272 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
5273 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
5274 uint8_t* opcodes = (uint8_t*)fixUp;
5275 if ( opcodes[-2] != 0x8B )
5276 throw "GOT load reloc does not point to a movq instruction";
5279 // fall into general rel32 case
5280 case x86_64::kBranchPCRel32WeakImport:
5281 case x86_64::kBranchPCRel32:
5282 case x86_64::kBranchPCRel8:
5283 case x86_64::kPCRel32:
5284 case x86_64::kPCRel32_1:
5285 case x86_64::kPCRel32_2:
5286 case x86_64::kPCRel32_4:
5287 case x86_64::kPCRel32GOT:
5288 case x86_64::kPCRel32GOTWeakImport:
5289 switch ( ref->getTarget().getDefinitionKind() ) {
5290 case ObjectFile::Atom::kRegularDefinition:
5291 case ObjectFile::Atom::kWeakDefinition:
5292 case ObjectFile::Atom::kTentativeDefinition:
5293 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5295 case ObjectFile::Atom::kAbsoluteSymbol:
5296 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5298 case ObjectFile::Atom::kExternalDefinition:
5299 case ObjectFile::Atom::kExternalWeakDefinition:
5300 throw "codegen problem, can't use rel32 to external symbol";
5303 switch ( ref->getKind() ) {
5304 case x86_64::kPCRel32_1:
5307 case x86_64::kPCRel32_2:
5310 case x86_64::kPCRel32_4:
5313 case x86_64::kBranchPCRel8:
5317 if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
5318 if ( (displacement > 127) || (displacement < (-128)) ) {
5319 fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n",
5320 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
5321 throw "rel8 out of range";
5323 *((int8_t*)fixUp) = (int8_t)displacement;
5326 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
5327 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
5328 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
5329 throw "rel32 out of range";
5331 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
5334 case x86_64::kDtraceProbeSite:
5335 // change call site to a NOP
5336 dtraceProbeSite = (uint8_t*)fixUp;
5337 dtraceProbeSite[-1] = 0x90; // 1-byte nop
5338 dtraceProbeSite[0] = 0x0F; // 4-byte nop
5339 dtraceProbeSite[1] = 0x1F;
5340 dtraceProbeSite[2] = 0x40;
5341 dtraceProbeSite[3] = 0x00;
5343 case x86_64::kDtraceIsEnabledSite:
5344 // change call site to a clear eax
5345 dtraceProbeSite = (uint8_t*)fixUp;
5346 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
5347 dtraceProbeSite[0] = 0x33;
5348 dtraceProbeSite[1] = 0xC0;
5349 dtraceProbeSite[2] = 0x90; // 1-byte nop
5350 dtraceProbeSite[3] = 0x90; // 1-byte nop
5352 case x86_64::kDtraceTypeReference:
5353 case x86_64::kDtraceProbe:
5354 // nothing to fix up
5360 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5362 const int64_t twoGigLimit = 0x7FFFFFFF;
5363 bool external = this->makesExternalRelocatableReference(ref->getTarget());
5364 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
5365 int64_t displacement = 0;
5367 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
5368 case x86_64::kNoFixUp:
5369 case x86_64::kFollowOn:
5370 case x86_64::kGroupSubordinate:
5373 case x86_64::kPointer:
5374 case x86_64::kPointerWeakImport:
5377 // external relocation ==> pointer contains addend
5378 LittleEndian::set64(*fixUp, ref->getTargetOffset());
5381 // internal relocation ==> pointer contains target address
5382 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5386 case x86_64::kPointerDiff32:
5387 // addend in content
5388 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
5390 case x86_64::kPointerDiff:
5391 // addend in content
5392 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
5394 case x86_64::kBranchPCRel32:
5395 case x86_64::kBranchPCRel32WeakImport:
5396 case x86_64::kDtraceProbeSite:
5397 case x86_64::kDtraceIsEnabledSite:
5398 case x86_64::kPCRel32:
5399 case x86_64::kPCRel32_1:
5400 case x86_64::kPCRel32_2:
5401 case x86_64::kPCRel32_4:
5402 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
5403 temp32 = ref->getTargetOffset();
5405 // extern relocation contains addend
5406 displacement = temp32;
5409 // internal relocations contain delta to target address
5410 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5412 switch ( ref->getKind() ) {
5413 case x86_64::kPCRel32_1:
5416 case x86_64::kPCRel32_2:
5419 case x86_64::kPCRel32_4:
5423 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
5424 //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());
5425 throw "rel32 out of range";
5427 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
5429 case x86_64::kBranchPCRel8:
5430 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
5431 temp32 = ref->getTargetOffset();
5433 // extern relocation contains addend
5434 displacement = temp32;
5437 // internal relocations contain delta to target address
5438 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
5440 if ( (displacement > 127) || (displacement < (-128)) ) {
5441 //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());
5442 throw "rel8 out of range";
5444 *((int8_t*)fixUp) = (int8_t)displacement;
5446 case x86_64::kPCRel32GOT:
5447 case x86_64::kPCRel32GOTLoad:
5448 case x86_64::kPCRel32GOTWeakImport:
5449 case x86_64::kPCRel32GOTLoadWeakImport:
5450 // contains addend (usually zero)
5451 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
5453 case x86_64::kDtraceTypeReference:
5454 case x86_64::kDtraceProbe:
5455 // nothing to fix up
5461 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5463 fixUpReference_powerpc(ref, inAtom, buffer, true);
5467 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5469 fixUpReference_powerpc(ref, inAtom, buffer, true);
5473 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5475 fixUpReference_powerpc(ref, inAtom, buffer, false);
5479 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5481 fixUpReference_powerpc(ref, inAtom, buffer, false);
5485 // ppc and ppc64 are mostly the same, so they share a template specialzation
5487 template <typename A>
5488 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
5490 uint32_t instruction;
5491 uint32_t newInstruction;
5492 int64_t displacement;
5493 uint64_t targetAddr = 0;
5494 uint64_t picBaseAddr;
5495 uint16_t instructionLowHalf;
5496 uint16_t instructionHighHalf;
5497 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
5498 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
5499 bool relocateableExternal = false;
5500 const int64_t picbase_twoGigLimit = 0x80000000;
5502 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
5503 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
5504 if ( finalLinkedImage )
5505 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
5507 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
5510 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
5513 case A::kGroupSubordinate:
5516 case A::kPointerWeakImport:
5519 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
5520 if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers
5521 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
5522 switch (ref->getTarget().getDefinitionKind()) {
5523 case ObjectFile::Atom::kExternalDefinition:
5524 case ObjectFile::Atom::kExternalWeakDefinition:
5525 // prebound lazy pointer to another dylib ==> pointer contains zero
5526 P::setP(*fixUpPointer, 0);
5528 case ObjectFile::Atom::kTentativeDefinition:
5529 case ObjectFile::Atom::kRegularDefinition:
5530 case ObjectFile::Atom::kWeakDefinition:
5531 case ObjectFile::Atom::kAbsoluteSymbol:
5532 // prebound lazy pointer to withing this dylib ==> pointer contains address
5533 P::setP(*fixUpPointer, targetAddr);
5537 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
5538 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
5539 if ( this->indirectSymbolIsLocal(ref) )
5540 P::setP(*fixUpPointer, targetAddr);
5542 P::setP(*fixUpPointer, 0);
5544 else if ( relocateableExternal ) {
5545 if ( fOptions.prebind() ) {
5546 switch (ref->getTarget().getDefinitionKind()) {
5547 case ObjectFile::Atom::kExternalDefinition:
5548 case ObjectFile::Atom::kExternalWeakDefinition:
5549 // prebound external relocation ==> pointer contains addend
5550 P::setP(*fixUpPointer, ref->getTargetOffset());
5552 case ObjectFile::Atom::kTentativeDefinition:
5553 case ObjectFile::Atom::kRegularDefinition:
5554 case ObjectFile::Atom::kWeakDefinition:
5555 // prebound external relocation to internal atom ==> pointer contains target address + addend
5556 P::setP(*fixUpPointer, targetAddr);
5558 case ObjectFile::Atom::kAbsoluteSymbol:
5563 // external relocation ==> pointer contains addend
5564 P::setP(*fixUpPointer, ref->getTargetOffset());
5568 // internal relocation
5569 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
5570 // pointer contains target address
5571 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
5572 P::setP(*fixUpPointer, targetAddr);
5575 // pointer contains addend
5576 P::setP(*fixUpPointer, ref->getTargetOffset());
5581 case A::kPointerDiff64:
5582 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5584 case A::kPointerDiff32:
5585 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5587 case A::kPointerDiff16:
5588 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5590 case A::kDtraceProbeSite:
5591 if ( finalLinkedImage ) {
5592 // change call site to a NOP
5593 BigEndian::set32(*fixUp, 0x60000000);
5596 // set bl instuction to branch to address zero in .o file
5597 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
5598 instruction = BigEndian::get32(*fixUp);
5599 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
5600 BigEndian::set32(*fixUp, newInstruction);
5603 case A::kDtraceIsEnabledSite:
5604 if ( finalLinkedImage ) {
5605 // change call site to a li r3,0
5606 BigEndian::set32(*fixUp, 0x38600000);
5609 // set bl instuction to branch to address zero in .o file
5610 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
5611 instruction = BigEndian::get32(*fixUp);
5612 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
5613 BigEndian::set32(*fixUp, newInstruction);
5616 case A::kBranch24WeakImport:
5619 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
5620 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
5621 if ( relocateableExternal ) {
5622 // doing "ld -r" to an external symbol
5623 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
5624 displacement -= ref->getTarget().getAddress();
5627 const int64_t bl_eightMegLimit = 0x00FFFFFF;
5628 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
5629 //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());
5630 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",
5631 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
5632 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
5635 instruction = BigEndian::get32(*fixUp);
5636 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
5637 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
5638 BigEndian::set32(*fixUp, newInstruction);
5643 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
5644 if ( relocateableExternal ) {
5645 // doing "ld -r" to an external symbol
5646 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
5647 displacement -= ref->getTarget().getAddress();
5649 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
5650 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
5651 //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());
5652 throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
5653 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
5654 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
5657 //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
5658 instruction = BigEndian::get32(*fixUp);
5659 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
5660 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
5661 BigEndian::set32(*fixUp, newInstruction);
5664 case A::kPICBaseLow16:
5665 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
5666 displacement = targetAddr - picBaseAddr;
5667 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
5668 throw "32-bit pic-base out of range";
5669 instructionLowHalf = (displacement & 0xFFFF);
5670 instruction = BigEndian::get32(*fixUp);
5671 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
5672 BigEndian::set32(*fixUp, newInstruction);
5674 case A::kPICBaseLow14:
5675 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
5676 displacement = targetAddr - picBaseAddr;
5677 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
5678 throw "32-bit pic-base out of range";
5679 if ( (displacement & 0x3) != 0 )
5680 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
5681 instructionLowHalf = (displacement & 0xFFFC);
5682 instruction = BigEndian::get32(*fixUp);
5683 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
5684 BigEndian::set32(*fixUp, newInstruction);
5686 case A::kPICBaseHigh16:
5687 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
5688 displacement = targetAddr - picBaseAddr;
5689 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
5690 throw "32-bit pic-base out of range";
5691 instructionLowHalf = displacement >> 16;
5692 if ( (displacement & 0x00008000) != 0 )
5693 ++instructionLowHalf;
5694 instruction = BigEndian::get32(*fixUp);
5695 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
5696 BigEndian::set32(*fixUp, newInstruction);
5699 if ( relocateableExternal && !finalLinkedImage )
5700 targetAddr -= ref->getTarget().getAddress();
5701 instructionLowHalf = (targetAddr & 0xFFFF);
5702 instruction = BigEndian::get32(*fixUp);
5703 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
5704 BigEndian::set32(*fixUp, newInstruction);
5707 if ( relocateableExternal && !finalLinkedImage )
5708 targetAddr -= ref->getTarget().getAddress();
5709 if ( (targetAddr & 0x3) != 0 )
5710 throw "bad address for absolute lo14 instruction fix-up";
5711 instructionLowHalf = (targetAddr & 0xFFFF);
5712 instruction = BigEndian::get32(*fixUp);
5713 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
5714 BigEndian::set32(*fixUp, newInstruction);
5717 if ( relocateableExternal ) {
5718 if ( finalLinkedImage ) {
5719 switch (ref->getTarget().getDefinitionKind()) {
5720 case ObjectFile::Atom::kExternalDefinition:
5721 case ObjectFile::Atom::kExternalWeakDefinition:
5722 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
5724 case ObjectFile::Atom::kTentativeDefinition:
5725 case ObjectFile::Atom::kRegularDefinition:
5726 case ObjectFile::Atom::kWeakDefinition:
5727 // use target address
5729 case ObjectFile::Atom::kAbsoluteSymbol:
5730 targetAddr = ref->getTarget().getSectionOffset();
5735 targetAddr -= ref->getTarget().getAddress();
5738 instructionHighHalf = (targetAddr >> 16);
5739 instruction = BigEndian::get32(*fixUp);
5740 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
5741 BigEndian::set32(*fixUp, newInstruction);
5743 case A::kAbsHigh16AddLow:
5744 if ( relocateableExternal ) {
5745 if ( finalLinkedImage ) {
5746 switch (ref->getTarget().getDefinitionKind()) {
5747 case ObjectFile::Atom::kExternalDefinition:
5748 case ObjectFile::Atom::kExternalWeakDefinition:
5749 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
5751 case ObjectFile::Atom::kTentativeDefinition:
5752 case ObjectFile::Atom::kRegularDefinition:
5753 case ObjectFile::Atom::kWeakDefinition:
5754 // use target address
5756 case ObjectFile::Atom::kAbsoluteSymbol:
5757 targetAddr = ref->getTarget().getSectionOffset();
5762 targetAddr -= ref->getTarget().getAddress();
5765 if ( targetAddr & 0x00008000 )
5766 targetAddr += 0x00010000;
5767 instruction = BigEndian::get32(*fixUp);
5768 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
5769 BigEndian::set32(*fixUp, newInstruction);
5771 case A::kDtraceTypeReference:
5772 case A::kDtraceProbe:
5773 // nothing to fix up
5779 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5781 uint8_t kind = ref->getKind();
5782 switch ( (ppc::ReferenceKinds)kind ) {
5784 case ppc::kFollowOn:
5785 case ppc::kGroupSubordinate:
5787 case ppc::kPointerWeakImport:
5788 case ppc::kPointerDiff16:
5789 case ppc::kPointerDiff32:
5790 case ppc::kPointerDiff64:
5791 case ppc::kDtraceProbe:
5792 case ppc::kDtraceProbeSite:
5793 case ppc::kDtraceIsEnabledSite:
5794 case ppc::kDtraceTypeReference:
5795 // these are never used to call external functions
5797 case ppc::kBranch24:
5798 case ppc::kBranch24WeakImport:
5799 case ppc::kBranch14:
5800 // these are used to call external functions
5802 case ppc::kPICBaseLow16:
5803 case ppc::kPICBaseLow14:
5804 case ppc::kPICBaseHigh16:
5805 case ppc::kAbsLow16:
5806 case ppc::kAbsLow14:
5807 case ppc::kAbsHigh16:
5808 case ppc::kAbsHigh16AddLow:
5809 // these are only used to call external functions
5810 // in -mlong-branch stubs
5811 switch ( ref->getTarget().getDefinitionKind() ) {
5812 case ObjectFile::Atom::kExternalDefinition:
5813 case ObjectFile::Atom::kExternalWeakDefinition:
5814 // if the .o file this atom came from has long-branch stubs,
5815 // then assume these instructions in a stub.
5816 // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
5817 return ( inAtom->getFile()->hasLongBranchStubs() );
5818 case ObjectFile::Atom::kTentativeDefinition:
5819 case ObjectFile::Atom::kRegularDefinition:
5820 case ObjectFile::Atom::kWeakDefinition:
5821 case ObjectFile::Atom::kAbsoluteSymbol:
5830 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5832 uint8_t kind = ref->getKind();
5833 switch ( (arm::ReferenceKinds)kind ) {
5834 case arm::kBranch24:
5835 case arm::kBranch24WeakImport:
5836 case arm::kThumbBranch22:
5837 case arm::kThumbBranch22WeakImport:
5840 case arm::kFollowOn:
5841 case arm::kGroupSubordinate:
5843 case arm::kReadOnlyPointer:
5844 case arm::kPointerWeakImport:
5845 case arm::kPointerDiff:
5846 case arm::kDtraceProbe:
5847 case arm::kDtraceProbeSite:
5848 case arm::kDtraceIsEnabledSite:
5849 case arm::kDtraceTypeReference:
5856 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5858 uint8_t kind = ref->getKind();
5859 switch ( (ppc64::ReferenceKinds)kind ) {
5861 case ppc::kFollowOn:
5862 case ppc::kGroupSubordinate:
5864 case ppc::kPointerWeakImport:
5865 case ppc::kPointerDiff16:
5866 case ppc::kPointerDiff32:
5867 case ppc::kPointerDiff64:
5868 case ppc::kPICBaseLow16:
5869 case ppc::kPICBaseLow14:
5870 case ppc::kPICBaseHigh16:
5871 case ppc::kAbsLow16:
5872 case ppc::kAbsLow14:
5873 case ppc::kAbsHigh16:
5874 case ppc::kAbsHigh16AddLow:
5875 case ppc::kDtraceProbe:
5876 case ppc::kDtraceProbeSite:
5877 case ppc::kDtraceIsEnabledSite:
5878 case ppc::kDtraceTypeReference:
5879 // these are never used to call external functions
5881 case ppc::kBranch24:
5882 case ppc::kBranch24WeakImport:
5883 case ppc::kBranch14:
5884 // these are used to call external functions
5891 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5893 uint8_t kind = ref->getKind();
5894 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
5898 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5900 uint8_t kind = ref->getKind();
5901 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
5906 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
5908 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
5912 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
5914 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
5918 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
5920 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
5924 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
5927 case x86_64::kPointerWeakImport:
5928 case x86_64::kBranchPCRel32WeakImport:
5929 case x86_64::kPCRel32GOTWeakImport:
5930 case x86_64::kPCRel32GOTLoadWeakImport:
5937 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
5939 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
5940 kind == arm::kPointerWeakImport);
5944 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
5950 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
5956 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
5962 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
5965 case x86_64::kPCRel32GOT:
5966 case x86_64::kPCRel32GOTWeakImport:
5967 case x86_64::kPCRel32GOTLoad:
5968 case x86_64::kPCRel32GOTLoadWeakImport:
5975 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
5981 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
5987 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
5993 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
5999 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
6002 case x86_64::kPCRel32GOTLoad:
6003 case x86_64::kPCRel32GOTLoadWeakImport:
6010 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
6015 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
6016 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
6017 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
6018 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
6021 template <typename A>
6022 void Writer<A>::optimizeDylibReferences()
6024 //fprintf(stderr, "original ordinals table:\n");
6025 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
6026 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
6028 // find unused dylibs that can be removed
6029 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
6030 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
6031 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
6032 ObjectFile::Reader* reader = it->first;
6033 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
6034 if ( aliasPos != fLibraryAliases.end() ) {
6035 // already noticed that this reader has same install name as another reader
6036 readerAliases[reader] = aliasPos->second;
6038 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || fOptions.deadStripDylibs()) ) {
6039 // this reader can be optimized away
6040 it->second = 0xFFFFFFFF;
6041 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
6042 if ( pos != fLibraryToLoadCommand.end() )
6043 pos->second->optimizeAway();
6046 // mark this reader as using it ordinal
6047 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
6048 if ( pos == ordinalToReader.end() )
6049 ordinalToReader[it->second] = reader;
6051 readerAliases[reader] = pos->second;
6054 // renumber ordinals (depends on iterator walking in ordinal order)
6055 // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
6056 uint32_t newOrdinal = 0;
6057 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
6058 if ( it->first <= fLibraryToOrdinal.size() ) {
6059 if ( ! it->second->isLazyLoadedDylib() )
6060 fLibraryToOrdinal[it->second] = ++newOrdinal;
6063 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
6064 if ( it->first <= fLibraryToOrdinal.size() ) {
6065 if ( it->second->isLazyLoadedDylib() ) {
6066 fLibraryToOrdinal[it->second] = ++newOrdinal;
6071 // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
6072 if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
6073 throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
6075 // add aliases (e.g. -lm points to libSystem.dylib)
6076 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
6077 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
6080 //fprintf(stderr, "new ordinals table:\n");
6081 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
6082 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
6088 void Writer<arm>::scanForAbsoluteReferences()
6090 // arm codegen never has absolute references. FIXME: Is this correct?
6094 void Writer<x86_64>::scanForAbsoluteReferences()
6096 // x86_64 codegen never has absolute references
6100 void Writer<x86>::scanForAbsoluteReferences()
6102 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
6103 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
6104 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6105 ObjectFile::Atom* atom = *it;
6106 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6107 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6108 ObjectFile::Reference* ref = *rit;
6109 switch (ref->getKind()) {
6110 case x86::kAbsolute32:
6111 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
6120 void Writer<ppc>::scanForAbsoluteReferences()
6122 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
6123 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
6124 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6125 ObjectFile::Atom* atom = *it;
6126 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6127 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6128 ObjectFile::Reference* ref = *rit;
6129 switch (ref->getKind()) {
6130 case ppc::kAbsLow16:
6131 case ppc::kAbsLow14:
6132 case ppc::kAbsHigh16:
6133 case ppc::kAbsHigh16AddLow:
6134 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
6143 // for ppc64 look for any -mdynamic-no-pic codegen
6145 void Writer<ppc64>::scanForAbsoluteReferences()
6147 // only do this for main executable
6148 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
6149 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6150 ObjectFile::Atom* atom = *it;
6151 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6152 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6153 ObjectFile::Reference* ref = *rit;
6154 switch (ref->getKind()) {
6155 case ppc64::kAbsLow16:
6156 case ppc64::kAbsLow14:
6157 case ppc64::kAbsHigh16:
6158 case ppc64::kAbsHigh16AddLow:
6159 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
6160 // shrink page-zero and add pad segment to compensate
6161 fPadSegmentInfo = new SegmentInfo();
6162 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
6163 fPageZeroAtom->setSize(0x1000);
6172 template <typename A>
6173 void Writer<A>::insertDummyStubs()
6175 // only needed for x86
6179 void Writer<x86>::insertDummyStubs()
6181 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
6182 std::vector<class StubAtom<x86>*> betterStubs;
6183 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
6184 switch (betterStubs.size() % 64 ) {
6185 case 12:// stub would occupy 0x3C->0x41
6186 case 25:// stub would occupy 0x7D->0x82
6187 case 38:// stub would occupy 0xBE->0xC3
6188 case 51:// stub would occupy 0xFF->0x04
6189 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
6192 betterStubs.push_back(*it);
6195 fAllSynthesizedStubs.clear();
6196 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
6199 template <typename A>
6200 void Writer<A>::synthesizeStubs()
6202 switch ( fOptions.outputKind() ) {
6203 case Options::kObjectFile:
6204 // these output kinds never have stubs
6206 case Options::kStaticExecutable:
6207 case Options::kDyld:
6208 case Options::kDynamicLibrary:
6209 case Options::kDynamicBundle:
6210 case Options::kDynamicExecutable:
6211 // try to synthesize stubs for these
6215 // walk every atom and reference
6216 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6217 ObjectFile::Atom* atom = *it;
6218 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6219 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6220 ObjectFile::Reference* ref = *rit;
6221 switch ( ref->getTargetBinding()) {
6222 case ObjectFile::Reference::kUnboundByName:
6223 case ObjectFile::Reference::kDontBind:
6225 case ObjectFile::Reference::kBoundByName:
6226 case ObjectFile::Reference::kBoundDirectly:
6227 ObjectFile::Atom& target = ref->getTarget();
6228 // build map of which symbols need weak importing
6229 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
6230 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
6231 bool weakImport = this->weakImportReferenceKind(ref->getKind());
6232 // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
6233 // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
6234 // in dylibs that are weakly linked.
6235 if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
6236 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
6237 pos = fLibraryToLoadCommand.find(target.getFile());
6238 if ( pos != fLibraryToLoadCommand.end() ) {
6239 if ( pos->second->linkedWeak() )
6243 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
6244 if ( pos == fWeakImportMap.end() ) {
6245 // target not in fWeakImportMap, so add
6246 fWeakImportMap[&target] = weakImport;
6249 // target in fWeakImportMap, check for weakness mismatch
6250 if ( pos->second != weakImport ) {
6252 switch ( fOptions.weakReferenceMismatchTreatment() ) {
6253 case Options::kWeakReferenceMismatchError:
6254 throwf("mismatching weak references for symbol: %s", target.getName());
6255 case Options::kWeakReferenceMismatchWeak:
6258 case Options::kWeakReferenceMismatchNonWeak:
6259 pos->second = false;
6264 // update if we use a weak_import or a strong import from this dylib
6265 if ( fWeakImportMap[&target] )
6266 fDylibReadersWithWeakImports.insert(target.getFile());
6268 fDylibReadersWithNonWeakImports.insert(target.getFile());
6270 // create stubs as needed
6271 if ( this->stubableReference(atom, ref)
6272 && (ref->getTargetOffset() == 0)
6273 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
6274 ObjectFile::Atom* stub = NULL;
6275 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
6276 if ( pos == fStubsMap.end() ) {
6277 bool forLazyDylib = false;
6278 switch ( target.getDefinitionKind() ) {
6279 case ObjectFile::Atom::kRegularDefinition:
6280 case ObjectFile::Atom::kWeakDefinition:
6281 case ObjectFile::Atom::kAbsoluteSymbol:
6282 case ObjectFile::Atom::kTentativeDefinition:
6284 case ObjectFile::Atom::kExternalDefinition:
6285 case ObjectFile::Atom::kExternalWeakDefinition:
6286 if ( target.getFile()->isLazyLoadedDylib() )
6287 forLazyDylib = true;
6290 stub = new StubAtom<A>(*this, target, forLazyDylib);
6291 fStubsMap[&target] = stub;
6296 // alter reference to use stub instead
6297 ref->setTarget(*stub, 0);
6299 else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
6300 throwf("illegal reference to %s in lazy loaded dylib from %s in %s",
6301 target.getDisplayName(), atom->getDisplayName(),
6302 atom->getFile()->getPath());
6304 // create GOT slots (non-lazy pointers) as needed
6305 else if ( this->GOTReferenceKind(ref->getKind()) ) {
6307 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
6309 if ( fBiggerThanTwoGigs ) {
6310 // in big images use GOT for all zero fill atoms
6311 // this is just a heuristic and may need to be re-examined
6312 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
6315 // < 2GB image so remove all GOT entries that we can
6316 useGOT = mustUseGOT;
6318 // if this GOT usage cannot be optimized away then make a GOT enry
6319 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
6322 ObjectFile::Atom* nlp = NULL;
6323 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
6324 if ( pos == fGOTMap.end() ) {
6325 nlp = new NonLazyPointerAtom<A>(*this, target);
6326 fGOTMap[&target] = nlp;
6331 // alter reference to use non lazy pointer instead
6332 ref->setTarget(*nlp, ref->getTargetOffset());
6340 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
6342 // add dummy fast stubs (x86 only)
6343 if ( !fOptions.slowx86Stubs() )
6344 this->insertDummyStubs();
6346 // sort lazy pointers
6347 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
6348 std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
6351 // add stubs to fAllAtoms
6352 if ( fAllSynthesizedStubs.size() != 0 ) {
6353 std::vector<ObjectFile::Atom*> textStubs;
6354 std::vector<ObjectFile::Atom*> importStubs;
6355 for (typename std::vector<class StubAtom<A>*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) {
6356 ObjectFile::Atom* stubAtom = *sit;
6357 if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 )
6358 textStubs.push_back(stubAtom);
6360 importStubs.push_back(stubAtom);
6362 // any helper stubs go right after regular stubs
6363 if ( fAllSynthesizedStubHelpers.size() != 0 )
6364 textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
6365 // insert text stubs right after __text section
6366 ObjectFile::Section* curSection = NULL;
6367 ObjectFile::Atom* prevAtom = NULL;
6368 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6369 ObjectFile::Atom* atom = *it;
6370 ObjectFile::Section* nextSection = atom->getSection();
6371 if ( nextSection != curSection ) {
6372 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
6373 // found end of __text section, insert stubs here
6374 fAllAtoms->insert(it, textStubs.begin(), textStubs.end());
6377 curSection = nextSection;
6381 if ( importStubs.size() != 0 ) {
6382 // insert __IMPORTS stubs right before __LINKEDIT
6383 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6384 ObjectFile::Atom* atom = *it;
6385 ObjectFile::Section* nextSection = atom->getSection();
6386 if ( nextSection != curSection ) {
6387 // for i386 where stubs are not in __TEXT segment
6388 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
6389 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
6390 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
6391 fAllAtoms->insert(it, importStubs.begin(), importStubs.end());
6394 curSection = nextSection;
6402 // add lazy dylib pointers to fAllAtoms
6403 if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) {
6404 ObjectFile::Section* curSection = NULL;
6405 ObjectFile::Atom* prevAtom = NULL;
6406 bool inserted = false;
6407 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6408 ObjectFile::Atom* atom = *it;
6409 ObjectFile::Section* nextSection = atom->getSection();
6410 if ( nextSection != curSection ) {
6411 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
6412 // found end of __dyld section, insert lazy pointers here
6413 fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
6417 curSection = nextSection;
6422 throw "can't insert lazy pointers, __dyld section not found";
6426 // add lazy pointers to fAllAtoms
6427 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
6428 ObjectFile::Section* curSection = NULL;
6429 ObjectFile::Atom* prevAtom = NULL;
6430 bool inserted = false;
6431 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6432 ObjectFile::Atom* atom = *it;
6433 ObjectFile::Section* nextSection = atom->getSection();
6434 if ( nextSection != curSection ) {
6435 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
6436 // found end of __dyld section, insert lazy pointers here
6437 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
6441 curSection = nextSection;
6446 throw "can't insert lazy pointers, __dyld section not found";
6450 // add non-lazy pointers to fAllAtoms
6451 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
6452 ObjectFile::Section* curSection = NULL;
6453 ObjectFile::Atom* prevAtom = NULL;
6454 bool inserted = false;
6455 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6456 ObjectFile::Atom* atom = *it;
6457 ObjectFile::Section* nextSection = atom->getSection();
6458 if ( nextSection != curSection ) {
6459 if ( (prevAtom != NULL)
6460 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
6461 || ((strcmp(prevAtom->getSectionName(), "__data") == 0) &&
6462 ((fOptions.outputKind() == Options::kDyld) || (fOptions.outputKind() == Options::kStaticExecutable))) ) ) {
6463 // found end of __dyld section, insert lazy pointers here
6464 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
6468 curSection = nextSection;
6473 throw "can't insert non-lazy pointers, __dyld section not found";
6477 // build LC_SEGMENT_SPLIT_INFO content now that all atoms exist
6478 if ( fSplitCodeToDataContentAtom != NULL ) {
6479 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6480 ObjectFile::Atom* atom = *it;
6481 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6482 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6483 ObjectFile::Reference* ref = *rit;
6484 switch ( ref->getTargetBinding()) {
6485 case ObjectFile::Reference::kUnboundByName:
6486 case ObjectFile::Reference::kDontBind:
6488 case ObjectFile::Reference::kBoundByName:
6489 case ObjectFile::Reference::kBoundDirectly:
6490 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
6491 this->addCrossSegmentRef(atom, ref);
6502 template <typename A>
6503 void Writer<A>::partitionIntoSections()
6505 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
6507 // for every atom, set its sectionInfo object and section offset
6508 // build up fSegmentInfos along the way
6509 ObjectFile::Section* curSection = NULL;
6510 SectionInfo* currentSectionInfo = NULL;
6511 SegmentInfo* currentSegmentInfo = NULL;
6512 SectionInfo* cstringSectionInfo = NULL;
6513 unsigned int sectionIndex = 1;
6514 fSegmentInfos.reserve(8);
6515 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
6516 ObjectFile::Atom* atom = (*fAllAtoms)[i];
6517 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
6518 if ( oneSegmentCommand ) {
6519 if ( currentSegmentInfo == NULL ) {
6520 currentSegmentInfo = new SegmentInfo();
6521 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6522 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6523 this->fSegmentInfos.push_back(currentSegmentInfo);
6525 currentSectionInfo = new SectionInfo();
6526 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
6527 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
6528 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
6529 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
6530 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
6531 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
6532 currentSectionInfo->setIndex(sectionIndex++);
6533 currentSegmentInfo->fSections.push_back(currentSectionInfo);
6534 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
6535 cstringSectionInfo = currentSectionInfo;
6538 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
6539 currentSegmentInfo = new SegmentInfo();
6540 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
6541 uint32_t initprot = 0;
6542 if ( atom->getSegment().isContentReadable() )
6543 initprot |= VM_PROT_READ;
6544 if ( atom->getSegment().isContentWritable() )
6545 initprot |= VM_PROT_WRITE;
6546 if ( atom->getSegment().isContentExecutable() )
6547 initprot |= VM_PROT_EXECUTE;
6548 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
6549 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
6550 currentSegmentInfo->fInitProtection = initprot;
6551 if ( initprot == 0 )
6552 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
6553 else if ( fOptions.architecture() == CPU_TYPE_ARM )
6554 currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init
6556 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6557 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
6558 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
6559 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
6560 currentSegmentInfo->fInitProtection = it->init;
6561 currentSegmentInfo->fMaxProtection = it->max;
6564 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
6565 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
6566 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
6567 currentSegmentInfo->fIndependentAddress = true;
6568 this->fSegmentInfos.push_back(currentSegmentInfo);
6570 currentSectionInfo = new SectionInfo();
6571 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
6572 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
6573 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
6574 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
6575 // check for -sectalign override
6576 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
6577 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
6578 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
6579 currentSectionInfo->fAlignment = it->alignment;
6581 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
6582 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
6583 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
6584 currentSectionInfo->setIndex(sectionIndex++);
6585 currentSegmentInfo->fSections.push_back(currentSectionInfo);
6587 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
6588 fLoadCommandsSection = currentSectionInfo;
6589 fLoadCommandsSegment = currentSegmentInfo;
6591 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
6592 currentSectionInfo->fAllLazyPointers = true;
6593 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
6594 currentSectionInfo->fAllLazyPointers = true;
6595 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) )
6596 currentSectionInfo->fAllLazyDylibPointers = true;
6597 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
6598 currentSectionInfo->fAllNonLazyPointers = true;
6599 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
6600 currentSectionInfo->fAllNonLazyPointers = true;
6601 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
6602 currentSectionInfo->fAllNonLazyPointers = true;
6603 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
6604 currentSectionInfo->fAllStubs = true;
6605 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
6606 currentSectionInfo->fAllStubs = true;
6607 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
6608 currentSectionInfo->fAllStubs = true;
6609 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
6610 currentSectionInfo->fAllStubs = true;
6611 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) )
6612 currentSectionInfo->fAllStubs = true;
6613 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) )
6614 currentSectionInfo->fAllStubs = true;
6615 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
6616 currentSectionInfo->fAllSelfModifyingStubs = true;
6617 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
6619 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) )
6620 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
6621 curSection = atom->getSection();
6622 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers
6623 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) {
6624 fSymbolTableCommands->needDynamicTable();
6627 // any non-zero fill atoms make whole section marked not-zero-fill
6628 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
6629 currentSectionInfo->fAllZeroFill = false;
6630 // change section object to be Writer's SectionInfo object
6631 atom->setSection(currentSectionInfo);
6632 // section alignment is that of a contained atom with the greatest alignment
6633 uint8_t atomAlign = atom->getAlignment().powerOf2;
6634 if ( currentSectionInfo->fAlignment < atomAlign )
6635 currentSectionInfo->fAlignment = atomAlign;
6636 // calculate section offset for this atom
6637 uint64_t offset = currentSectionInfo->fSize;
6638 uint64_t alignment = 1 << atomAlign;
6639 uint64_t currentModulus = (offset % alignment);
6640 uint64_t requiredModulus = atom->getAlignment().modulus;
6641 if ( currentModulus != requiredModulus ) {
6642 if ( requiredModulus > currentModulus )
6643 offset += requiredModulus-currentModulus;
6645 offset += requiredModulus+alignment-currentModulus;
6647 atom->setSectionOffset(offset);
6648 uint64_t curAtomSize = atom->getSize();
6649 currentSectionInfo->fSize = offset + curAtomSize;
6650 // add atom to section vector
6651 currentSectionInfo->fAtoms.push_back(atom);
6652 // update largest size
6653 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
6654 fLargestAtomSize = curAtomSize;
6656 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
6657 // when merging cstring sections in .o files, all strings need to use the max alignment
6658 uint64_t offset = 0;
6659 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
6660 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
6661 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
6662 ObjectFile::Atom* atom = *it;
6663 atom->setSectionOffset(offset);
6664 offset += atom->getSize();
6666 cstringSectionInfo->fSize = offset;
6671 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
6672 class TargetAndOffsetComparor
6675 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
6677 if ( left.atom != right.atom )
6678 return ( left.atom < right.atom );
6679 return ( left.offset < right.offset );
6684 bool Writer<ppc>::addBranchIslands()
6686 return this->addPPCBranchIslands();
6690 bool Writer<ppc64>::addBranchIslands()
6692 return this->addPPCBranchIslands();
6696 bool Writer<x86>::addBranchIslands()
6698 // x86 branches can reach entire 4G address space, so no need for branch islands
6703 bool Writer<x86_64>::addBranchIslands()
6705 // x86 branches can reach entire 4G size of largest image
6710 bool Writer<arm>::addBranchIslands()
6712 // arm branch islands not (yet) supported
6713 // you can instead compile with -mlong-call
6718 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
6721 case ppc::kBranch24:
6722 case ppc::kBranch24WeakImport:
6729 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
6732 case ppc64::kBranch24:
6733 case ppc64::kBranch24WeakImport:
6740 // PowerPC can do PC relative branches as far as +/-16MB.
6741 // If a branch target is >16MB then we insert one or more
6742 // "branch islands" between the branch and its target that
6743 // allows island hoping to the target.
6745 // Branch Island Algorithm
6747 // If the __TEXT segment < 16MB, then no branch islands needed
6748 // Otherwise, every 15MB into the __TEXT segment is region is
6749 // added which can contain branch islands. Every out of range
6750 // bl instruction is checked. If it crosses a region, an island
6751 // is added to that region with the same target and the bl is
6752 // adjusted to target the island instead.
6754 // In theory, if too many islands are added to one region, it
6755 // could grow the __TEXT enough that other previously in-range
6756 // bl branches could be pushed out of range. We reduce the
6757 // probability this could happen by placing the ranges every
6758 // 15MB which means the region would have to be 1MB (256K islands)
6759 // before any branches could be pushed out of range.
6761 template <typename A>
6762 bool Writer<A>::addPPCBranchIslands()
6765 bool result = false;
6766 // Can only possibly need branch islands if __TEXT segment > 16M
6767 if ( fLoadCommandsSegment->fSize > 16000000 ) {
6768 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
6769 const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section
6770 SectionInfo* textSection = NULL;
6771 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
6772 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
6774 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
6778 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
6779 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
6780 AtomToIsland regionsMap[kIslandRegionsCount];
6781 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
6782 unsigned int islandCount = 0;
6783 if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
6785 // create islands for branch references that are out of range
6786 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6787 ObjectFile::Atom* atom = *it;
6788 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6789 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6790 ObjectFile::Reference* ref = *rit;
6791 if ( this->isBranch24Reference(ref->getKind()) ) {
6792 ObjectFile::Atom& target = ref->getTarget();
6793 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
6794 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
6795 int64_t displacement = dstAddr - srcAddr;
6796 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
6797 const int64_t kFifteenMegLimit = kBetweenRegions;
6798 if ( displacement > kFifteenMegLimit ) {
6799 // create forward branch chain
6800 ObjectFile::Atom* nextTarget = ⌖
6801 uint64_t nextTargetOffset = ref->getTargetOffset();
6802 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
6803 AtomToIsland* region = ®ionsMap[i];
6804 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
6805 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
6806 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
6807 if ( pos == region->end() ) {
6808 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
6809 island->setSection(textSection);
6810 (*region)[finalTargetAndOffset] = island;
6811 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
6812 regionsIslands[i].push_back(island);
6814 nextTarget = island;
6815 nextTargetOffset = 0;
6818 nextTarget = pos->second;
6819 nextTargetOffset = 0;
6823 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
6824 ref->setTarget(*nextTarget, nextTargetOffset);
6826 else if ( displacement < (-kFifteenMegLimit) ) {
6827 // create back branching chain
6828 ObjectFile::Atom* prevTarget = ⌖
6829 uint64_t prevTargetOffset = ref->getTargetOffset();
6830 for (int i=0; i < kIslandRegionsCount ; ++i) {
6831 AtomToIsland* region = ®ionsMap[i];
6832 int64_t islandRegionAddr = kBetweenRegions * (i+1);
6833 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
6834 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
6835 if ( pos == region->end() ) {
6836 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
6837 island->setSection(textSection);
6838 (*region)[finalTargetAndOffset] = island;
6839 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
6840 regionsIslands[i].push_back(island);
6842 prevTarget = island;
6843 prevTargetOffset = 0;
6846 prevTarget = pos->second;
6847 prevTargetOffset = 0;
6851 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
6852 ref->setTarget(*prevTarget, prevTargetOffset);
6858 // insert islands into __text section and adjust section offsets
6859 if ( islandCount > 0 ) {
6860 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
6861 std::vector<ObjectFile::Atom*> newAtomList;
6862 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
6863 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
6864 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
6865 int regionIndex = 0;
6866 uint64_t atomSlide = 0;
6867 uint64_t sectionOffset = 0;
6868 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
6869 ObjectFile::Atom* atom = *it;
6870 if ( atom->getAddress() > islandRegionAddr ) {
6871 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
6872 sectionOffset = islandStartOffset;
6873 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
6874 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
6875 ObjectFile::Atom* islandAtom = *rit;
6876 newAtomList.push_back(islandAtom);
6877 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
6878 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
6879 islandAtom->setSectionOffset(sectionOffset);
6880 sectionOffset += islandAtom->getSize();
6883 islandRegionAddr += kBetweenRegions;
6884 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
6885 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
6887 newAtomList.push_back(atom);
6888 if ( atomSlide != 0 )
6889 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
6891 sectionOffset = textSection->fSize+atomSlide;
6892 // put any remaining islands at end of __text section
6893 if ( regionIndex < kIslandRegionsCount ) {
6894 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
6895 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
6896 ObjectFile::Atom* islandAtom = *rit;
6897 newAtomList.push_back(islandAtom);
6898 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
6899 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
6900 islandAtom->setSectionOffset(sectionOffset);
6901 sectionOffset += islandAtom->getSize();
6905 textSection->fAtoms = newAtomList;
6906 textSection->fSize = sectionOffset;
6915 template <typename A>
6916 void Writer<A>::adjustLoadCommandsAndPadding()
6918 fSegmentCommands->computeSize();
6920 // recompute load command section offsets
6921 uint64_t offset = 0;
6922 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
6923 const unsigned int atomCount = loadCommandAtoms.size();
6924 for (unsigned int i=0; i < atomCount; ++i) {
6925 ObjectFile::Atom* atom = loadCommandAtoms[i];
6926 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
6927 offset = ( (offset+alignment-1) & (-alignment) );
6928 atom->setSectionOffset(offset);
6929 uint32_t atomSize = atom->getSize();
6930 if ( atomSize > fLargestAtomSize )
6931 fLargestAtomSize = atomSize;
6933 fLoadCommandsSection->fSize = offset;
6936 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
6937 const int sectionCount = sectionInfos.size();
6938 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
6939 for(int j=0; j < sectionCount; ++j) {
6940 SectionInfo* curSection = sectionInfos[j];
6941 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
6942 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
6945 uint64_t paddingSize = 0;
6946 if ( fOptions.outputKind() == Options::kDyld ) {
6947 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
6948 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
6950 else if ( fOptions.outputKind() == Options::kObjectFile ) {
6951 // mach-o .o files need no padding between load commands and first section
6954 else if ( fOptions.makeEncryptable() ) {
6955 // want load commands to end on a page boundary, so __text starts on page boundary
6956 paddingSize = 4096 - ((totalSizeOfHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
6957 fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfHeaderAndLoadCommands+paddingSize);
6960 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
6962 for(int j=sectionCount-1; j >=0; --j) {
6963 SectionInfo* curSection = sectionInfos[j];
6964 addr -= curSection->fSize;
6965 addr = addr & (0 - (1 << curSection->fAlignment));
6966 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
6967 addr -= totalSizeOfHeaderAndLoadCommands;
6968 paddingSize = addr % 4096;
6973 // if command line requires more padding than this
6974 uint32_t minPad = fOptions.minimumHeaderPad();
6975 if ( fOptions.maxMminimumHeaderPad() ) {
6976 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
6977 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
6978 if ( fOptions.outputKind() == Options::kDynamicLibrary )
6979 altMin += MAXPATHLEN;
6980 if ( altMin > minPad )
6983 if ( paddingSize < minPad ) {
6984 int extraPages = (minPad - paddingSize + 4095)/4096;
6985 paddingSize += extraPages * 4096;
6989 // adjust atom size and update section size
6990 fHeaderPadding->setSize(paddingSize);
6991 for(int j=0; j < sectionCount; ++j) {
6992 SectionInfo* curSection = sectionInfos[j];
6993 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
6994 curSection->fSize = paddingSize;
6998 // assign file offsets and logical address to all segments
6999 template <typename A>
7000 void Writer<A>::assignFileOffsets()
7002 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
7003 bool haveFixedSegments = false;
7004 uint64_t fileOffset = 0;
7005 uint64_t nextContiguousAddress = fOptions.baseAddress();
7006 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
7007 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
7009 // process segments with fixed addresses (-segaddr)
7010 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
7011 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7012 SegmentInfo* curSegment = *segit;
7013 if ( strcmp(curSegment->fName, it->name) == 0 ) {
7014 curSegment->fBaseAddress = it->address;
7015 curSegment->fFixedAddress = true;
7021 // Run through the segments and each segment's sections to assign addresses
7022 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7023 SegmentInfo* curSegment = *segit;
7025 if ( fOptions.splitSeg() ) {
7026 if ( curSegment->fInitProtection & VM_PROT_WRITE )
7027 nextContiguousAddress = nextWritableAddress;
7029 nextContiguousAddress = nextReadOnlyAddress;
7032 fileOffset = (fileOffset+4095) & (-4096);
7033 curSegment->fFileOffset = fileOffset;
7035 // Set the segment base address
7036 if ( curSegment->fFixedAddress )
7037 haveFixedSegments = true;
7039 curSegment->fBaseAddress = nextContiguousAddress;
7041 // We've set the segment address, now run through each section.
7042 uint64_t address = curSegment->fBaseAddress;
7043 SectionInfo* firstZeroFillSection = NULL;
7044 SectionInfo* prevSection = NULL;
7046 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
7048 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
7049 SectionInfo* curSection = *it;
7051 // adjust section address based on alignment
7052 uint64_t alignment = 1 << curSection->fAlignment;
7053 address = ( (address+alignment-1) & (-alignment) );
7055 // adjust file offset to match address
7056 if ( prevSection != NULL ) {
7057 if ( finalLinkedImage || !prevSection->fVirtualSection )
7058 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
7060 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
7063 // update section info
7064 curSection->fFileOffset = fileOffset;
7065 curSection->setBaseAddress(address);
7066 //fprintf(stderr, "%s %s %llX\n", curSegment->fName, curSection->fSectionName, address);
7068 // keep track of trailing zero fill sections
7069 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
7070 firstZeroFillSection = curSection;
7071 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
7072 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
7074 // update running pointers
7075 if ( finalLinkedImage || !curSection->fVirtualSection )
7076 address += curSection->fSize;
7077 fileOffset += curSection->fSize;
7079 // sanity check size of 32-bit binaries
7080 if ( address > maxAddress() )
7081 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
7083 // update segment info
7084 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
7085 curSegment->fSize = curSegment->fFileSize;
7086 prevSection = curSection;
7089 if ( fOptions.outputKind() == Options::kObjectFile ) {
7090 // don't page align .o files
7093 // optimize trailing zero-fill sections to not occupy disk space
7094 if ( firstZeroFillSection != NULL ) {
7095 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
7096 fileOffset = firstZeroFillSection->fFileOffset;
7098 // page align segment size
7099 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
7100 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
7101 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
7102 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
7103 if ( curSegment->fInitProtection & VM_PROT_WRITE )
7104 nextWritableAddress = nextContiguousAddress;
7106 nextReadOnlyAddress = nextContiguousAddress;
7111 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
7112 if ( haveFixedSegments ) {
7113 int segCount = fSegmentInfos.size();
7114 for(int i=0; i < segCount; ++i) {
7115 SegmentInfo* segment1 = fSegmentInfos[i];
7117 for(int j=0; j < segCount; ++j) {
7119 SegmentInfo* segment2 = fSegmentInfos[j];
7121 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
7122 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
7123 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7124 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7126 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
7127 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
7128 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7129 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7131 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
7132 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7133 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7140 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
7141 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7142 SegmentInfo* curSegment = *segit;
7143 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
7144 if ( fFirstWritableSegment == NULL )
7145 fFirstWritableSegment = curSegment;
7146 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
7147 fWritableSegmentPastFirst4GB = true;
7151 // record size of encrypted part of __TEXT segment
7152 if ( fOptions.makeEncryptable() ) {
7153 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7154 SegmentInfo* curSegment = *segit;
7155 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
7156 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
7164 template <typename A>
7165 void Writer<A>::adjustLinkEditSections()
7167 // link edit content is always in last segment
7168 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
7169 unsigned int firstLinkEditSectionIndex = 0;
7170 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
7171 ++firstLinkEditSectionIndex;
7173 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
7174 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
7175 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
7176 if ( fPadSegmentInfo != NULL ) {
7177 // insert __4GBFILL segment into segments vector before LINKEDIT
7178 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
7179 if ( *it == lastSeg ) {
7180 fSegmentInfos.insert(it, fPadSegmentInfo);
7184 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
7185 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
7186 fPadSegmentInfo->fBaseAddress = address;
7187 // adjust LINKEDIT to start at zeroPageSize
7188 address = fOptions.zeroPageSize();
7189 lastSeg->fBaseAddress = fOptions.zeroPageSize();
7191 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
7192 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
7193 // adjust section address based on alignment
7194 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
7195 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
7197 fileOffset += pad; // adjust file offset to match address
7198 lastSeg->fSections[i]->setBaseAddress(address);
7199 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
7200 lastSeg->fSections[i]->setBaseAddress(0);
7201 lastSeg->fSections[i]->fFileOffset = fileOffset;
7202 uint64_t sectionOffset = 0;
7203 for (unsigned int j=0; j < atoms.size(); ++j) {
7204 ObjectFile::Atom* atom = atoms[j];
7205 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
7206 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
7207 atom->setSectionOffset(sectionOffset);
7208 uint64_t size = atom->getSize();
7209 sectionOffset += size;
7210 if ( size > fLargestAtomSize )
7211 fLargestAtomSize = size;
7213 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
7214 lastSeg->fSections[i]->fSize = sectionOffset;
7215 fileOffset += sectionOffset;
7216 address += sectionOffset;
7218 if ( fOptions.outputKind() == Options::kObjectFile ) {
7219 //lastSeg->fBaseAddress = 0;
7220 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
7221 //lastSeg->fFileOffset = 0;
7222 //lastSeg->fFileSize =
7225 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
7226 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
7231 template <typename A>
7232 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
7234 switch ( fWriter.fOptions.outputKind() ) {
7235 case Options::kDynamicExecutable:
7236 case Options::kStaticExecutable:
7237 return ObjectFile::Atom::scopeGlobal;
7238 case Options::kDynamicLibrary:
7239 case Options::kDynamicBundle:
7240 case Options::kDyld:
7241 case Options::kObjectFile:
7242 return ObjectFile::Atom::scopeLinkageUnit;
7244 throw "unknown header type";
7247 template <typename A>
7248 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
7250 switch ( fWriter.fOptions.outputKind() ) {
7251 case Options::kDynamicExecutable:
7252 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
7253 case Options::kStaticExecutable:
7254 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
7255 case Options::kDynamicLibrary:
7256 case Options::kDynamicBundle:
7257 case Options::kDyld:
7258 return ObjectFile::Atom::kSymbolTableIn;
7259 case Options::kObjectFile:
7260 return ObjectFile::Atom::kSymbolTableNotIn;
7262 throw "unknown header type";
7265 template <typename A>
7266 const char* MachHeaderAtom<A>::getName() const
7268 switch ( fWriter.fOptions.outputKind() ) {
7269 case Options::kDynamicExecutable:
7270 case Options::kStaticExecutable:
7271 return "__mh_execute_header";
7272 case Options::kDynamicLibrary:
7273 return "__mh_dylib_header";
7274 case Options::kDynamicBundle:
7275 return "__mh_bundle_header";
7276 case Options::kObjectFile:
7278 case Options::kDyld:
7279 return "__mh_dylinker_header";
7281 throw "unknown header type";
7284 template <typename A>
7285 const char* MachHeaderAtom<A>::getDisplayName() const
7287 switch ( fWriter.fOptions.outputKind() ) {
7288 case Options::kDynamicExecutable:
7289 case Options::kStaticExecutable:
7290 case Options::kDynamicLibrary:
7291 case Options::kDynamicBundle:
7292 case Options::kDyld:
7293 return this->getName();
7294 case Options::kObjectFile:
7295 return "mach header";
7297 throw "unknown header type";
7300 template <typename A>
7301 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
7304 uint32_t fileType = 0;
7305 switch ( fWriter.fOptions.outputKind() ) {
7306 case Options::kDynamicExecutable:
7307 case Options::kStaticExecutable:
7308 fileType = MH_EXECUTE;
7310 case Options::kDynamicLibrary:
7311 fileType = MH_DYLIB;
7313 case Options::kDynamicBundle:
7314 fileType = MH_BUNDLE;
7316 case Options::kObjectFile:
7317 fileType = MH_OBJECT;
7319 case Options::kDyld:
7320 fileType = MH_DYLINKER;
7326 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
7327 if ( fWriter.fCanScatter )
7328 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
7331 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
7332 flags |= MH_NOUNDEFS;
7335 flags = MH_DYLDLINK;
7336 if ( fWriter.fOptions.bindAtLoad() )
7337 flags |= MH_BINDATLOAD;
7338 switch ( fWriter.fOptions.nameSpace() ) {
7339 case Options::kTwoLevelNameSpace:
7340 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
7342 case Options::kFlatNameSpace:
7344 case Options::kForceFlatNameSpace:
7345 flags |= MH_FORCE_FLAT;
7348 if ( fWriter.fHasWeakExports )
7349 flags |= MH_WEAK_DEFINES;
7350 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
7351 flags |= MH_BINDS_TO_WEAK;
7352 if ( fWriter.fOptions.prebind() )
7353 flags |= MH_PREBOUND;
7354 if ( fWriter.fOptions.splitSeg() )
7355 flags |= MH_SPLIT_SEGS;
7356 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
7357 flags |= MH_NO_REEXPORTED_DYLIBS;
7358 if ( fWriter.fOptions.positionIndependentExecutable() )
7361 if ( fWriter.fOptions.hasExecutableStack() )
7362 flags |= MH_ALLOW_STACK_EXECUTION;
7363 if ( fWriter.fOptions.readerOptions().fRootSafe )
7364 flags |= MH_ROOT_SAFE;
7365 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
7366 flags |= MH_SETUID_SAFE;
7369 // get commands info
7370 uint32_t commandsSize = 0;
7371 uint32_t commandsCount = 0;
7373 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
7374 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
7375 ObjectFile::Atom* atom = *it;
7376 commandsSize += atom->getSize();
7377 // segment and symbol table atoms can contain more than one load command
7378 if ( atom == fWriter.fSegmentCommands )
7379 commandsCount += fWriter.fSegmentCommands->commandCount();
7380 else if ( atom == fWriter.fSymbolTableCommands )
7381 commandsCount += fWriter.fSymbolTableCommands->commandCount();
7382 else if ( atom->getSize() != 0 )
7386 // fill out mach_header
7387 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
7389 mh->set_filetype(fileType);
7390 mh->set_ncmds(commandsCount);
7391 mh->set_sizeofcmds(commandsSize);
7392 mh->set_flags(flags);
7396 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
7398 header.set_magic(MH_MAGIC);
7399 header.set_cputype(CPU_TYPE_POWERPC);
7400 header.set_cpusubtype(fWriter.fCpuConstraint);
7404 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
7406 header.set_magic(MH_MAGIC_64);
7407 header.set_cputype(CPU_TYPE_POWERPC64);
7408 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7409 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
7411 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
7412 header.set_reserved(0);
7416 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
7418 header.set_magic(MH_MAGIC);
7419 header.set_cputype(CPU_TYPE_I386);
7420 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
7424 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
7426 header.set_magic(MH_MAGIC_64);
7427 header.set_cputype(CPU_TYPE_X86_64);
7428 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7429 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
7431 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
7432 header.set_reserved(0);
7436 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
7438 header.set_magic(MH_MAGIC);
7439 header.set_cputype(CPU_TYPE_ARM);
7440 header.set_cpusubtype(fWriter.fCpuConstraint);
7443 template <typename A>
7444 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
7445 : WriterAtom<A>(writer, Segment::fgStackSegment)
7447 if ( stackGrowsDown() )
7448 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
7450 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
7454 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
7455 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
7456 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
7457 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
7458 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
7460 template <typename A>
7461 void SegmentLoadCommandsAtom<A>::computeSize()
7464 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
7465 const int segCount = segmentInfos.size();
7466 for(int i=0; i < segCount; ++i) {
7467 size += sizeof(macho_segment_command<P>);
7468 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
7469 const int sectionCount = sectionInfos.size();
7470 for(int j=0; j < sectionCount; ++j) {
7471 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
7472 size += sizeof(macho_section<P>);
7476 fCommandCount = segCount;
7477 if ( fWriter.fPadSegmentInfo != NULL ) {
7479 fSize += sizeof(macho_segment_command<P>);
7484 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
7486 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7490 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
7492 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
7496 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
7498 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7502 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
7504 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
7508 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
7510 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7513 template <typename A>
7514 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7516 uint64_t size = this->getSize();
7517 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
7518 bzero(buffer, size);
7519 uint8_t* p = buffer;
7520 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
7521 const int segCount = segmentInfos.size();
7522 for(int i=0; i < segCount; ++i) {
7523 SegmentInfo* segInfo = segmentInfos[i];
7524 const int sectionCount = segInfo->fSections.size();
7525 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
7526 cmd->set_cmd(macho_segment_command<P>::CMD);
7527 cmd->set_segname(segInfo->fName);
7528 cmd->set_vmaddr(segInfo->fBaseAddress);
7529 cmd->set_vmsize(segInfo->fSize);
7530 cmd->set_fileoff(segInfo->fFileOffset);
7531 cmd->set_filesize(segInfo->fFileSize);
7532 cmd->set_maxprot(segInfo->fMaxProtection);
7533 cmd->set_initprot(segInfo->fInitProtection);
7534 // add sections array
7535 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
7536 unsigned int sectionsEmitted = 0;
7537 for (int j=0; j < sectionCount; ++j) {
7538 SectionInfo* sectInfo = segInfo->fSections[j];
7539 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
7540 macho_section<P>* sect = §ions[sectionsEmitted++];
7542 // .o file segment does not cover load commands, so recalc at first real section
7543 if ( sectionsEmitted == 1 ) {
7544 cmd->set_vmaddr(sectInfo->getBaseAddress());
7545 cmd->set_fileoff(sectInfo->fFileOffset);
7547 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
7548 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
7550 sect->set_sectname(sectInfo->fSectionName);
7551 sect->set_segname(sectInfo->fSegmentName);
7552 sect->set_addr(sectInfo->getBaseAddress());
7553 sect->set_size(sectInfo->fSize);
7554 sect->set_offset(sectInfo->fFileOffset);
7555 sect->set_align(sectInfo->fAlignment);
7556 if ( sectInfo->fRelocCount != 0 ) {
7557 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
7558 sect->set_nreloc(sectInfo->fRelocCount);
7560 if ( sectInfo->fAllZeroFill ) {
7561 sect->set_flags(S_ZEROFILL);
7562 sect->set_offset(0);
7564 else if ( sectInfo->fAllLazyPointers ) {
7565 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
7566 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7568 else if ( sectInfo->fAllLazyDylibPointers ) {
7569 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
7570 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7572 else if ( sectInfo->fAllNonLazyPointers ) {
7573 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
7574 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7576 else if ( sectInfo->fAllStubs ) {
7577 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
7578 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7579 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
7581 else if ( sectInfo->fAllSelfModifyingStubs ) {
7582 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
7583 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7584 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
7586 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7587 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
7589 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7590 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
7592 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7593 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
7595 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7596 sect->set_flags(S_COALESCED);
7598 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7599 sect->set_flags(S_COALESCED);
7601 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7602 sect->set_flags(S_INTERPOSING);
7604 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7605 sect->set_flags(S_CSTRING_LITERALS);
7607 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7608 sect->set_flags(S_4BYTE_LITERALS);
7610 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7611 sect->set_flags(S_8BYTE_LITERALS);
7613 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7614 sect->set_flags(S_16BYTE_LITERALS);
7616 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
7617 sect->set_flags(S_LITERAL_POINTERS);
7619 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
7620 sect->set_flags(S_LITERAL_POINTERS);
7622 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7623 sect->set_flags(S_DTRACE_DOF);
7625 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7626 sect->set_flags(S_DTRACE_DOF);
7628 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7629 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
7630 if ( sectInfo->fHasTextLocalRelocs )
7631 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
7632 if ( sectInfo->fHasTextExternalRelocs )
7633 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
7637 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
7638 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
7639 cmd->set_nsects(sectionsEmitted);
7644 template <typename A>
7645 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
7646 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
7648 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
7649 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
7650 switch ( fWriter.fOptions.outputKind() ) {
7651 case Options::kDynamicExecutable:
7652 case Options::kDynamicLibrary:
7653 case Options::kDynamicBundle:
7654 case Options::kDyld:
7655 fNeedsDynamicSymbolTable = true;
7657 case Options::kObjectFile:
7658 case Options::kStaticExecutable:
7659 fNeedsDynamicSymbolTable = false;
7662 writer.fSymbolTableCommands = this;
7667 template <typename A>
7668 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
7670 fNeedsDynamicSymbolTable = true;
7674 template <typename A>
7675 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
7677 if ( fNeedsDynamicSymbolTable )
7678 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
7680 return this->alignedSize(sizeof(macho_symtab_command<P>));
7683 template <typename A>
7684 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7686 // build LC_DYSYMTAB command
7687 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
7688 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
7689 symbolTableCmd->set_cmd(LC_SYMTAB);
7690 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
7691 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
7692 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
7693 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
7694 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
7696 // build LC_DYSYMTAB command
7697 if ( fNeedsDynamicSymbolTable ) {
7698 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
7699 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
7700 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
7701 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
7702 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
7703 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
7704 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
7705 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
7706 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
7707 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
7708 if ( fWriter.fModuleInfoAtom != NULL ) {
7709 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
7710 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
7711 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
7712 dynamicSymbolTableCmd->set_nmodtab(1);
7713 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
7714 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
7716 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
7717 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
7718 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
7719 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
7720 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
7721 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
7722 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
7728 template <typename A>
7729 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
7731 return fNeedsDynamicSymbolTable ? 2 : 1;
7734 template <typename A>
7735 uint64_t DyldLoadCommandsAtom<A>::getSize() const
7737 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
7740 template <typename A>
7741 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7743 uint64_t size = this->getSize();
7744 bzero(buffer, size);
7745 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
7746 if ( fWriter.fOptions.outputKind() == Options::kDyld )
7747 cmd->set_cmd(LC_ID_DYLINKER);
7749 cmd->set_cmd(LC_LOAD_DYLINKER);
7750 cmd->set_cmdsize(this->getSize());
7751 cmd->set_name_offset();
7752 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
7755 template <typename A>
7756 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
7758 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
7761 template <typename A>
7762 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7764 uint64_t size = this->getSize();
7766 bzero(buffer, size);
7767 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
7768 cmd->set_cmd(LC_SUB_CLIENT);
7769 cmd->set_cmdsize(size);
7770 cmd->set_client_offset();
7771 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
7775 template <typename A>
7776 uint64_t DylibLoadCommandsAtom<A>::getSize() const
7778 if ( fOptimizedAway ) {
7782 const char* path = fInfo.reader->getInstallPath();
7783 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
7787 template <typename A>
7788 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7790 if ( fOptimizedAway )
7792 uint64_t size = this->getSize();
7793 bzero(buffer, size);
7794 const char* path = fInfo.reader->getInstallPath();
7795 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
7796 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
7797 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
7798 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
7799 if ( fInfo.options.fLazyLoad )
7800 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
7801 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
7802 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
7803 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7804 cmd->set_cmd(LC_REEXPORT_DYLIB);
7806 cmd->set_cmd(LC_LOAD_DYLIB);
7807 cmd->set_cmdsize(this->getSize());
7808 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
7809 cmd->set_current_version(fInfo.reader->getCurrentVersion());
7810 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
7811 cmd->set_name_offset();
7812 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
7817 template <typename A>
7818 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
7820 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
7823 template <typename A>
7824 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7826 uint64_t size = this->getSize();
7827 bzero(buffer, size);
7828 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
7829 cmd->set_cmd(LC_ID_DYLIB);
7830 cmd->set_cmdsize(this->getSize());
7831 cmd->set_name_offset();
7832 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
7833 cmd->set_current_version(fWriter.fOptions.currentVersion());
7834 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
7835 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
7839 template <typename A>
7840 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7842 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7843 if (fWriter.fEntryPoint->isThumb())
7845 bzero(buffer, sizeof(macho_routines_command<P>));
7846 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
7847 cmd->set_cmd(macho_routines_command<P>::CMD);
7848 cmd->set_cmdsize(this->getSize());
7849 cmd->set_init_address(initAddr);
7853 template <typename A>
7854 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
7856 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
7859 template <typename A>
7860 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7862 uint64_t size = this->getSize();
7863 bzero(buffer, size);
7864 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
7865 cmd->set_cmd(LC_SUB_UMBRELLA);
7866 cmd->set_cmdsize(this->getSize());
7867 cmd->set_sub_umbrella_offset();
7868 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
7871 template <typename A>
7872 void UUIDLoadCommandAtom<A>::generate()
7874 switch ( fWriter.fOptions.getUUIDMode() ) {
7875 case Options::kUUIDNone:
7878 case Options::kUUIDRandom:
7879 ::uuid_generate_random(fUUID);
7882 case Options::kUUIDContent:
7889 template <typename A>
7890 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
7892 memcpy(fUUID, uuid, 16);
7895 template <typename A>
7896 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
7899 uint64_t size = this->getSize();
7900 bzero(buffer, size);
7901 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
7902 cmd->set_cmd(LC_UUID);
7903 cmd->set_cmdsize(this->getSize());
7904 cmd->set_uuid((uint8_t*)fUUID);
7909 template <typename A>
7910 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
7912 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
7915 template <typename A>
7916 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7918 uint64_t size = this->getSize();
7919 bzero(buffer, size);
7920 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
7921 cmd->set_cmd(LC_SUB_LIBRARY);
7922 cmd->set_cmdsize(this->getSize());
7923 cmd->set_sub_library_offset();
7924 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
7925 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
7928 template <typename A>
7929 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
7931 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
7934 template <typename A>
7935 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7937 uint64_t size = this->getSize();
7938 bzero(buffer, size);
7939 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
7940 cmd->set_cmd(LC_SUB_FRAMEWORK);
7941 cmd->set_cmdsize(this->getSize());
7942 cmd->set_umbrella_offset();
7943 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
7947 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
7949 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
7953 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
7955 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
7959 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
7961 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
7965 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
7967 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
7970 // We should be picking it up from a header
7972 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
7974 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
7978 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
7980 uint64_t size = this->getSize();
7981 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7982 bzero(buffer, size);
7983 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
7984 cmd->set_cmd(LC_UNIXTHREAD);
7985 cmd->set_cmdsize(size);
7986 cmd->set_flavor(1); // PPC_THREAD_STATE
7987 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
7988 cmd->set_thread_register(0, start);
7989 if ( fWriter.fOptions.hasCustomStack() )
7990 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
7995 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
7997 uint64_t size = this->getSize();
7998 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7999 bzero(buffer, size);
8000 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
8001 cmd->set_cmd(LC_UNIXTHREAD);
8002 cmd->set_cmdsize(size);
8003 cmd->set_flavor(5); // PPC_THREAD_STATE64
8004 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
8005 cmd->set_thread_register(0, start);
8006 if ( fWriter.fOptions.hasCustomStack() )
8007 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
8011 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
8013 uint64_t size = this->getSize();
8014 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8015 bzero(buffer, size);
8016 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
8017 cmd->set_cmd(LC_UNIXTHREAD);
8018 cmd->set_cmdsize(size);
8019 cmd->set_flavor(1); // i386_THREAD_STATE
8020 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
8021 cmd->set_thread_register(10, start);
8022 if ( fWriter.fOptions.hasCustomStack() )
8023 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
8027 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
8029 uint64_t size = this->getSize();
8030 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8031 bzero(buffer, size);
8032 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
8033 cmd->set_cmd(LC_UNIXTHREAD);
8034 cmd->set_cmdsize(size);
8035 cmd->set_flavor(x86_THREAD_STATE64);
8036 cmd->set_count(x86_THREAD_STATE64_COUNT);
8037 cmd->set_thread_register(16, start); // rip
8038 if ( fWriter.fOptions.hasCustomStack() )
8039 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
8043 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
8045 uint64_t size = this->getSize();
8046 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8047 bzero(buffer, size);
8048 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
8049 cmd->set_cmd(LC_UNIXTHREAD);
8050 cmd->set_cmdsize(size);
8053 cmd->set_thread_register(15, start); // pc
8054 if ( fWriter.fOptions.hasCustomStack() )
8055 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
8058 template <typename A>
8059 uint64_t RPathLoadCommandsAtom<A>::getSize() const
8061 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
8064 template <typename A>
8065 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8067 uint64_t size = this->getSize();
8068 bzero(buffer, size);
8069 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
8070 cmd->set_cmd(LC_RPATH);
8071 cmd->set_cmdsize(this->getSize());
8072 cmd->set_path_offset();
8073 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
8078 template <typename A>
8079 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8081 uint64_t size = this->getSize();
8082 bzero(buffer, size);
8083 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
8084 cmd->set_cmd(LC_ENCRYPTION_INFO);
8085 cmd->set_cmdsize(this->getSize());
8086 cmd->set_cryptoff(fStartOffset);
8087 cmd->set_cryptsize(fEndOffset-fStartOffset);
8088 cmd->set_cryptid(0);
8093 template <typename A>
8094 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
8096 bzero(buffer, fSize);
8099 template <typename A>
8100 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
8103 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
8104 if ( fWriter.fLargestAtomSize < newSize )
8105 fWriter.fLargestAtomSize = newSize;
8108 template <typename A>
8109 uint64_t LinkEditAtom<A>::getFileOffset() const
8111 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
8115 template <typename A>
8116 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
8118 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
8121 template <typename A>
8122 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8124 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
8128 template <typename A>
8129 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
8131 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
8134 template <typename A>
8135 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8137 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
8142 template <typename A>
8143 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
8145 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
8148 template <typename A>
8149 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8151 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
8154 template <typename A>
8155 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
8157 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
8160 template <typename A>
8161 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8163 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
8164 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
8169 template <typename A>
8170 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
8172 return fTable.size() * sizeof(uint32_t);
8175 template <typename A>
8176 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8178 uint64_t size = this->getSize();
8179 bzero(buffer, size);
8180 const uint32_t indirectTableSize = fTable.size();
8181 uint32_t* indirectTable = (uint32_t*)buffer;
8182 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
8183 if ( it->indirectIndex < indirectTableSize ) {
8184 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
8187 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
8194 template <typename A>
8195 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
8197 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
8198 + sizeof(macho_dylib_module<P>)
8199 + this->getReferencesCount()*sizeof(uint32_t);
8202 template <typename A>
8203 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
8205 return this->getFileOffset();
8208 template <typename A>
8209 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
8211 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
8214 template <typename A>
8215 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
8217 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
8220 template <typename A>
8221 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
8223 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
8226 template <typename A>
8227 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8229 uint64_t size = this->getSize();
8230 bzero(buffer, size);
8231 // create toc. The symbols are already sorted, they are all in the smae module
8232 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
8233 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
8234 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
8235 p->set_module_index(0);
8237 // create module table (one entry)
8238 uint16_t numInits = 0;
8239 uint16_t numTerms = 0;
8240 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
8241 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
8242 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
8243 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
8244 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
8245 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
8246 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
8247 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
8248 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
8252 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
8253 module->set_module_name(fModuleNameOffset);
8254 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
8255 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
8256 module->set_irefsym(0);
8257 module->set_nrefsym(this->getReferencesCount());
8258 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
8259 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
8260 module->set_iextrel(0);
8261 module->set_nextrel(fWriter.fExternalRelocs.size());
8262 module->set_iinit_iterm(0,0);
8263 module->set_ninit_nterm(numInits,numTerms);
8264 module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years
8265 module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years
8266 // create reference table
8267 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
8268 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
8269 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
8270 ref->set_flags(REFERENCE_FLAG_DEFINED);
8272 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
8273 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
8274 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
8275 if ( pos != fWriter.fStubsMap.end() )
8276 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
8278 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
8284 template <typename A>
8285 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
8286 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
8288 fCurrentBuffer = new char[kBufferSize];
8289 // burn first byte of string pool (so zero is never a valid string offset)
8290 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
8291 // make offset 1 always point to an empty string
8292 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
8295 template <typename A>
8296 uint64_t StringsLinkEditAtom<A>::getSize() const
8299 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
8302 template <typename A>
8303 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8305 uint64_t offset = 0;
8306 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
8307 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
8308 offset += kBufferSize;
8310 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
8311 // zero fill end to align
8312 offset += fCurrentBufferUsed;
8313 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
8314 buffer[offset++] = 0;
8317 template <typename A>
8318 int32_t StringsLinkEditAtom<A>::add(const char* name)
8320 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
8321 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
8322 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
8323 fCurrentBufferUsed += lenNeeded;
8326 int copied = kBufferSize-fCurrentBufferUsed-1;
8327 // change trailing '\0' that strlcpy added to real char
8328 fCurrentBuffer[kBufferSize-1] = name[copied];
8329 // alloc next buffer
8330 fFullBuffers.push_back(fCurrentBuffer);
8331 fCurrentBuffer = new char[kBufferSize];
8332 fCurrentBufferUsed = 0;
8333 // append rest of string
8334 this->add(&name[copied+1]);
8340 template <typename A>
8341 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
8343 StringToOffset::iterator pos = fUniqueStrings.find(name);
8344 if ( pos != fUniqueStrings.end() ) {
8348 int32_t offset = this->add(name);
8349 fUniqueStrings[name] = offset;
8355 template <typename A>
8356 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
8358 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
8359 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
8360 // check for out of bounds
8361 if ( index > maxIndex )
8363 // check for index in fCurrentBuffer
8364 if ( index > currentBufferStartIndex )
8365 return &fCurrentBuffer[index-currentBufferStartIndex];
8366 // otherwise index is in a full buffer
8367 uint32_t fullBufferIndex = index/kBufferSize;
8368 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
8373 template <typename A>
8374 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
8375 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
8377 char* buf = new char[strlen(name)+32];
8378 if ( targetOffset == 0 ) {
8379 if ( islandRegion == 0 )
8380 sprintf(buf, "%s$island", name);
8382 sprintf(buf, "%s$island_%d", name, islandRegion);
8385 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
8392 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
8394 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
8395 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
8396 OSWriteBigInt32(buffer, 0, branchInstruction);
8400 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
8402 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
8403 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
8404 OSWriteBigInt32(buffer, 0, branchInstruction);
8408 uint64_t BranchIslandAtom<ppc>::getSize() const
8414 uint64_t BranchIslandAtom<ppc64>::getSize() const
8421 template <typename A>
8422 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
8424 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
8425 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
8427 return 0; // a zero size causes the load command to be suppressed
8430 template <typename A>
8431 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8433 uint64_t size = this->getSize();
8434 bzero(buffer, size);
8435 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
8436 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
8437 cmd->set_cmdsize(size);
8438 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
8439 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
8443 template <typename A>
8444 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
8446 return fEncodedData.size();
8449 template <typename A>
8450 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
8452 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
8456 template <typename A>
8457 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
8459 pint_t addr = fWriter.fOptions.baseAddress();
8460 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
8461 pint_t nextAddr = it->atom->getAddress() + it->offset;
8462 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
8463 uint64_t delta = nextAddr - addr;
8465 throw "double split seg info for same address";
8469 byte = delta & 0x7F;
8473 fEncodedData.push_back(byte);
8476 while( byte >= 0x80 );
8481 template <typename A>
8482 void SegmentSplitInfoContentAtom<A>::encode()
8484 if ( ! fCantEncode ) {
8485 fEncodedData.reserve(8192);
8487 if ( fKind1Locations.size() != 0 ) {
8488 fEncodedData.push_back(1);
8489 //fprintf(stderr, "type 1:\n");
8490 this->uleb128EncodeAddresses(fKind1Locations);
8491 fEncodedData.push_back(0);
8494 if ( fKind2Locations.size() != 0 ) {
8495 fEncodedData.push_back(2);
8496 //fprintf(stderr, "type 2:\n");
8497 this->uleb128EncodeAddresses(fKind2Locations);
8498 fEncodedData.push_back(0);
8501 if ( fKind3Locations.size() != 0 ) {
8502 fEncodedData.push_back(3);
8503 //fprintf(stderr, "type 3:\n");
8504 this->uleb128EncodeAddresses(fKind3Locations);
8505 fEncodedData.push_back(0);
8508 if ( fKind4Locations.size() != 0 ) {
8509 fEncodedData.push_back(4);
8510 //fprintf(stderr, "type 4:\n");
8511 this->uleb128EncodeAddresses(fKind4Locations);
8512 fEncodedData.push_back(0);
8515 // always add zero byte to mark end
8516 fEncodedData.push_back(0);
8518 // add zeros to end to align size
8519 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
8520 fEncodedData.push_back(0);
8525 template <typename A>
8526 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
8527 : WriterAtom<A>(writer, getInfoSegment())
8531 // struct objc_image_info {
8532 // uint32_t version; // initially 0
8535 // #define OBJC_IMAGE_SUPPORTS_GC 2
8536 // #define OBJC_IMAGE_GC_ONLY 4
8538 if ( objcReplacementClasses )
8540 switch ( objcConstraint ) {
8541 case ObjectFile::Reader::kObjcNone:
8542 case ObjectFile::Reader::kObjcRetainRelease:
8544 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
8547 case ObjectFile::Reader::kObjcGC:
8551 A::P::E::set32(fContent[1], value);
8554 template <typename A>
8555 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
8557 memcpy(buffer, &fContent[0], 8);
8561 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
8562 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
8563 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
8564 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
8565 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
8566 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
8568 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
8569 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
8570 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
8571 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
8572 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
8575 }; // namespace executable
8576 }; // namespace mach_o
8579 #endif // __EXECUTABLE_MACH_O__