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
6554 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6555 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
6556 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
6557 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
6558 currentSegmentInfo->fInitProtection = it->init;
6559 currentSegmentInfo->fMaxProtection = it->max;
6562 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
6563 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
6564 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
6565 currentSegmentInfo->fIndependentAddress = true;
6566 this->fSegmentInfos.push_back(currentSegmentInfo);
6568 currentSectionInfo = new SectionInfo();
6569 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
6570 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
6571 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
6572 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
6573 // check for -sectalign override
6574 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
6575 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
6576 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
6577 currentSectionInfo->fAlignment = it->alignment;
6579 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
6580 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
6581 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
6582 currentSectionInfo->setIndex(sectionIndex++);
6583 currentSegmentInfo->fSections.push_back(currentSectionInfo);
6585 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
6586 fLoadCommandsSection = currentSectionInfo;
6587 fLoadCommandsSegment = currentSegmentInfo;
6589 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
6590 currentSectionInfo->fAllLazyPointers = true;
6591 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
6592 currentSectionInfo->fAllLazyPointers = true;
6593 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) )
6594 currentSectionInfo->fAllLazyDylibPointers = true;
6595 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
6596 currentSectionInfo->fAllNonLazyPointers = true;
6597 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
6598 currentSectionInfo->fAllNonLazyPointers = true;
6599 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
6600 currentSectionInfo->fAllNonLazyPointers = true;
6601 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
6602 currentSectionInfo->fAllStubs = true;
6603 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
6604 currentSectionInfo->fAllStubs = true;
6605 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
6606 currentSectionInfo->fAllStubs = true;
6607 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
6608 currentSectionInfo->fAllStubs = true;
6609 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) )
6610 currentSectionInfo->fAllStubs = true;
6611 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) )
6612 currentSectionInfo->fAllStubs = true;
6613 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
6614 currentSectionInfo->fAllSelfModifyingStubs = true;
6615 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
6617 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) )
6618 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
6619 curSection = atom->getSection();
6620 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers
6621 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) {
6622 fSymbolTableCommands->needDynamicTable();
6625 // any non-zero fill atoms make whole section marked not-zero-fill
6626 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
6627 currentSectionInfo->fAllZeroFill = false;
6628 // change section object to be Writer's SectionInfo object
6629 atom->setSection(currentSectionInfo);
6630 // section alignment is that of a contained atom with the greatest alignment
6631 uint8_t atomAlign = atom->getAlignment().powerOf2;
6632 if ( currentSectionInfo->fAlignment < atomAlign )
6633 currentSectionInfo->fAlignment = atomAlign;
6634 // calculate section offset for this atom
6635 uint64_t offset = currentSectionInfo->fSize;
6636 uint64_t alignment = 1 << atomAlign;
6637 uint64_t currentModulus = (offset % alignment);
6638 uint64_t requiredModulus = atom->getAlignment().modulus;
6639 if ( currentModulus != requiredModulus ) {
6640 if ( requiredModulus > currentModulus )
6641 offset += requiredModulus-currentModulus;
6643 offset += requiredModulus+alignment-currentModulus;
6645 atom->setSectionOffset(offset);
6646 uint64_t curAtomSize = atom->getSize();
6647 currentSectionInfo->fSize = offset + curAtomSize;
6648 // add atom to section vector
6649 currentSectionInfo->fAtoms.push_back(atom);
6650 // update largest size
6651 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
6652 fLargestAtomSize = curAtomSize;
6654 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
6655 // when merging cstring sections in .o files, all strings need to use the max alignment
6656 uint64_t offset = 0;
6657 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
6658 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
6659 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
6660 ObjectFile::Atom* atom = *it;
6661 atom->setSectionOffset(offset);
6662 offset += atom->getSize();
6664 cstringSectionInfo->fSize = offset;
6669 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
6670 class TargetAndOffsetComparor
6673 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
6675 if ( left.atom != right.atom )
6676 return ( left.atom < right.atom );
6677 return ( left.offset < right.offset );
6682 bool Writer<ppc>::addBranchIslands()
6684 return this->addPPCBranchIslands();
6688 bool Writer<ppc64>::addBranchIslands()
6690 return this->addPPCBranchIslands();
6694 bool Writer<x86>::addBranchIslands()
6696 // x86 branches can reach entire 4G address space, so no need for branch islands
6701 bool Writer<x86_64>::addBranchIslands()
6703 // x86 branches can reach entire 4G size of largest image
6708 bool Writer<arm>::addBranchIslands()
6710 // arm branch islands not (yet) supported
6711 // you can instead compile with -mlong-call
6716 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
6719 case ppc::kBranch24:
6720 case ppc::kBranch24WeakImport:
6727 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
6730 case ppc64::kBranch24:
6731 case ppc64::kBranch24WeakImport:
6738 // PowerPC can do PC relative branches as far as +/-16MB.
6739 // If a branch target is >16MB then we insert one or more
6740 // "branch islands" between the branch and its target that
6741 // allows island hoping to the target.
6743 // Branch Island Algorithm
6745 // If the __TEXT segment < 16MB, then no branch islands needed
6746 // Otherwise, every 15MB into the __TEXT segment is region is
6747 // added which can contain branch islands. Every out of range
6748 // bl instruction is checked. If it crosses a region, an island
6749 // is added to that region with the same target and the bl is
6750 // adjusted to target the island instead.
6752 // In theory, if too many islands are added to one region, it
6753 // could grow the __TEXT enough that other previously in-range
6754 // bl branches could be pushed out of range. We reduce the
6755 // probability this could happen by placing the ranges every
6756 // 15MB which means the region would have to be 1MB (256K islands)
6757 // before any branches could be pushed out of range.
6759 template <typename A>
6760 bool Writer<A>::addPPCBranchIslands()
6763 bool result = false;
6764 // Can only possibly need branch islands if __TEXT segment > 16M
6765 if ( fLoadCommandsSegment->fSize > 16000000 ) {
6766 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
6767 const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section
6768 SectionInfo* textSection = NULL;
6769 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
6770 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
6772 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
6776 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
6777 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
6778 AtomToIsland regionsMap[kIslandRegionsCount];
6779 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
6780 unsigned int islandCount = 0;
6781 if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
6783 // create islands for branch references that are out of range
6784 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6785 ObjectFile::Atom* atom = *it;
6786 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6787 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6788 ObjectFile::Reference* ref = *rit;
6789 if ( this->isBranch24Reference(ref->getKind()) ) {
6790 ObjectFile::Atom& target = ref->getTarget();
6791 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
6792 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
6793 int64_t displacement = dstAddr - srcAddr;
6794 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
6795 const int64_t kFifteenMegLimit = kBetweenRegions;
6796 if ( displacement > kFifteenMegLimit ) {
6797 // create forward branch chain
6798 ObjectFile::Atom* nextTarget = ⌖
6799 uint64_t nextTargetOffset = ref->getTargetOffset();
6800 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
6801 AtomToIsland* region = ®ionsMap[i];
6802 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
6803 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
6804 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
6805 if ( pos == region->end() ) {
6806 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
6807 island->setSection(textSection);
6808 (*region)[finalTargetAndOffset] = island;
6809 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
6810 regionsIslands[i].push_back(island);
6812 nextTarget = island;
6813 nextTargetOffset = 0;
6816 nextTarget = pos->second;
6817 nextTargetOffset = 0;
6821 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
6822 ref->setTarget(*nextTarget, nextTargetOffset);
6824 else if ( displacement < (-kFifteenMegLimit) ) {
6825 // create back branching chain
6826 ObjectFile::Atom* prevTarget = ⌖
6827 uint64_t prevTargetOffset = ref->getTargetOffset();
6828 for (int i=0; i < kIslandRegionsCount ; ++i) {
6829 AtomToIsland* region = ®ionsMap[i];
6830 int64_t islandRegionAddr = kBetweenRegions * (i+1);
6831 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
6832 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
6833 if ( pos == region->end() ) {
6834 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
6835 island->setSection(textSection);
6836 (*region)[finalTargetAndOffset] = island;
6837 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
6838 regionsIslands[i].push_back(island);
6840 prevTarget = island;
6841 prevTargetOffset = 0;
6844 prevTarget = pos->second;
6845 prevTargetOffset = 0;
6849 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
6850 ref->setTarget(*prevTarget, prevTargetOffset);
6856 // insert islands into __text section and adjust section offsets
6857 if ( islandCount > 0 ) {
6858 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
6859 std::vector<ObjectFile::Atom*> newAtomList;
6860 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
6861 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
6862 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
6863 int regionIndex = 0;
6864 uint64_t atomSlide = 0;
6865 uint64_t sectionOffset = 0;
6866 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
6867 ObjectFile::Atom* atom = *it;
6868 if ( atom->getAddress() > islandRegionAddr ) {
6869 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
6870 sectionOffset = islandStartOffset;
6871 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
6872 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
6873 ObjectFile::Atom* islandAtom = *rit;
6874 newAtomList.push_back(islandAtom);
6875 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
6876 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
6877 islandAtom->setSectionOffset(sectionOffset);
6878 sectionOffset += islandAtom->getSize();
6881 islandRegionAddr += kBetweenRegions;
6882 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
6883 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
6885 newAtomList.push_back(atom);
6886 if ( atomSlide != 0 )
6887 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
6889 sectionOffset = textSection->fSize+atomSlide;
6890 // put any remaining islands at end of __text section
6891 if ( regionIndex < kIslandRegionsCount ) {
6892 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
6893 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
6894 ObjectFile::Atom* islandAtom = *rit;
6895 newAtomList.push_back(islandAtom);
6896 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
6897 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
6898 islandAtom->setSectionOffset(sectionOffset);
6899 sectionOffset += islandAtom->getSize();
6903 textSection->fAtoms = newAtomList;
6904 textSection->fSize = sectionOffset;
6913 template <typename A>
6914 void Writer<A>::adjustLoadCommandsAndPadding()
6916 fSegmentCommands->computeSize();
6918 // recompute load command section offsets
6919 uint64_t offset = 0;
6920 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
6921 const unsigned int atomCount = loadCommandAtoms.size();
6922 for (unsigned int i=0; i < atomCount; ++i) {
6923 ObjectFile::Atom* atom = loadCommandAtoms[i];
6924 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
6925 offset = ( (offset+alignment-1) & (-alignment) );
6926 atom->setSectionOffset(offset);
6927 uint32_t atomSize = atom->getSize();
6928 if ( atomSize > fLargestAtomSize )
6929 fLargestAtomSize = atomSize;
6931 fLoadCommandsSection->fSize = offset;
6934 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
6935 const int sectionCount = sectionInfos.size();
6936 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
6937 for(int j=0; j < sectionCount; ++j) {
6938 SectionInfo* curSection = sectionInfos[j];
6939 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
6940 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
6943 uint64_t paddingSize = 0;
6944 if ( fOptions.outputKind() == Options::kDyld ) {
6945 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
6946 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
6948 else if ( fOptions.outputKind() == Options::kObjectFile ) {
6949 // mach-o .o files need no padding between load commands and first section
6952 else if ( fOptions.makeEncryptable() ) {
6953 // want load commands to end on a page boundary, so __text starts on page boundary
6954 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
6955 fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfHeaderAndLoadCommands+paddingSize);
6958 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
6960 for(int j=sectionCount-1; j >=0; --j) {
6961 SectionInfo* curSection = sectionInfos[j];
6962 addr -= curSection->fSize;
6963 addr = addr & (0 - (1 << curSection->fAlignment));
6964 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
6965 addr -= totalSizeOfHeaderAndLoadCommands;
6966 paddingSize = addr % 4096;
6971 // if command line requires more padding than this
6972 uint32_t minPad = fOptions.minimumHeaderPad();
6973 if ( fOptions.maxMminimumHeaderPad() ) {
6974 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
6975 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
6976 if ( fOptions.outputKind() == Options::kDynamicLibrary )
6977 altMin += MAXPATHLEN;
6978 if ( altMin > minPad )
6981 if ( paddingSize < minPad ) {
6982 int extraPages = (minPad - paddingSize + 4095)/4096;
6983 paddingSize += extraPages * 4096;
6987 // adjust atom size and update section size
6988 fHeaderPadding->setSize(paddingSize);
6989 for(int j=0; j < sectionCount; ++j) {
6990 SectionInfo* curSection = sectionInfos[j];
6991 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
6992 curSection->fSize = paddingSize;
6996 // assign file offsets and logical address to all segments
6997 template <typename A>
6998 void Writer<A>::assignFileOffsets()
7000 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
7001 bool haveFixedSegments = false;
7002 uint64_t fileOffset = 0;
7003 uint64_t nextContiguousAddress = fOptions.baseAddress();
7004 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
7005 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
7007 // process segments with fixed addresses (-segaddr)
7008 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
7009 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7010 SegmentInfo* curSegment = *segit;
7011 if ( strcmp(curSegment->fName, it->name) == 0 ) {
7012 curSegment->fBaseAddress = it->address;
7013 curSegment->fFixedAddress = true;
7019 // Run through the segments and each segment's sections to assign addresses
7020 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7021 SegmentInfo* curSegment = *segit;
7023 if ( fOptions.splitSeg() ) {
7024 if ( curSegment->fInitProtection & VM_PROT_WRITE )
7025 nextContiguousAddress = nextWritableAddress;
7027 nextContiguousAddress = nextReadOnlyAddress;
7030 fileOffset = (fileOffset+4095) & (-4096);
7031 curSegment->fFileOffset = fileOffset;
7033 // Set the segment base address
7034 if ( curSegment->fFixedAddress )
7035 haveFixedSegments = true;
7037 curSegment->fBaseAddress = nextContiguousAddress;
7039 // We've set the segment address, now run through each section.
7040 uint64_t address = curSegment->fBaseAddress;
7041 SectionInfo* firstZeroFillSection = NULL;
7042 SectionInfo* prevSection = NULL;
7044 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
7046 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
7047 SectionInfo* curSection = *it;
7049 // adjust section address based on alignment
7050 uint64_t alignment = 1 << curSection->fAlignment;
7051 address = ( (address+alignment-1) & (-alignment) );
7053 // adjust file offset to match address
7054 if ( prevSection != NULL ) {
7055 if ( finalLinkedImage || !prevSection->fVirtualSection )
7056 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
7058 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
7061 // update section info
7062 curSection->fFileOffset = fileOffset;
7063 curSection->setBaseAddress(address);
7064 //fprintf(stderr, "%s %s %llX\n", curSegment->fName, curSection->fSectionName, address);
7066 // keep track of trailing zero fill sections
7067 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
7068 firstZeroFillSection = curSection;
7069 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
7070 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
7072 // update running pointers
7073 if ( finalLinkedImage || !curSection->fVirtualSection )
7074 address += curSection->fSize;
7075 fileOffset += curSection->fSize;
7077 // sanity check size of 32-bit binaries
7078 if ( address > maxAddress() )
7079 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
7081 // update segment info
7082 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
7083 curSegment->fSize = curSegment->fFileSize;
7084 prevSection = curSection;
7087 if ( fOptions.outputKind() == Options::kObjectFile ) {
7088 // don't page align .o files
7091 // optimize trailing zero-fill sections to not occupy disk space
7092 if ( firstZeroFillSection != NULL ) {
7093 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
7094 fileOffset = firstZeroFillSection->fFileOffset;
7096 // page align segment size
7097 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
7098 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
7099 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
7100 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
7101 if ( curSegment->fInitProtection & VM_PROT_WRITE )
7102 nextWritableAddress = nextContiguousAddress;
7104 nextReadOnlyAddress = nextContiguousAddress;
7109 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
7110 if ( haveFixedSegments ) {
7111 int segCount = fSegmentInfos.size();
7112 for(int i=0; i < segCount; ++i) {
7113 SegmentInfo* segment1 = fSegmentInfos[i];
7115 for(int j=0; j < segCount; ++j) {
7117 SegmentInfo* segment2 = fSegmentInfos[j];
7119 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
7120 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
7121 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7122 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7124 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
7125 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
7126 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7127 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7129 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
7130 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7131 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7138 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
7139 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7140 SegmentInfo* curSegment = *segit;
7141 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
7142 if ( fFirstWritableSegment == NULL )
7143 fFirstWritableSegment = curSegment;
7144 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
7145 fWritableSegmentPastFirst4GB = true;
7149 // record size of encrypted part of __TEXT segment
7150 if ( fOptions.makeEncryptable() ) {
7151 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7152 SegmentInfo* curSegment = *segit;
7153 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
7154 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
7162 template <typename A>
7163 void Writer<A>::adjustLinkEditSections()
7165 // link edit content is always in last segment
7166 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
7167 unsigned int firstLinkEditSectionIndex = 0;
7168 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
7169 ++firstLinkEditSectionIndex;
7171 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
7172 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
7173 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
7174 if ( fPadSegmentInfo != NULL ) {
7175 // insert __4GBFILL segment into segments vector before LINKEDIT
7176 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
7177 if ( *it == lastSeg ) {
7178 fSegmentInfos.insert(it, fPadSegmentInfo);
7182 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
7183 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
7184 fPadSegmentInfo->fBaseAddress = address;
7185 // adjust LINKEDIT to start at zeroPageSize
7186 address = fOptions.zeroPageSize();
7187 lastSeg->fBaseAddress = fOptions.zeroPageSize();
7189 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
7190 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
7191 // adjust section address based on alignment
7192 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
7193 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
7195 fileOffset += pad; // adjust file offset to match address
7196 lastSeg->fSections[i]->setBaseAddress(address);
7197 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
7198 lastSeg->fSections[i]->setBaseAddress(0);
7199 lastSeg->fSections[i]->fFileOffset = fileOffset;
7200 uint64_t sectionOffset = 0;
7201 for (unsigned int j=0; j < atoms.size(); ++j) {
7202 ObjectFile::Atom* atom = atoms[j];
7203 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
7204 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
7205 atom->setSectionOffset(sectionOffset);
7206 uint64_t size = atom->getSize();
7207 sectionOffset += size;
7208 if ( size > fLargestAtomSize )
7209 fLargestAtomSize = size;
7211 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
7212 lastSeg->fSections[i]->fSize = sectionOffset;
7213 fileOffset += sectionOffset;
7214 address += sectionOffset;
7216 if ( fOptions.outputKind() == Options::kObjectFile ) {
7217 //lastSeg->fBaseAddress = 0;
7218 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
7219 //lastSeg->fFileOffset = 0;
7220 //lastSeg->fFileSize =
7223 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
7224 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
7229 template <typename A>
7230 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
7232 switch ( fWriter.fOptions.outputKind() ) {
7233 case Options::kDynamicExecutable:
7234 case Options::kStaticExecutable:
7235 return ObjectFile::Atom::scopeGlobal;
7236 case Options::kDynamicLibrary:
7237 case Options::kDynamicBundle:
7238 case Options::kDyld:
7239 case Options::kObjectFile:
7240 return ObjectFile::Atom::scopeLinkageUnit;
7242 throw "unknown header type";
7245 template <typename A>
7246 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
7248 switch ( fWriter.fOptions.outputKind() ) {
7249 case Options::kDynamicExecutable:
7250 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
7251 case Options::kStaticExecutable:
7252 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
7253 case Options::kDynamicLibrary:
7254 case Options::kDynamicBundle:
7255 case Options::kDyld:
7256 return ObjectFile::Atom::kSymbolTableIn;
7257 case Options::kObjectFile:
7258 return ObjectFile::Atom::kSymbolTableNotIn;
7260 throw "unknown header type";
7263 template <typename A>
7264 const char* MachHeaderAtom<A>::getName() const
7266 switch ( fWriter.fOptions.outputKind() ) {
7267 case Options::kDynamicExecutable:
7268 case Options::kStaticExecutable:
7269 return "__mh_execute_header";
7270 case Options::kDynamicLibrary:
7271 return "__mh_dylib_header";
7272 case Options::kDynamicBundle:
7273 return "__mh_bundle_header";
7274 case Options::kObjectFile:
7276 case Options::kDyld:
7277 return "__mh_dylinker_header";
7279 throw "unknown header type";
7282 template <typename A>
7283 const char* MachHeaderAtom<A>::getDisplayName() const
7285 switch ( fWriter.fOptions.outputKind() ) {
7286 case Options::kDynamicExecutable:
7287 case Options::kStaticExecutable:
7288 case Options::kDynamicLibrary:
7289 case Options::kDynamicBundle:
7290 case Options::kDyld:
7291 return this->getName();
7292 case Options::kObjectFile:
7293 return "mach header";
7295 throw "unknown header type";
7298 template <typename A>
7299 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
7302 uint32_t fileType = 0;
7303 switch ( fWriter.fOptions.outputKind() ) {
7304 case Options::kDynamicExecutable:
7305 case Options::kStaticExecutable:
7306 fileType = MH_EXECUTE;
7308 case Options::kDynamicLibrary:
7309 fileType = MH_DYLIB;
7311 case Options::kDynamicBundle:
7312 fileType = MH_BUNDLE;
7314 case Options::kObjectFile:
7315 fileType = MH_OBJECT;
7317 case Options::kDyld:
7318 fileType = MH_DYLINKER;
7324 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
7325 if ( fWriter.fCanScatter )
7326 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
7329 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
7330 flags |= MH_NOUNDEFS;
7333 flags = MH_DYLDLINK;
7334 if ( fWriter.fOptions.bindAtLoad() )
7335 flags |= MH_BINDATLOAD;
7336 switch ( fWriter.fOptions.nameSpace() ) {
7337 case Options::kTwoLevelNameSpace:
7338 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
7340 case Options::kFlatNameSpace:
7342 case Options::kForceFlatNameSpace:
7343 flags |= MH_FORCE_FLAT;
7346 if ( fWriter.fHasWeakExports )
7347 flags |= MH_WEAK_DEFINES;
7348 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
7349 flags |= MH_BINDS_TO_WEAK;
7350 if ( fWriter.fOptions.prebind() )
7351 flags |= MH_PREBOUND;
7352 if ( fWriter.fOptions.splitSeg() )
7353 flags |= MH_SPLIT_SEGS;
7354 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
7355 flags |= MH_NO_REEXPORTED_DYLIBS;
7356 if ( fWriter.fOptions.positionIndependentExecutable() )
7359 if ( fWriter.fOptions.hasExecutableStack() )
7360 flags |= MH_ALLOW_STACK_EXECUTION;
7361 if ( fWriter.fOptions.readerOptions().fRootSafe )
7362 flags |= MH_ROOT_SAFE;
7363 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
7364 flags |= MH_SETUID_SAFE;
7367 // get commands info
7368 uint32_t commandsSize = 0;
7369 uint32_t commandsCount = 0;
7371 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
7372 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
7373 ObjectFile::Atom* atom = *it;
7374 commandsSize += atom->getSize();
7375 // segment and symbol table atoms can contain more than one load command
7376 if ( atom == fWriter.fSegmentCommands )
7377 commandsCount += fWriter.fSegmentCommands->commandCount();
7378 else if ( atom == fWriter.fSymbolTableCommands )
7379 commandsCount += fWriter.fSymbolTableCommands->commandCount();
7380 else if ( atom->getSize() != 0 )
7384 // fill out mach_header
7385 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
7387 mh->set_filetype(fileType);
7388 mh->set_ncmds(commandsCount);
7389 mh->set_sizeofcmds(commandsSize);
7390 mh->set_flags(flags);
7394 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
7396 header.set_magic(MH_MAGIC);
7397 header.set_cputype(CPU_TYPE_POWERPC);
7398 header.set_cpusubtype(fWriter.fCpuConstraint);
7402 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
7404 header.set_magic(MH_MAGIC_64);
7405 header.set_cputype(CPU_TYPE_POWERPC64);
7406 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7407 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
7409 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
7410 header.set_reserved(0);
7414 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
7416 header.set_magic(MH_MAGIC);
7417 header.set_cputype(CPU_TYPE_I386);
7418 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
7422 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
7424 header.set_magic(MH_MAGIC_64);
7425 header.set_cputype(CPU_TYPE_X86_64);
7426 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7427 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
7429 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
7430 header.set_reserved(0);
7434 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
7436 header.set_magic(MH_MAGIC);
7437 header.set_cputype(CPU_TYPE_ARM);
7438 header.set_cpusubtype(fWriter.fCpuConstraint);
7441 template <typename A>
7442 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
7443 : WriterAtom<A>(writer, Segment::fgStackSegment)
7445 if ( stackGrowsDown() )
7446 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
7448 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
7452 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
7453 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
7454 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
7455 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
7456 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
7458 template <typename A>
7459 void SegmentLoadCommandsAtom<A>::computeSize()
7462 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
7463 const int segCount = segmentInfos.size();
7464 for(int i=0; i < segCount; ++i) {
7465 size += sizeof(macho_segment_command<P>);
7466 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
7467 const int sectionCount = sectionInfos.size();
7468 for(int j=0; j < sectionCount; ++j) {
7469 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
7470 size += sizeof(macho_section<P>);
7474 fCommandCount = segCount;
7475 if ( fWriter.fPadSegmentInfo != NULL ) {
7477 fSize += sizeof(macho_segment_command<P>);
7482 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
7484 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7488 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
7490 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
7494 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
7496 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7500 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
7502 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
7506 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
7508 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7511 template <typename A>
7512 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7514 uint64_t size = this->getSize();
7515 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
7516 bzero(buffer, size);
7517 uint8_t* p = buffer;
7518 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
7519 const int segCount = segmentInfos.size();
7520 for(int i=0; i < segCount; ++i) {
7521 SegmentInfo* segInfo = segmentInfos[i];
7522 const int sectionCount = segInfo->fSections.size();
7523 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
7524 cmd->set_cmd(macho_segment_command<P>::CMD);
7525 cmd->set_segname(segInfo->fName);
7526 cmd->set_vmaddr(segInfo->fBaseAddress);
7527 cmd->set_vmsize(segInfo->fSize);
7528 cmd->set_fileoff(segInfo->fFileOffset);
7529 cmd->set_filesize(segInfo->fFileSize);
7530 cmd->set_maxprot(segInfo->fMaxProtection);
7531 cmd->set_initprot(segInfo->fInitProtection);
7532 // add sections array
7533 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
7534 unsigned int sectionsEmitted = 0;
7535 for (int j=0; j < sectionCount; ++j) {
7536 SectionInfo* sectInfo = segInfo->fSections[j];
7537 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
7538 macho_section<P>* sect = §ions[sectionsEmitted++];
7540 // .o file segment does not cover load commands, so recalc at first real section
7541 if ( sectionsEmitted == 1 ) {
7542 cmd->set_vmaddr(sectInfo->getBaseAddress());
7543 cmd->set_fileoff(sectInfo->fFileOffset);
7545 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
7546 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
7548 sect->set_sectname(sectInfo->fSectionName);
7549 sect->set_segname(sectInfo->fSegmentName);
7550 sect->set_addr(sectInfo->getBaseAddress());
7551 sect->set_size(sectInfo->fSize);
7552 sect->set_offset(sectInfo->fFileOffset);
7553 sect->set_align(sectInfo->fAlignment);
7554 if ( sectInfo->fRelocCount != 0 ) {
7555 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
7556 sect->set_nreloc(sectInfo->fRelocCount);
7558 if ( sectInfo->fAllZeroFill ) {
7559 sect->set_flags(S_ZEROFILL);
7560 sect->set_offset(0);
7562 else if ( sectInfo->fAllLazyPointers ) {
7563 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
7564 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7566 else if ( sectInfo->fAllLazyDylibPointers ) {
7567 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
7568 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7570 else if ( sectInfo->fAllNonLazyPointers ) {
7571 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
7572 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7574 else if ( sectInfo->fAllStubs ) {
7575 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
7576 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7577 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
7579 else if ( sectInfo->fAllSelfModifyingStubs ) {
7580 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
7581 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7582 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
7584 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7585 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
7587 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7588 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
7590 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7591 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
7593 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7594 sect->set_flags(S_COALESCED);
7596 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7597 sect->set_flags(S_COALESCED);
7599 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7600 sect->set_flags(S_INTERPOSING);
7602 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7603 sect->set_flags(S_CSTRING_LITERALS);
7605 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7606 sect->set_flags(S_4BYTE_LITERALS);
7608 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7609 sect->set_flags(S_8BYTE_LITERALS);
7611 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7612 sect->set_flags(S_16BYTE_LITERALS);
7614 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
7615 sect->set_flags(S_LITERAL_POINTERS);
7617 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
7618 sect->set_flags(S_LITERAL_POINTERS);
7620 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7621 sect->set_flags(S_DTRACE_DOF);
7623 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7624 sect->set_flags(S_DTRACE_DOF);
7626 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7627 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
7628 if ( sectInfo->fHasTextLocalRelocs )
7629 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
7630 if ( sectInfo->fHasTextExternalRelocs )
7631 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
7635 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
7636 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
7637 cmd->set_nsects(sectionsEmitted);
7642 template <typename A>
7643 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
7644 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
7646 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
7647 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
7648 switch ( fWriter.fOptions.outputKind() ) {
7649 case Options::kDynamicExecutable:
7650 case Options::kDynamicLibrary:
7651 case Options::kDynamicBundle:
7652 case Options::kDyld:
7653 fNeedsDynamicSymbolTable = true;
7655 case Options::kObjectFile:
7656 case Options::kStaticExecutable:
7657 fNeedsDynamicSymbolTable = false;
7660 writer.fSymbolTableCommands = this;
7665 template <typename A>
7666 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
7668 fNeedsDynamicSymbolTable = true;
7672 template <typename A>
7673 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
7675 if ( fNeedsDynamicSymbolTable )
7676 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
7678 return this->alignedSize(sizeof(macho_symtab_command<P>));
7681 template <typename A>
7682 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7684 // build LC_DYSYMTAB command
7685 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
7686 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
7687 symbolTableCmd->set_cmd(LC_SYMTAB);
7688 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
7689 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
7690 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
7691 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
7692 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
7694 // build LC_DYSYMTAB command
7695 if ( fNeedsDynamicSymbolTable ) {
7696 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
7697 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
7698 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
7699 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
7700 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
7701 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
7702 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
7703 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
7704 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
7705 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
7706 if ( fWriter.fModuleInfoAtom != NULL ) {
7707 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
7708 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
7709 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
7710 dynamicSymbolTableCmd->set_nmodtab(1);
7711 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
7712 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
7714 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
7715 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
7716 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
7717 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
7718 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
7719 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
7720 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
7726 template <typename A>
7727 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
7729 return fNeedsDynamicSymbolTable ? 2 : 1;
7732 template <typename A>
7733 uint64_t DyldLoadCommandsAtom<A>::getSize() const
7735 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
7738 template <typename A>
7739 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7741 uint64_t size = this->getSize();
7742 bzero(buffer, size);
7743 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
7744 if ( fWriter.fOptions.outputKind() == Options::kDyld )
7745 cmd->set_cmd(LC_ID_DYLINKER);
7747 cmd->set_cmd(LC_LOAD_DYLINKER);
7748 cmd->set_cmdsize(this->getSize());
7749 cmd->set_name_offset();
7750 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
7753 template <typename A>
7754 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
7756 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
7759 template <typename A>
7760 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7762 uint64_t size = this->getSize();
7764 bzero(buffer, size);
7765 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
7766 cmd->set_cmd(LC_SUB_CLIENT);
7767 cmd->set_cmdsize(size);
7768 cmd->set_client_offset();
7769 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
7773 template <typename A>
7774 uint64_t DylibLoadCommandsAtom<A>::getSize() const
7776 if ( fOptimizedAway ) {
7780 const char* path = fInfo.reader->getInstallPath();
7781 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
7785 template <typename A>
7786 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7788 if ( fOptimizedAway )
7790 uint64_t size = this->getSize();
7791 bzero(buffer, size);
7792 const char* path = fInfo.reader->getInstallPath();
7793 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
7794 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
7795 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
7796 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
7797 if ( fInfo.options.fLazyLoad )
7798 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
7799 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
7800 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
7801 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7802 cmd->set_cmd(LC_REEXPORT_DYLIB);
7804 cmd->set_cmd(LC_LOAD_DYLIB);
7805 cmd->set_cmdsize(this->getSize());
7806 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
7807 cmd->set_current_version(fInfo.reader->getCurrentVersion());
7808 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
7809 cmd->set_name_offset();
7810 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
7815 template <typename A>
7816 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
7818 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
7821 template <typename A>
7822 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7824 uint64_t size = this->getSize();
7825 bzero(buffer, size);
7826 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
7827 cmd->set_cmd(LC_ID_DYLIB);
7828 cmd->set_cmdsize(this->getSize());
7829 cmd->set_name_offset();
7830 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
7831 cmd->set_current_version(fWriter.fOptions.currentVersion());
7832 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
7833 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
7837 template <typename A>
7838 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7840 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7841 if (fWriter.fEntryPoint->isThumb())
7843 bzero(buffer, sizeof(macho_routines_command<P>));
7844 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
7845 cmd->set_cmd(macho_routines_command<P>::CMD);
7846 cmd->set_cmdsize(this->getSize());
7847 cmd->set_init_address(initAddr);
7851 template <typename A>
7852 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
7854 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
7857 template <typename A>
7858 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7860 uint64_t size = this->getSize();
7861 bzero(buffer, size);
7862 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
7863 cmd->set_cmd(LC_SUB_UMBRELLA);
7864 cmd->set_cmdsize(this->getSize());
7865 cmd->set_sub_umbrella_offset();
7866 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
7869 template <typename A>
7870 void UUIDLoadCommandAtom<A>::generate()
7872 switch ( fWriter.fOptions.getUUIDMode() ) {
7873 case Options::kUUIDNone:
7876 case Options::kUUIDRandom:
7877 ::uuid_generate_random(fUUID);
7880 case Options::kUUIDContent:
7887 template <typename A>
7888 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
7890 memcpy(fUUID, uuid, 16);
7893 template <typename A>
7894 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
7897 uint64_t size = this->getSize();
7898 bzero(buffer, size);
7899 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
7900 cmd->set_cmd(LC_UUID);
7901 cmd->set_cmdsize(this->getSize());
7902 cmd->set_uuid((uint8_t*)fUUID);
7907 template <typename A>
7908 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
7910 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
7913 template <typename A>
7914 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7916 uint64_t size = this->getSize();
7917 bzero(buffer, size);
7918 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
7919 cmd->set_cmd(LC_SUB_LIBRARY);
7920 cmd->set_cmdsize(this->getSize());
7921 cmd->set_sub_library_offset();
7922 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
7923 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
7926 template <typename A>
7927 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
7929 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
7932 template <typename A>
7933 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7935 uint64_t size = this->getSize();
7936 bzero(buffer, size);
7937 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
7938 cmd->set_cmd(LC_SUB_FRAMEWORK);
7939 cmd->set_cmdsize(this->getSize());
7940 cmd->set_umbrella_offset();
7941 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
7945 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
7947 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
7951 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
7953 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
7957 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
7959 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
7963 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
7965 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
7968 // We should be picking it up from a header
7970 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
7972 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
7976 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
7978 uint64_t size = this->getSize();
7979 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7980 bzero(buffer, size);
7981 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
7982 cmd->set_cmd(LC_UNIXTHREAD);
7983 cmd->set_cmdsize(size);
7984 cmd->set_flavor(1); // PPC_THREAD_STATE
7985 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
7986 cmd->set_thread_register(0, start);
7987 if ( fWriter.fOptions.hasCustomStack() )
7988 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
7993 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
7995 uint64_t size = this->getSize();
7996 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7997 bzero(buffer, size);
7998 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
7999 cmd->set_cmd(LC_UNIXTHREAD);
8000 cmd->set_cmdsize(size);
8001 cmd->set_flavor(5); // PPC_THREAD_STATE64
8002 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
8003 cmd->set_thread_register(0, start);
8004 if ( fWriter.fOptions.hasCustomStack() )
8005 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
8009 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
8011 uint64_t size = this->getSize();
8012 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8013 bzero(buffer, size);
8014 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
8015 cmd->set_cmd(LC_UNIXTHREAD);
8016 cmd->set_cmdsize(size);
8017 cmd->set_flavor(1); // i386_THREAD_STATE
8018 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
8019 cmd->set_thread_register(10, start);
8020 if ( fWriter.fOptions.hasCustomStack() )
8021 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
8025 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
8027 uint64_t size = this->getSize();
8028 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8029 bzero(buffer, size);
8030 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
8031 cmd->set_cmd(LC_UNIXTHREAD);
8032 cmd->set_cmdsize(size);
8033 cmd->set_flavor(x86_THREAD_STATE64);
8034 cmd->set_count(x86_THREAD_STATE64_COUNT);
8035 cmd->set_thread_register(16, start); // rip
8036 if ( fWriter.fOptions.hasCustomStack() )
8037 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
8041 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
8043 uint64_t size = this->getSize();
8044 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8045 bzero(buffer, size);
8046 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
8047 cmd->set_cmd(LC_UNIXTHREAD);
8048 cmd->set_cmdsize(size);
8051 cmd->set_thread_register(15, start); // pc
8052 if ( fWriter.fOptions.hasCustomStack() )
8053 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
8056 template <typename A>
8057 uint64_t RPathLoadCommandsAtom<A>::getSize() const
8059 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
8062 template <typename A>
8063 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8065 uint64_t size = this->getSize();
8066 bzero(buffer, size);
8067 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
8068 cmd->set_cmd(LC_RPATH);
8069 cmd->set_cmdsize(this->getSize());
8070 cmd->set_path_offset();
8071 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
8076 template <typename A>
8077 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8079 uint64_t size = this->getSize();
8080 bzero(buffer, size);
8081 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
8082 cmd->set_cmd(LC_ENCRYPTION_INFO);
8083 cmd->set_cmdsize(this->getSize());
8084 cmd->set_cryptoff(fStartOffset);
8085 cmd->set_cryptsize(fEndOffset-fStartOffset);
8086 cmd->set_cryptid(0);
8091 template <typename A>
8092 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
8094 bzero(buffer, fSize);
8097 template <typename A>
8098 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
8101 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
8102 if ( fWriter.fLargestAtomSize < newSize )
8103 fWriter.fLargestAtomSize = newSize;
8106 template <typename A>
8107 uint64_t LinkEditAtom<A>::getFileOffset() const
8109 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
8113 template <typename A>
8114 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
8116 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
8119 template <typename A>
8120 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8122 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
8126 template <typename A>
8127 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
8129 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
8132 template <typename A>
8133 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8135 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
8140 template <typename A>
8141 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
8143 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
8146 template <typename A>
8147 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8149 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
8152 template <typename A>
8153 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
8155 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
8158 template <typename A>
8159 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8161 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
8162 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
8167 template <typename A>
8168 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
8170 return fTable.size() * sizeof(uint32_t);
8173 template <typename A>
8174 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8176 uint64_t size = this->getSize();
8177 bzero(buffer, size);
8178 const uint32_t indirectTableSize = fTable.size();
8179 uint32_t* indirectTable = (uint32_t*)buffer;
8180 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
8181 if ( it->indirectIndex < indirectTableSize ) {
8182 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
8185 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
8192 template <typename A>
8193 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
8195 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
8196 + sizeof(macho_dylib_module<P>)
8197 + this->getReferencesCount()*sizeof(uint32_t);
8200 template <typename A>
8201 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
8203 return this->getFileOffset();
8206 template <typename A>
8207 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
8209 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
8212 template <typename A>
8213 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
8215 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
8218 template <typename A>
8219 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
8221 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
8224 template <typename A>
8225 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8227 uint64_t size = this->getSize();
8228 bzero(buffer, size);
8229 // create toc. The symbols are already sorted, they are all in the smae module
8230 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
8231 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
8232 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
8233 p->set_module_index(0);
8235 // create module table (one entry)
8236 uint16_t numInits = 0;
8237 uint16_t numTerms = 0;
8238 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
8239 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
8240 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
8241 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
8242 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
8243 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
8244 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
8245 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
8246 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
8250 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
8251 module->set_module_name(fModuleNameOffset);
8252 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
8253 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
8254 module->set_irefsym(0);
8255 module->set_nrefsym(this->getReferencesCount());
8256 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
8257 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
8258 module->set_iextrel(0);
8259 module->set_nextrel(fWriter.fExternalRelocs.size());
8260 module->set_iinit_iterm(0,0);
8261 module->set_ninit_nterm(numInits,numTerms);
8262 module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years
8263 module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years
8264 // create reference table
8265 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
8266 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
8267 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
8268 ref->set_flags(REFERENCE_FLAG_DEFINED);
8270 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
8271 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
8272 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
8273 if ( pos != fWriter.fStubsMap.end() )
8274 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
8276 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
8282 template <typename A>
8283 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
8284 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
8286 fCurrentBuffer = new char[kBufferSize];
8287 // burn first byte of string pool (so zero is never a valid string offset)
8288 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
8289 // make offset 1 always point to an empty string
8290 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
8293 template <typename A>
8294 uint64_t StringsLinkEditAtom<A>::getSize() const
8297 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
8300 template <typename A>
8301 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8303 uint64_t offset = 0;
8304 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
8305 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
8306 offset += kBufferSize;
8308 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
8309 // zero fill end to align
8310 offset += fCurrentBufferUsed;
8311 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
8312 buffer[offset++] = 0;
8315 template <typename A>
8316 int32_t StringsLinkEditAtom<A>::add(const char* name)
8318 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
8319 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
8320 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
8321 fCurrentBufferUsed += lenNeeded;
8324 int copied = kBufferSize-fCurrentBufferUsed-1;
8325 // change trailing '\0' that strlcpy added to real char
8326 fCurrentBuffer[kBufferSize-1] = name[copied];
8327 // alloc next buffer
8328 fFullBuffers.push_back(fCurrentBuffer);
8329 fCurrentBuffer = new char[kBufferSize];
8330 fCurrentBufferUsed = 0;
8331 // append rest of string
8332 this->add(&name[copied+1]);
8338 template <typename A>
8339 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
8341 StringToOffset::iterator pos = fUniqueStrings.find(name);
8342 if ( pos != fUniqueStrings.end() ) {
8346 int32_t offset = this->add(name);
8347 fUniqueStrings[name] = offset;
8353 template <typename A>
8354 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
8356 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
8357 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
8358 // check for out of bounds
8359 if ( index > maxIndex )
8361 // check for index in fCurrentBuffer
8362 if ( index > currentBufferStartIndex )
8363 return &fCurrentBuffer[index-currentBufferStartIndex];
8364 // otherwise index is in a full buffer
8365 uint32_t fullBufferIndex = index/kBufferSize;
8366 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
8371 template <typename A>
8372 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
8373 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
8375 char* buf = new char[strlen(name)+32];
8376 if ( targetOffset == 0 ) {
8377 if ( islandRegion == 0 )
8378 sprintf(buf, "%s$island", name);
8380 sprintf(buf, "%s$island_%d", name, islandRegion);
8383 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
8390 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
8392 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
8393 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
8394 OSWriteBigInt32(buffer, 0, branchInstruction);
8398 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
8400 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
8401 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
8402 OSWriteBigInt32(buffer, 0, branchInstruction);
8406 uint64_t BranchIslandAtom<ppc>::getSize() const
8412 uint64_t BranchIslandAtom<ppc64>::getSize() const
8419 template <typename A>
8420 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
8422 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
8423 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
8425 return 0; // a zero size causes the load command to be suppressed
8428 template <typename A>
8429 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8431 uint64_t size = this->getSize();
8432 bzero(buffer, size);
8433 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
8434 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
8435 cmd->set_cmdsize(size);
8436 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
8437 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
8441 template <typename A>
8442 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
8444 return fEncodedData.size();
8447 template <typename A>
8448 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
8450 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
8454 template <typename A>
8455 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
8457 pint_t addr = fWriter.fOptions.baseAddress();
8458 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
8459 pint_t nextAddr = it->atom->getAddress() + it->offset;
8460 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
8461 uint64_t delta = nextAddr - addr;
8463 throw "double split seg info for same address";
8467 byte = delta & 0x7F;
8471 fEncodedData.push_back(byte);
8474 while( byte >= 0x80 );
8479 template <typename A>
8480 void SegmentSplitInfoContentAtom<A>::encode()
8482 if ( ! fCantEncode ) {
8483 fEncodedData.reserve(8192);
8485 if ( fKind1Locations.size() != 0 ) {
8486 fEncodedData.push_back(1);
8487 //fprintf(stderr, "type 1:\n");
8488 this->uleb128EncodeAddresses(fKind1Locations);
8489 fEncodedData.push_back(0);
8492 if ( fKind2Locations.size() != 0 ) {
8493 fEncodedData.push_back(2);
8494 //fprintf(stderr, "type 2:\n");
8495 this->uleb128EncodeAddresses(fKind2Locations);
8496 fEncodedData.push_back(0);
8499 if ( fKind3Locations.size() != 0 ) {
8500 fEncodedData.push_back(3);
8501 //fprintf(stderr, "type 3:\n");
8502 this->uleb128EncodeAddresses(fKind3Locations);
8503 fEncodedData.push_back(0);
8506 if ( fKind4Locations.size() != 0 ) {
8507 fEncodedData.push_back(4);
8508 //fprintf(stderr, "type 4:\n");
8509 this->uleb128EncodeAddresses(fKind4Locations);
8510 fEncodedData.push_back(0);
8513 // always add zero byte to mark end
8514 fEncodedData.push_back(0);
8516 // add zeros to end to align size
8517 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
8518 fEncodedData.push_back(0);
8523 template <typename A>
8524 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
8525 : WriterAtom<A>(writer, getInfoSegment())
8529 // struct objc_image_info {
8530 // uint32_t version; // initially 0
8533 // #define OBJC_IMAGE_SUPPORTS_GC 2
8534 // #define OBJC_IMAGE_GC_ONLY 4
8536 if ( objcReplacementClasses )
8538 switch ( objcConstraint ) {
8539 case ObjectFile::Reader::kObjcNone:
8540 case ObjectFile::Reader::kObjcRetainRelease:
8542 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
8545 case ObjectFile::Reader::kObjcGC:
8549 A::P::E::set32(fContent[1], value);
8552 template <typename A>
8553 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
8555 memcpy(buffer, &fContent[0], 8);
8559 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
8560 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
8561 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
8562 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
8563 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
8564 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
8566 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
8567 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
8568 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
8569 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
8570 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
8573 }; // namespace executable
8574 }; // namespace mach_o
8577 #endif // __EXECUTABLE_MACH_O__