1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2006 Apple Computer, 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 <mach-o/loader.h>
33 #include <mach-o/nlist.h>
34 #include <mach-o/reloc.h>
35 //#include <mach-o/ppc/reloc.h>
36 #include <mach-o/stab.h>
37 #include <uuid/uuid.h>
38 #include <mach/i386/thread_status.h>
39 #include <mach/ppc/thread_status.h>
45 #include <ext/hash_map>
47 #include "ObjectFile.h"
48 #include "ExecutableFile.h"
51 #include "MachOFileAbstraction.hpp"
56 // To implement architecture xxx, you must write template specializations for the following methods:
57 // MachHeaderAtom<xxx>::setHeaderInfo()
58 // ThreadsLoadCommandsAtom<xxx>::getSize()
59 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
60 // Writer<xxx>::addObjectRelocs()
61 // Writer<xxx>::fixUpReferenceRelocatable()
62 // Writer<xxx>::fixUpReferenceFinal()
63 // Writer<xxx>::stubableReferenceKind()
64 // Writer<xxx>::weakImportReferenceKind()
65 // Writer<xxx>::GOTReferenceKind()
70 namespace executable {
73 template <typename A> class WriterAtom;
74 template <typename A> class PageZeroAtom;
75 template <typename A> class CustomStackAtom;
76 template <typename A> class MachHeaderAtom;
77 template <typename A> class SegmentLoadCommandsAtom;
78 template <typename A> class SymbolTableLoadCommandsAtom;
79 template <typename A> class ThreadsLoadCommandsAtom;
80 template <typename A> class DylibIDLoadCommandsAtom;
81 template <typename A> class RoutinesLoadCommandsAtom;
82 template <typename A> class DyldLoadCommandsAtom;
83 template <typename A> class UUIDLoadCommandAtom;
84 template <typename A> class LinkEditAtom;
85 template <typename A> class SectionRelocationsLinkEditAtom;
86 template <typename A> class LocalRelocationsLinkEditAtom;
87 template <typename A> class ExternalRelocationsLinkEditAtom;
88 template <typename A> class SymbolTableLinkEditAtom;
89 template <typename A> class IndirectTableLinkEditAtom;
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;
98 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
99 class SectionInfo : public ObjectFile::Section {
101 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0),
102 fAlignment(0), fAllLazyPointers(false), fAllNonLazyPointers(false), fAllStubs(false),
103 fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false)
104 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
105 void setIndex(unsigned int index) { fIndex=index; }
106 std::vector<ObjectFile::Atom*> fAtoms;
107 char fSegmentName[20];
108 char fSectionName[20];
109 uint64_t fFileOffset;
111 uint32_t fRelocCount;
112 uint32_t fRelocOffset;
113 uint32_t fIndirectSymbolOffset;
115 bool fAllLazyPointers;
116 bool fAllNonLazyPointers;
118 bool fAllSelfModifyingStubs;
120 bool fVirtualSection;
123 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
127 SegmentInfo() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
128 fBaseAddress(0), fSize(0), fFixedAddress(false) { fName[0] = '\0'; }
129 std::vector<class SectionInfo*> fSections;
131 uint32_t fInitProtection;
132 uint32_t fMaxProtection;
133 uint64_t fFileOffset;
135 uint64_t fBaseAddress;
140 template <typename A>
141 class Writer : public ExecutableFile::Writer
144 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
147 virtual const char* getPath() { return fFilePath; }
148 virtual time_t getModificationTime() { return 0; }
149 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
150 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
151 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
152 virtual std::vector<Stab>* getStabs() { return NULL; }
154 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
155 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
156 std::vector<class ObjectFile::Reader::Stab>& stabs,
157 class ObjectFile::Atom* entryPointAtom,
158 class ObjectFile::Atom* dyldHelperAtom,
162 typedef typename A::P P;
163 typedef typename A::P::uint_t pint_t;
165 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
167 void assignFileOffsets();
168 void synthesizeStubs();
169 void partitionIntoSections();
170 bool addBranchIslands();
171 bool addPPCBranchIslands();
172 uint8_t branch24Reference();
173 void adjustLoadCommandsAndPadding();
174 void createDynamicLinkerCommand();
175 void createDylibCommands();
176 void buildLinkEdit();
177 uint64_t writeAtoms();
178 void writeNoOps(uint32_t from, uint32_t to);
179 void collectExportedAndImportedAndLocalAtoms();
180 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
181 void buildSymbolTable();
182 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
183 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
184 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
185 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
186 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
187 bool shouldExport(const ObjectFile::Atom& atom) const;
189 void adjustLinkEditSections();
190 void buildObjectFileFixups();
191 void buildExecutableFixups();
192 bool referenceRequiresRuntimeFixUp(const ObjectFile::Reference* ref, bool slideable) const;
193 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
194 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
195 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
196 uint8_t buffer[], bool finalLinkedImage) const;
197 uint32_t symbolIndex(ObjectFile::Atom& atom);
198 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
199 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
200 uint8_t getRelocPointerSize();
201 bool stubableReferenceKind(uint8_t kind);
202 bool GOTReferenceKind(uint8_t kind);
203 bool weakImportReferenceKind(uint8_t kind);
204 unsigned int collectStabs();
205 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
206 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
207 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
208 void addStabs(uint32_t startIndex);
209 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
210 bool illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable);
213 struct DirectLibrary {
214 class ObjectFile::Reader* fLibrary;
219 friend class WriterAtom<A>;
220 friend class PageZeroAtom<A>;
221 friend class CustomStackAtom<A>;
222 friend class MachHeaderAtom<A>;
223 friend class SegmentLoadCommandsAtom<A>;
224 friend class SymbolTableLoadCommandsAtom<A>;
225 friend class ThreadsLoadCommandsAtom<A>;
226 friend class DylibIDLoadCommandsAtom<A>;
227 friend class RoutinesLoadCommandsAtom<A>;
228 friend class DyldLoadCommandsAtom<A>;
229 friend class UUIDLoadCommandAtom<A>;
230 friend class LinkEditAtom<A>;
231 friend class SectionRelocationsLinkEditAtom<A>;
232 friend class LocalRelocationsLinkEditAtom<A>;
233 friend class ExternalRelocationsLinkEditAtom<A>;
234 friend class SymbolTableLinkEditAtom<A>;
235 // friend class IndirectTableLinkEditAtom<A>;
236 friend class StringsLinkEditAtom<A>;
237 friend class LoadCommandsPaddingAtom<A>;
238 friend class StubAtom<A>;
239 friend class StubHelperAtom<A>;
240 friend class LazyPointerAtom<A>;
241 friend class NonLazyPointerAtom<A>;
243 const char* fFilePath;
246 std::vector<class ObjectFile::Atom*>* fAllAtoms;
247 std::vector<class ObjectFile::Reader::Stab>* fStabs;
248 class SectionInfo* fLoadCommandsSection;
249 class SegmentInfo* fLoadCommandsSegment;
250 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
251 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
252 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
253 class UUIDLoadCommandAtom<A>* fUUIDAtom;
254 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
255 std::vector<SegmentInfo*> fSegmentInfos;
256 class ObjectFile::Atom* fEntryPoint;
257 class ObjectFile::Atom* fDyldHelper;
258 std::vector<DirectLibrary> fDirectLibraries;
259 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
260 std::vector<class ObjectFile::Atom*> fExportedAtoms;
261 std::vector<class ObjectFile::Atom*> fImportedAtoms;
262 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
263 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
264 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
265 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
266 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
267 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
268 class StringsLinkEditAtom<A>* fStringsAtom;
269 macho_nlist<P>* fSymbolTable;
270 std::vector<macho_relocation_info<P> > fSectionRelocs;
271 std::vector<macho_relocation_info<P> > fInternalRelocs;
272 std::vector<macho_relocation_info<P> > fExternalRelocs;
273 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
274 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
275 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
276 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
277 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
278 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
279 uint32_t fSymbolTableCount;
280 uint32_t fSymbolTableStabsCount;
281 uint32_t fSymbolTableStabsStartIndex;
282 uint32_t fSymbolTableLocalCount;
283 uint32_t fSymbolTableLocalStartIndex;
284 uint32_t fSymbolTableExportCount;
285 uint32_t fSymbolTableExportStartIndex;
286 uint32_t fSymbolTableImportCount;
287 uint32_t fSymbolTableImportStartIndex;
288 uint32_t fLargestAtomSize;
289 bool fEmitVirtualSections;
290 bool fHasWeakExports;
291 bool fReferencesWeakImports;
292 bool fSeenFollowOnReferences;
293 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
297 class Segment : public ObjectFile::Segment
300 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
301 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
302 virtual const char* getName() const { return fName; }
303 virtual bool isContentReadable() const { return fReadable; }
304 virtual bool isContentWritable() const { return fWritable; }
305 virtual bool isContentExecutable() const { return fExecutable; }
306 virtual bool hasFixedAddress() const { return fFixedAddress; }
308 static Segment fgTextSegment;
309 static Segment fgPageZeroSegment;
310 static Segment fgLinkEditSegment;
311 static Segment fgStackSegment;
312 static Segment fgImportSegment;
313 static Segment fgDataSegment;
316 const bool fReadable;
317 const bool fWritable;
318 const bool fExecutable;
319 const bool fFixedAddress;
322 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
323 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
324 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
325 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
326 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
327 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
330 template <typename A>
331 class WriterAtom : public ObjectFile::Atom
334 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
335 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { setDontDeadStrip(); }
337 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
338 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
339 virtual const char* getName() const { return NULL; }
340 virtual const char* getDisplayName() const { return this->getName(); }
341 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
342 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
343 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
344 virtual bool isZeroFill() const { return false; }
345 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
346 virtual bool mustRemainInSection() const { return true; }
347 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
348 virtual bool requiresFollowOnAtom() const { return false; }
349 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
350 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
351 virtual uint8_t getAlignment() const { return 2; }
352 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
353 virtual void setScope(Scope) { }
357 virtual ~WriterAtom() {}
358 typedef typename A::P P;
359 typedef typename A::P::E E;
361 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
367 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
370 template <typename A>
371 class PageZeroAtom : public WriterAtom<A>
374 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment) {}
375 virtual const char* getDisplayName() const { return "page zero content"; }
376 virtual bool isZeroFill() const { return true; }
377 virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); }
378 virtual const char* getSectionName() const { return "._zeropage"; }
379 virtual uint8_t getAlignment() const { return 12; }
381 using WriterAtom<A>::fWriter;
382 typedef typename A::P P;
385 template <typename A>
386 class DsoHandleAtom : public WriterAtom<A>
389 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
390 virtual const char* getName() const { return "___dso_handle"; }
391 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
392 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
393 virtual uint64_t getSize() const { return 0; }
394 virtual uint8_t getAlignment() const { return 12; }
395 virtual const char* getSectionName() const { return "._mach_header"; }
396 virtual void copyRawContent(uint8_t buffer[]) const {}
400 template <typename A>
401 class MachHeaderAtom : public WriterAtom<A>
404 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
405 virtual const char* getName() const;
406 virtual const char* getDisplayName() const;
407 virtual ObjectFile::Atom::Scope getScope() const;
408 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
409 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
410 virtual uint8_t getAlignment() const { return 12; }
411 virtual const char* getSectionName() const { return "._mach_header"; }
412 virtual void copyRawContent(uint8_t buffer[]) const;
414 using WriterAtom<A>::fWriter;
415 typedef typename A::P P;
416 void setHeaderInfo(macho_header<typename A::P>& header) const;
419 template <typename A>
420 class CustomStackAtom : public WriterAtom<A>
423 CustomStackAtom(Writer<A>& writer);
424 virtual const char* getDisplayName() const { return "custom stack content"; }
425 virtual bool isZeroFill() const { return true; }
426 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
427 virtual const char* getSectionName() const { return "._stack"; }
428 virtual uint8_t getAlignment() const { return 12; }
430 using WriterAtom<A>::fWriter;
431 typedef typename A::P P;
432 static bool stackGrowsDown();
435 template <typename A>
436 class LoadCommandAtom : public WriterAtom<A>
439 LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment) {}
440 static uint64_t alignedSize(uint64_t size);
444 template <typename A>
445 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
448 SegmentLoadCommandsAtom(Writer<A>& writer)
449 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0)
450 { writer.fSegmentCommands = this; }
451 virtual const char* getDisplayName() const { return "segment load commands"; }
452 virtual uint64_t getSize() const { return fSize; }
453 virtual uint8_t getAlignment() const { return 2; }
454 virtual const char* getSectionName() const { return "._load_commands"; }
455 virtual void copyRawContent(uint8_t buffer[]) const;
459 unsigned int commandCount() { return fCommandCount; }
460 void assignFileOffsets();
462 using WriterAtom<A>::fWriter;
463 typedef typename A::P P;
464 unsigned int fCommandCount;
468 template <typename A>
469 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
472 SymbolTableLoadCommandsAtom(Writer<A>&);
473 virtual const char* getDisplayName() const { return "symbol table load commands"; }
474 virtual uint64_t getSize() const;
475 virtual uint8_t getAlignment() const { return 2; }
476 virtual const char* getSectionName() const { return "._load_commands"; }
477 virtual void copyRawContent(uint8_t buffer[]) const;
478 unsigned int commandCount();
481 using WriterAtom<A>::fWriter;
482 typedef typename A::P P;
483 macho_symtab_command<typename A::P> fSymbolTable;
484 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
487 template <typename A>
488 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
491 ThreadsLoadCommandsAtom(Writer<A>& writer)
492 : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
493 virtual const char* getDisplayName() const { return "thread load commands"; }
494 virtual uint64_t getSize() const;
495 virtual uint8_t getAlignment() const { return 2; }
496 virtual const char* getSectionName() const { return "._load_commands"; }
497 virtual void copyRawContent(uint8_t buffer[]) const;
499 using WriterAtom<A>::fWriter;
500 typedef typename A::P P;
502 uint32_t fBufferSize;
505 template <typename A>
506 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
509 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
510 virtual const char* getDisplayName() const { return "dyld load command"; }
511 virtual uint64_t getSize() const;
512 virtual uint8_t getAlignment() const { return 2; }
513 virtual const char* getSectionName() const { return "._load_commands"; }
514 virtual void copyRawContent(uint8_t buffer[]) const;
516 using WriterAtom<A>::fWriter;
517 typedef typename A::P P;
520 template <typename A>
521 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
524 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
525 LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
526 virtual const char* getDisplayName() const { return "allowable_client load command"; }
527 virtual uint64_t getSize() const;
528 virtual uint8_t getAlignment() const { return 2; }
529 virtual const char* getSectionName() const { return "._load_commands"; }
530 virtual void copyRawContent(uint8_t buffer[]) const;
532 using WriterAtom<A>::fWriter;
533 typedef typename A::P P;
534 const char* clientString;
537 template <typename A>
538 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
541 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
542 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info) {}
543 virtual const char* getDisplayName() const { return "dylib load command"; }
544 virtual uint64_t getSize() const;
545 virtual uint8_t getAlignment() const { return 2; }
546 virtual const char* getSectionName() const { return "._load_commands"; }
547 virtual void copyRawContent(uint8_t buffer[]) const;
549 using WriterAtom<A>::fWriter;
550 typedef typename A::P P;
551 ExecutableFile::DyLibUsed& fInfo;
554 template <typename A>
555 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
558 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
559 virtual const char* getDisplayName() const { return "dylib ID load command"; }
560 virtual uint64_t getSize() const;
561 virtual uint8_t getAlignment() const { return 2; }
562 virtual const char* getSectionName() const { return "._load_commands"; }
563 virtual void copyRawContent(uint8_t buffer[]) const;
565 using WriterAtom<A>::fWriter;
566 typedef typename A::P P;
569 template <typename A>
570 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
573 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
574 virtual const char* getDisplayName() const { return "routines load command"; }
575 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
576 virtual uint8_t getAlignment() const { return 2; }
577 virtual const char* getSectionName() const { return "._load_commands"; }
578 virtual void copyRawContent(uint8_t buffer[]) const;
580 using WriterAtom<A>::fWriter;
581 typedef typename A::P P;
584 template <typename A>
585 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
588 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
589 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
590 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
591 virtual uint64_t getSize() const;
592 virtual uint8_t getAlignment() const { return 2; }
593 virtual const char* getSectionName() const { return "._load_commands"; }
594 virtual void copyRawContent(uint8_t buffer[]) const;
596 typedef typename A::P P;
600 template <typename A>
601 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
604 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
605 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
606 virtual const char* getDisplayName() const { return "sub-library load command"; }
607 virtual uint64_t getSize() const;
608 virtual uint8_t getAlignment() const { return 2; }
609 virtual const char* getSectionName() const { return "._load_commands"; }
610 virtual void copyRawContent(uint8_t buffer[]) const;
612 using WriterAtom<A>::fWriter;
613 typedef typename A::P P;
614 const char* fNameStart;
618 template <typename A>
619 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
622 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
623 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
624 virtual const char* getDisplayName() const { return "umbrella load command"; }
625 virtual uint64_t getSize() const;
626 virtual uint8_t getAlignment() const { return 2; }
627 virtual const char* getSectionName() const { return "._load_commands"; }
628 virtual void copyRawContent(uint8_t buffer[]) const;
630 using WriterAtom<A>::fWriter;
631 typedef typename A::P P;
635 template <typename A>
636 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
639 UUIDLoadCommandAtom(Writer<A>& writer)
640 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) { ::uuid_generate_random(fUUID);}
641 virtual const char* getDisplayName() const { return "uuid load command"; }
642 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
643 virtual uint8_t getAlignment() const { return 2; }
644 virtual const char* getSectionName() const { return "._load_commands"; }
645 virtual void copyRawContent(uint8_t buffer[]) const;
646 virtual void emit() { fEmit = true; }
648 using WriterAtom<A>::fWriter;
649 typedef typename A::P P;
654 template <typename A>
655 class LoadCommandsPaddingAtom : public WriterAtom<A>
658 LoadCommandsPaddingAtom(Writer<A>& writer)
659 : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
660 virtual const char* getDisplayName() const { return "header padding"; }
661 virtual uint64_t getSize() const { return fSize; }
662 virtual uint8_t getAlignment() const { return 2; }
663 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
664 virtual void copyRawContent(uint8_t buffer[]) const;
666 void setSize(uint64_t newSize);
668 using WriterAtom<A>::fWriter;
669 typedef typename A::P P;
673 template <typename A>
674 class LinkEditAtom : public WriterAtom<A>
677 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment) {}
678 uint64_t getFileOffset() const;
680 typedef typename A::P P;
683 template <typename A>
684 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
687 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
688 virtual const char* getDisplayName() const { return "section relocations"; }
689 virtual uint64_t getSize() const;
690 virtual uint8_t getAlignment() const { return 3; }
691 virtual const char* getSectionName() const { return "._section_relocs"; }
692 virtual void copyRawContent(uint8_t buffer[]) const;
694 using WriterAtom<A>::fWriter;
695 typedef typename A::P P;
698 template <typename A>
699 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
702 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
703 virtual const char* getDisplayName() const { return "local relocations"; }
704 virtual uint64_t getSize() const;
705 virtual uint8_t getAlignment() const { return 3; }
706 virtual const char* getSectionName() const { return "._local_relocs"; }
707 virtual void copyRawContent(uint8_t buffer[]) const;
709 using WriterAtom<A>::fWriter;
710 typedef typename A::P P;
713 template <typename A>
714 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
717 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
718 virtual const char* getDisplayName() const { return "symbol table"; }
719 virtual uint64_t getSize() const;
720 virtual uint8_t getAlignment() const { return 2; }
721 virtual const char* getSectionName() const { return "._symbol_table"; }
722 virtual void copyRawContent(uint8_t buffer[]) const;
724 using WriterAtom<A>::fWriter;
725 typedef typename A::P P;
728 template <typename A>
729 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
732 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
733 virtual const char* getDisplayName() const { return "external relocations"; }
734 virtual uint64_t getSize() const;
735 virtual uint8_t getAlignment() const { return 3; }
736 virtual const char* getSectionName() const { return "._extern_relocs"; }
737 virtual void copyRawContent(uint8_t buffer[]) const;
739 using WriterAtom<A>::fWriter;
740 typedef typename A::P P;
743 struct IndirectEntry {
744 uint32_t indirectIndex;
745 uint32_t symbolIndex;
748 template <typename A>
749 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
752 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
753 virtual const char* getDisplayName() const { return "indirect symbol table"; }
754 virtual uint64_t getSize() const;
755 virtual uint8_t getAlignment() const { return 2; }
756 virtual const char* getSectionName() const { return "._indirect_syms"; }
757 virtual void copyRawContent(uint8_t buffer[]) const;
759 std::vector<IndirectEntry> fTable;
762 using WriterAtom<A>::fWriter;
763 typedef typename A::P P;
769 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
772 template <typename A>
773 class StringsLinkEditAtom : public LinkEditAtom<A>
776 StringsLinkEditAtom(Writer<A>& writer);
777 virtual const char* getDisplayName() const { return "string pool"; }
778 virtual uint64_t getSize() const;
779 virtual uint8_t getAlignment() const { return 2; }
780 virtual const char* getSectionName() const { return "._string_pool"; }
781 virtual void copyRawContent(uint8_t buffer[]) const;
783 int32_t add(const char* name);
784 int32_t addUnique(const char* name);
785 int32_t emptyString() { return 1; }
788 using WriterAtom<A>::fWriter;
789 typedef typename A::P P;
790 enum { kBufferSize = 0x01000000 };
791 class CStringComparor {
793 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
795 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
797 std::vector<char*> fFullBuffers;
798 char* fCurrentBuffer;
799 uint32_t fCurrentBufferUsed;
800 StringToOffset fUniqueStrings;
805 template <typename A>
806 class UndefinedSymbolProxyAtom : public WriterAtom<A>
809 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
810 virtual const char* getName() const { return fName; }
811 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
812 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
813 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
814 virtual uint64_t getSize() const { return 0; }
815 virtual const char* getSectionName() const { return "._imports"; }
817 using WriterAtom<A>::fWriter;
818 typedef typename A::P P;
822 template <typename A>
823 class BranchIslandAtom : public WriterAtom<A>
826 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
827 virtual const char* getName() const { return fName; }
828 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
829 virtual uint64_t getSize() const;
830 virtual const char* getSectionName() const { return "__text"; }
831 virtual void copyRawContent(uint8_t buffer[]) const;
833 using WriterAtom<A>::fWriter;
835 ObjectFile::Atom& fTarget;
836 uint32_t fTargetOffset;
839 template <typename A>
840 class StubAtom : public WriterAtom<A>
843 StubAtom(Writer<A>& writer, ObjectFile::Atom& target);
844 virtual const char* getName() const { return fName; }
845 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
846 virtual uint8_t getAlignment() const { return 2; }
847 virtual uint64_t getSize() const;
848 virtual const char* getSectionName() const { return "__symbol_stub1"; }
849 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
850 virtual void copyRawContent(uint8_t buffer[]) const;
851 ObjectFile::Atom* getTarget() { return &fTarget; }
853 static const char* stubName(const char* importName);
855 using WriterAtom<A>::fWriter;
857 ObjectFile::Atom& fTarget;
858 std::vector<ObjectFile::Reference*> fReferences;
862 template <typename A>
863 class LazyPointerAtom : public WriterAtom<A>
866 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
867 virtual const char* getName() const { return fName; }
868 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
869 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
870 virtual const char* getSectionName() const { return "__la_symbol_ptr"; }
871 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
872 virtual void copyRawContent(uint8_t buffer[]) const;
873 ObjectFile::Atom* getTarget() { return &fTarget; }
875 using WriterAtom<A>::fWriter;
876 static const char* lazyPointerName(const char* importName);
878 ObjectFile::Atom& fTarget;
879 std::vector<ObjectFile::Reference*> fReferences;
883 template <typename A>
884 class NonLazyPointerAtom : public WriterAtom<A>
887 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
888 virtual const char* getName() const { return fName; }
889 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
890 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
891 virtual const char* getSectionName() const { return "__nl_symbol_ptr"; }
892 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
893 virtual void copyRawContent(uint8_t buffer[]) const;
894 ObjectFile::Atom* getTarget() { return &fTarget; }
896 using WriterAtom<A>::fWriter;
897 static const char* nonlazyPointerName(const char* importName);
899 ObjectFile::Atom& fTarget;
900 std::vector<ObjectFile::Reference*> fReferences;
904 template <typename A>
905 class WriterReference : public ObjectFile::Reference
908 typedef typename A::ReferenceKinds Kinds;
910 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
911 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
912 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target),
913 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
915 virtual ~WriterReference() {}
917 virtual bool isTargetUnbound() const { return false; }
918 virtual bool isFromTargetUnbound() const { return false; }
919 virtual uint8_t getKind() const { return (uint8_t)fKind; }
920 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
921 virtual const char* getTargetName() const { return fTarget->getName(); }
922 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
923 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
924 virtual bool hasFromTarget() const { return (fFromTarget != NULL); }
925 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
926 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
927 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = ⌖ fTargetOffset = offset; }
928 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ }
929 virtual void setFromTargetName(const char* name) { }
930 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
931 virtual const char* getDescription() const { return "writer refrence"; }
932 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
936 uint32_t fFixUpOffsetInSrc;
937 ObjectFile::Atom* fTarget;
938 uint32_t fTargetOffset;
939 ObjectFile::Atom* fFromTarget;
940 uint32_t fFromTargetOffset;
947 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
949 return (strcmp(left->getName(), right->getName()) < 0);
956 template <typename A>
957 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
958 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
959 fLoadCommandsSegment(NULL), fLargestAtomSize(1),
960 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
961 fSeenFollowOnReferences(false)
963 int permissions = 0777;
964 if ( fOptions.outputKind() == Options::kObjectFile )
966 // Calling unlink first assures the file is gone so that open creates it with correct permissions
967 // It also handles the case where fFilePath file is not writeable but its directory is
968 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
969 (void)unlink(fFilePath);
970 fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
971 if ( fFileDescriptor == -1 ) {
972 throw "can't open file for writing";
975 switch ( fOptions.outputKind() ) {
976 case Options::kDynamicExecutable:
977 case Options::kStaticExecutable:
978 fWriterSynthesizedAtoms.push_back(new PageZeroAtom<A>(*this));
979 if ( fOptions.outputKind() == Options::kDynamicExecutable )
980 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
981 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
982 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
983 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
984 if ( fOptions.outputKind() == Options::kDynamicExecutable )
985 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
986 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
987 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
988 if ( fOptions.hasCustomStack() )
989 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
990 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
991 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
992 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
993 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
994 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
995 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
996 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
998 case Options::kDynamicLibrary:
999 case Options::kDynamicBundle:
1000 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1002 case Options::kObjectFile:
1003 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1004 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1005 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
1006 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
1007 if ( fOptions.initFunctionName() != NULL )
1008 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
1010 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1011 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1012 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1013 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1014 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1015 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1016 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1017 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1018 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1020 case Options::kDyld:
1021 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1022 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1023 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1024 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1025 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1026 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1027 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1028 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1029 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1030 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1031 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1032 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1033 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1037 // add extra commmands
1038 uint8_t ordinal = 1;
1039 switch ( fOptions.outputKind() ) {
1040 case Options::kDynamicExecutable:
1041 case Options::kDynamicLibrary:
1042 case Options::kDynamicBundle:
1044 // add dylib load command atoms for all dynamic libraries
1045 const unsigned int libCount = dynamicLibraries.size();
1046 for (unsigned int i=0; i < libCount; ++i) {
1047 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
1048 if ( dylibInfo.indirect ) {
1049 // find ordinal of direct reader
1050 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
1052 for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1053 if ( it->first == dylibInfo.directReader ) {
1054 //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
1055 fLibraryToOrdinal[dylibInfo.reader] = it->second;
1061 fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
1065 // see if a DylibLoadCommandsAtom has already been created for this install path
1066 bool newDylib = true;
1067 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
1068 if ( dylibInfo.options.fInstallPathOverride != NULL )
1069 dylibInstallPath = dylibInfo.options.fInstallPathOverride;
1070 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
1071 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
1072 if ( !seenDylibInfo.indirect ) {
1073 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
1074 if ( seenDylibInfo.options.fInstallPathOverride != NULL )
1075 seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
1076 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
1077 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
1085 // assign new ordinal and check for other paired load commands
1086 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
1087 fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom<A>(*this, dylibInfo));
1088 if ( dylibInfo.options.fReExport ) {
1089 // this dylib also needs a sub_x load command
1090 bool isFrameworkReExport = false;
1091 const char* lastSlash = strrchr(dylibInstallPath, '/');
1092 if ( lastSlash != NULL ) {
1093 char frameworkName[strlen(lastSlash)+20];
1094 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
1095 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
1097 if ( isFrameworkReExport ) {
1098 // needs a LC_SUB_UMBRELLA command
1099 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
1102 // needs a LC_SUB_LIBRARY command
1103 const char* nameStart = &lastSlash[1];
1104 if ( lastSlash == NULL )
1105 nameStart = dylibInstallPath;
1106 int len = strlen(nameStart);
1107 const char* dot = strchr(nameStart, '.');
1109 len = dot - nameStart;
1110 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
1116 // add umbrella command if needed
1117 if ( fOptions.umbrellaName() != NULL ) {
1118 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
1120 std::vector<const char*>& allowableClients = fOptions.allowableClients();
1121 if ( allowableClients.size() != 0 ) {
1122 for (std::vector<const char*>::iterator it=allowableClients.begin();
1123 it != allowableClients.end();
1125 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
1129 case Options::kStaticExecutable:
1130 case Options::kObjectFile:
1131 case Options::kDyld:
1135 //fprintf(stderr, "ordinals table:\n");
1136 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1137 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
1141 template <typename A>
1142 Writer<A>::~Writer()
1144 if ( fFilePath != NULL )
1145 free((void*)fFilePath);
1146 if ( fSymbolTable != NULL )
1147 delete [] fSymbolTable;
1151 template <typename A>
1152 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
1154 if ( (fOptions.outputKind() == Options::kObjectFile)
1155 || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
1156 return new UndefinedSymbolProxyAtom<A>(*this, name);
1161 template <typename A>
1162 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
1164 // flat namespace images use zero for all ordinals
1165 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
1168 // is an UndefinedSymbolProxyAtom
1170 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
1171 return DYNAMIC_LOOKUP_ORDINAL;
1173 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
1174 if ( pos != fLibraryToOrdinal.end() )
1177 throw "can't find ordinal for imported symbol";
1181 template <typename A>
1182 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
1183 std::vector<class ObjectFile::Reader::Stab>& stabs,
1184 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
1189 fEntryPoint = entryPointAtom;
1190 fDyldHelper = dyldHelperAtom;
1192 // Set for create UUID
1196 // create inter-library stubs
1199 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
1200 partitionIntoSections();
1202 // segment load command can now be sized and padding can be set
1203 adjustLoadCommandsAndPadding();
1205 // assign each section a file offset
1206 assignFileOffsets();
1208 // if need to add branch islands, reassign file offsets
1209 if ( addBranchIslands() )
1210 assignFileOffsets();
1212 // build symbol table and relocations
1216 return writeAtoms();
1219 template <typename A>
1220 void Writer<A>::buildLinkEdit()
1222 this->collectExportedAndImportedAndLocalAtoms();
1223 this->buildSymbolTable();
1224 this->buildFixups();
1225 this->adjustLinkEditSections();
1230 template <typename A>
1231 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
1233 return atom->getAddress();
1234 // SectionInfo* info = (SectionInfo*)atom->getSection();
1235 // return info->getBaseAddress() + atom->getSectionOffset();
1238 template <typename A>
1239 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1242 entry->set_n_type(N_EXT | N_SECT);
1243 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
1244 if ( fOptions.keepPrivateExterns() )
1245 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
1248 // set n_sect (section number of implementation )
1249 uint8_t sectionIndex = atom->getSection()->getIndex();
1250 entry->set_n_sect(sectionIndex);
1252 // the __mh_execute_header is magic and must be an absolute symbol
1253 if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0)
1254 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
1255 entry->set_n_type(N_EXT | N_ABS);
1259 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1260 desc |= REFERENCED_DYNAMICALLY;
1261 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
1263 fHasWeakExports = true;
1265 entry->set_n_desc(desc);
1267 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1268 entry->set_n_value(this->getAtomLoadAddress(atom));
1271 template <typename A>
1272 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1275 entry->set_n_type(N_UNDF | N_EXT);
1276 if ( fOptions.keepPrivateExterns()
1277 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
1278 && (fOptions.outputKind() == Options::kObjectFile) )
1279 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
1282 entry->set_n_sect(0);
1285 if ( fOptions.outputKind() != Options::kObjectFile ) {
1286 // set n_desc ( high byte is library ordinal, low byte is reference type )
1287 desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
1289 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
1290 SET_LIBRARY_ORDINAL(desc, ordinal);
1292 catch (const char* msg) {
1293 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
1296 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1297 desc |= REFERENCED_DYNAMICALLY;
1298 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1299 desc |= N_REF_TO_WEAK;
1300 fReferencesWeakImports = true;
1302 // set weak_import attribute
1303 if ( fWeakImportMap[atom] )
1305 entry->set_n_desc(desc);
1307 // set n_value, zero for import proxy and size for tentative definition
1308 entry->set_n_value(atom->getSize());
1311 template <typename A>
1312 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1315 uint8_t type = N_SECT;
1316 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
1318 entry->set_n_type(type);
1320 // set n_sect (section number of implementation )
1321 uint8_t sectIndex = atom->getSection()->getIndex();
1322 if ( sectIndex == 0 ) {
1323 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
1324 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
1327 entry->set_n_sect(sectIndex);
1331 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
1333 entry->set_n_desc(desc);
1335 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1336 entry->set_n_value(this->getAtomLoadAddress(atom));
1340 template <typename A>
1341 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
1343 macho_nlist<P>* entry = &fSymbolTable[startIndex];
1344 for (uint32_t i=0; i < count; ++i, ++entry) {
1345 ObjectFile::Atom* atom = atoms[i];
1346 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
1347 if ( &atoms == &fExportedAtoms ) {
1348 this->setExportNlist(atom, entry);
1350 else if ( &atoms == &fImportedAtoms ) {
1351 this->setImportNlist(atom, entry);
1354 this->setLocalNlist(atom, entry);
1359 template <typename A>
1360 void Writer<A>::buildSymbolTable()
1362 fSymbolTableStabsStartIndex = 0;
1363 fSymbolTableStabsCount = fStabs->size();
1364 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
1365 fSymbolTableLocalCount = fLocalSymbolAtoms.size();
1366 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
1367 fSymbolTableExportCount = fExportedAtoms.size();
1368 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
1369 fSymbolTableImportCount = fImportedAtoms.size();
1371 // allocate symbol table
1372 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
1373 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
1375 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
1376 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount);
1377 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
1378 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
1379 addStabs(fSymbolTableStabsStartIndex);
1384 template <typename A>
1385 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
1387 if ( atom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
1389 switch ( atom.getScope() ) {
1390 case ObjectFile::Atom::scopeGlobal:
1392 case ObjectFile::Atom::scopeLinkageUnit:
1393 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
1399 template <typename A>
1400 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
1402 const int atomCount = fAllAtoms->size();
1403 // guess at sizes of each bucket to minimize re-allocations
1404 fImportedAtoms.reserve(100);
1405 fExportedAtoms.reserve(atomCount/2);
1406 fLocalSymbolAtoms.reserve(atomCount);
1407 for (int i=0; i < atomCount; ++i) {
1408 ObjectFile::Atom* atom = (*fAllAtoms)[i];
1409 // only named atoms go in symbol table
1410 if ( atom->getName() != NULL ) {
1411 // put atom into correct bucket: imports, exports, locals
1412 //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
1413 switch ( atom->getDefinitionKind() ) {
1414 case ObjectFile::Atom::kExternalDefinition:
1415 case ObjectFile::Atom::kExternalWeakDefinition:
1416 fImportedAtoms.push_back(atom);
1418 case ObjectFile::Atom::kTentativeDefinition:
1419 if ( fOptions.outputKind() == Options::kObjectFile ) {
1420 fImportedAtoms.push_back(atom);
1424 case ObjectFile::Atom::kRegularDefinition:
1425 case ObjectFile::Atom::kWeakDefinition:
1426 if ( this->shouldExport(*atom) )
1427 fExportedAtoms.push_back(atom);
1428 else if ( !fOptions.stripLocalSymbols()
1429 && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) )
1430 fLocalSymbolAtoms.push_back(atom);
1436 // sort exported atoms by name
1437 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
1438 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
1439 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), ExportSorter());
1443 template <typename A>
1444 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
1446 switch ( stab.type ) {
1448 if ( stab.other == 0 ) {
1449 // end of function N_FUN has size
1450 return stab.atom->getSize();
1453 // start of function N_FUN has address
1454 return getAtomLoadAddress(stab.atom);
1459 if ( stab.atom == NULL )
1460 // some weird assembly files have slines not associated with a function
1463 // all these stab types need their value changed from an offset in the atom to an address
1464 return getAtomLoadAddress(stab.atom) + stab.value;
1468 // all these need address of atom
1469 return getAtomLoadAddress(stab.atom);;
1471 return stab.atom->getSize();
1479 template <typename A>
1480 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
1482 switch (stab.type) {
1484 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
1485 return this->fStringsAtom->emptyString();
1488 // fall into uniquing case
1492 return this->fStringsAtom->addUnique(stab.string);
1495 if ( stab.string == NULL )
1497 else if ( stab.string[0] == '\0' )
1498 return this->fStringsAtom->emptyString();
1500 return this->fStringsAtom->add(stab.string);
1505 template <typename A>
1506 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
1508 if ( stab.atom != NULL )
1509 return stab.atom->getSection()->getIndex();
1514 template <typename A>
1515 void Writer<A>::addStabs(uint32_t startIndex)
1517 macho_nlist<P>* entry = &fSymbolTable[startIndex];
1518 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
1519 const ObjectFile::Reader::Stab& stab = *it;
1520 entry->set_n_type(stab.type);
1521 entry->set_n_sect(sectionIndexForStab(stab));
1522 entry->set_n_desc(stab.desc);
1523 entry->set_n_value(valueForStab(stab));
1524 entry->set_n_strx(stringOffsetForStab(stab));
1530 template <typename A>
1531 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
1535 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
1537 return i + fSymbolTableImportStartIndex;
1543 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
1545 return i + fSymbolTableLocalStartIndex;
1551 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
1553 return i + fSymbolTableExportStartIndex;
1557 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
1561 template <typename A>
1562 void Writer<A>::buildFixups()
1564 if ( fOptions.outputKind() == Options::kObjectFile ) {
1565 this->buildObjectFileFixups();
1568 if ( fOptions.keepRelocations() )
1569 this->buildObjectFileFixups();
1570 this->buildExecutableFixups();
1576 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1578 ObjectFile::Atom& target = ref->getTarget();
1579 bool isExtern = false;
1580 switch ( target.getDefinitionKind() ) {
1581 case ObjectFile::Atom::kRegularDefinition:
1584 case ObjectFile::Atom::kWeakDefinition:
1585 case ObjectFile::Atom::kTentativeDefinition:
1586 case ObjectFile::Atom::kExternalDefinition:
1587 case ObjectFile::Atom::kExternalWeakDefinition:
1588 isExtern = shouldExport(target);
1591 uint32_t symbolIndex = 0;
1593 symbolIndex = this->symbolIndex(target);
1594 uint32_t sectionNum = target.getSection()->getIndex();
1595 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1596 macho_relocation_info<P> reloc1;
1597 macho_relocation_info<P> reloc2;
1598 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1599 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1600 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
1604 case x86::kFollowOn:
1608 case x86::kPointerWeakImport:
1609 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1610 // use scattered reloc is target offset is non-zero
1611 sreloc1->set_r_scattered(true);
1612 sreloc1->set_r_pcrel(false);
1613 sreloc1->set_r_length(2);
1614 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1615 sreloc1->set_r_address(address);
1616 sreloc1->set_r_value(target.getAddress());
1619 reloc1.set_r_address(address);
1620 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1621 reloc1.set_r_pcrel(false);
1622 reloc1.set_r_length(2);
1623 reloc1.set_r_extern(isExtern);
1624 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1626 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1629 case x86::kPointerDiff:
1631 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1632 sreloc1->set_r_scattered(true);
1633 sreloc1->set_r_pcrel(false);
1634 sreloc1->set_r_length(2);
1635 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
1636 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
1638 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
1639 sreloc1->set_r_address(address);
1640 sreloc1->set_r_value(target.getAddress());
1641 sreloc2->set_r_scattered(true);
1642 sreloc2->set_r_pcrel(false);
1643 sreloc2->set_r_length(2);
1644 sreloc2->set_r_type(PPC_RELOC_PAIR);
1645 sreloc2->set_r_address(0);
1646 sreloc2->set_r_value(fromAddr);
1647 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1648 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1652 case x86::kPCRel32WeakImport:
1654 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1655 // use scattered reloc is target offset is non-zero
1656 sreloc1->set_r_scattered(true);
1657 sreloc1->set_r_pcrel(true);
1658 sreloc1->set_r_length(2);
1659 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1660 sreloc1->set_r_address(address);
1661 sreloc1->set_r_value(target.getAddress());
1664 reloc1.set_r_address(address);
1665 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1666 reloc1.set_r_pcrel(true);
1667 reloc1.set_r_length(2);
1668 reloc1.set_r_extern(isExtern);
1669 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1671 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1681 uint8_t Writer<ppc>::getRelocPointerSize()
1687 uint8_t Writer<ppc64>::getRelocPointerSize()
1693 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1695 return addObjectRelocs_powerpc(atom, ref);
1699 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1701 return addObjectRelocs_powerpc(atom, ref);
1705 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
1706 // they use a common addObjectRelocs_powerpc() method.
1708 template <typename A>
1709 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1711 ObjectFile::Atom& target = ref->getTarget();
1712 bool isExtern = false;
1713 switch ( target.getDefinitionKind() ) {
1714 case ObjectFile::Atom::kRegularDefinition:
1717 case ObjectFile::Atom::kWeakDefinition:
1718 case ObjectFile::Atom::kTentativeDefinition:
1719 case ObjectFile::Atom::kExternalDefinition:
1720 case ObjectFile::Atom::kExternalWeakDefinition:
1721 isExtern = shouldExport(target);
1725 uint32_t symbolIndex = 0;
1727 symbolIndex = this->symbolIndex(target);
1728 uint32_t sectionNum = target.getSection()->getIndex();
1729 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1730 macho_relocation_info<P> reloc1;
1731 macho_relocation_info<P> reloc2;
1732 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1733 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1734 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
1742 case A::kPointerWeakImport:
1743 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
1744 // use scattered reloc is target offset is outside target
1745 sreloc1->set_r_scattered(true);
1746 sreloc1->set_r_pcrel(false);
1747 sreloc1->set_r_length(getRelocPointerSize());
1748 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1749 sreloc1->set_r_address(address);
1750 sreloc1->set_r_value(target.getAddress());
1753 reloc1.set_r_address(address);
1755 reloc1.set_r_symbolnum(symbolIndex);
1757 reloc1.set_r_symbolnum(sectionNum);
1758 reloc1.set_r_pcrel(false);
1759 reloc1.set_r_length(getRelocPointerSize());
1760 reloc1.set_r_extern(isExtern);
1761 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1763 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1766 case A::kPointerDiff32:
1767 case A::kPointerDiff64:
1769 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1770 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1771 sreloc1->set_r_scattered(true);
1772 sreloc1->set_r_pcrel(false);
1773 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1774 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
1775 sreloc1->set_r_address(address);
1776 sreloc1->set_r_value(toAddr);
1777 sreloc2->set_r_scattered(true);
1778 sreloc2->set_r_pcrel(false);
1779 sreloc2->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1780 sreloc2->set_r_type(PPC_RELOC_PAIR);
1781 sreloc2->set_r_address(0);
1782 sreloc2->set_r_value(fromAddr);
1783 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1784 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1788 case A::kBranch24WeakImport:
1790 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1791 reloc1.set_r_address(address);
1793 reloc1.set_r_symbolnum(symbolIndex);
1795 reloc1.set_r_symbolnum(sectionNum);
1796 reloc1.set_r_pcrel(true);
1797 reloc1.set_r_length(2);
1798 reloc1.set_r_type(PPC_RELOC_BR24);
1799 reloc1.set_r_extern(isExtern);
1802 sreloc1->set_r_scattered(true);
1803 sreloc1->set_r_pcrel(true);
1804 sreloc1->set_r_length(2);
1805 sreloc1->set_r_type(PPC_RELOC_BR24);
1806 sreloc1->set_r_address(address);
1807 sreloc1->set_r_value(target.getAddress());
1809 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1813 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1814 reloc1.set_r_address(address);
1816 reloc1.set_r_symbolnum(symbolIndex);
1818 reloc1.set_r_symbolnum(sectionNum);
1819 reloc1.set_r_pcrel(true);
1820 reloc1.set_r_length(2);
1821 reloc1.set_r_type(PPC_RELOC_BR14);
1822 reloc1.set_r_extern(isExtern);
1825 sreloc1->set_r_scattered(true);
1826 sreloc1->set_r_pcrel(true);
1827 sreloc1->set_r_length(2);
1828 sreloc1->set_r_type(PPC_RELOC_BR14);
1829 sreloc1->set_r_address(address);
1830 sreloc1->set_r_value(target.getAddress());
1832 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1835 case A::kPICBaseLow16:
1836 case A::kPICBaseLow14:
1838 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
1839 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1840 sreloc1->set_r_scattered(true);
1841 sreloc1->set_r_pcrel(false);
1842 sreloc1->set_r_length(2);
1843 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
1844 sreloc1->set_r_address(address);
1845 sreloc1->set_r_value(target.getAddress());
1846 sreloc2->set_r_scattered(true);
1847 sreloc2->set_r_pcrel(false);
1848 sreloc2->set_r_length(2);
1849 sreloc2->set_r_type(PPC_RELOC_PAIR);
1850 sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
1851 sreloc2->set_r_value(fromAddr);
1852 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1853 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1857 case A::kPICBaseHigh16:
1859 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
1860 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1861 sreloc1->set_r_scattered(true);
1862 sreloc1->set_r_pcrel(false);
1863 sreloc1->set_r_length(2);
1864 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
1865 sreloc1->set_r_address(address);
1866 sreloc1->set_r_value(target.getAddress());
1867 sreloc2->set_r_scattered(true);
1868 sreloc2->set_r_pcrel(false);
1869 sreloc2->set_r_length(2);
1870 sreloc2->set_r_type(PPC_RELOC_PAIR);
1871 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
1872 sreloc2->set_r_value(fromAddr);
1873 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1874 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1881 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1882 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1883 reloc1.set_r_address(address);
1885 reloc1.set_r_symbolnum(symbolIndex);
1887 reloc1.set_r_symbolnum(sectionNum);
1888 reloc1.set_r_pcrel(false);
1889 reloc1.set_r_length(2);
1890 reloc1.set_r_extern(isExtern);
1891 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
1894 sreloc1->set_r_scattered(true);
1895 sreloc1->set_r_pcrel(false);
1896 sreloc1->set_r_length(2);
1897 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
1898 sreloc1->set_r_address(address);
1899 sreloc1->set_r_value(target.getAddress());
1902 reloc2.set_r_address(ref->getTargetOffset() >> 16);
1904 reloc2.set_r_address(toAddr >> 16);
1905 reloc2.set_r_symbolnum(0);
1906 reloc2.set_r_pcrel(false);
1907 reloc2.set_r_length(2);
1908 reloc2.set_r_extern(false);
1909 reloc2.set_r_type(PPC_RELOC_PAIR);
1910 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1911 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1917 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1918 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1919 reloc1.set_r_address(address);
1921 reloc1.set_r_symbolnum(symbolIndex);
1923 reloc1.set_r_symbolnum(sectionNum);
1924 reloc1.set_r_pcrel(false);
1925 reloc1.set_r_length(2);
1926 reloc1.set_r_extern(isExtern);
1927 reloc1.set_r_type(PPC_RELOC_HI16);
1930 sreloc1->set_r_scattered(true);
1931 sreloc1->set_r_pcrel(false);
1932 sreloc1->set_r_length(2);
1933 sreloc1->set_r_type(PPC_RELOC_HI16);
1934 sreloc1->set_r_address(address);
1935 sreloc1->set_r_value(target.getAddress());
1938 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
1940 reloc2.set_r_address(toAddr & 0xFFFF);
1941 reloc2.set_r_symbolnum(0);
1942 reloc2.set_r_pcrel(false);
1943 reloc2.set_r_length(2);
1944 reloc2.set_r_extern(false);
1945 reloc2.set_r_type(PPC_RELOC_PAIR);
1946 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1947 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1951 case A::kAbsHigh16AddLow:
1953 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1954 uint32_t overflow = 0;
1955 if ( (toAddr & 0x00008000) != 0 )
1957 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1958 reloc1.set_r_address(address);
1960 reloc1.set_r_symbolnum(symbolIndex);
1962 reloc1.set_r_symbolnum(sectionNum);
1963 reloc1.set_r_pcrel(false);
1964 reloc1.set_r_length(2);
1965 reloc1.set_r_extern(isExtern);
1966 reloc1.set_r_type(PPC_RELOC_HA16);
1969 sreloc1->set_r_scattered(true);
1970 sreloc1->set_r_pcrel(false);
1971 sreloc1->set_r_length(2);
1972 sreloc1->set_r_type(PPC_RELOC_HA16);
1973 sreloc1->set_r_address(address);
1974 sreloc1->set_r_value(target.getAddress());
1977 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
1979 reloc2.set_r_address(toAddr & 0xFFFF);
1980 reloc2.set_r_symbolnum(0);
1981 reloc2.set_r_pcrel(false);
1982 reloc2.set_r_length(2);
1983 reloc2.set_r_extern(false);
1984 reloc2.set_r_type(PPC_RELOC_PAIR);
1985 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1986 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1995 template <typename A>
1996 void Writer<A>::buildObjectFileFixups()
1998 uint32_t relocIndex = 0;
1999 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2000 const int segCount = segmentInfos.size();
2001 for(int i=0; i < segCount; ++i) {
2002 SegmentInfo* curSegment = segmentInfos[i];
2003 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2004 const int sectionCount = sectionInfos.size();
2005 for(int j=0; j < sectionCount; ++j) {
2006 SectionInfo* curSection = sectionInfos[j];
2007 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
2008 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2009 if ( ! curSection->fAllZeroFill ) {
2010 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
2011 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2012 curSection->fRelocOffset = relocIndex;
2013 const int atomCount = sectionAtoms.size();
2014 for (int k=0; k < atomCount; ++k) {
2015 ObjectFile::Atom* atom = sectionAtoms[k];
2016 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
2017 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2018 const int refCount = refs.size();
2019 for (int l=0; l < refCount; ++l) {
2020 ObjectFile::Reference* ref = refs[l];
2021 if ( ref->getKind() == A::kFollowOn )
2022 fSeenFollowOnReferences = true;
2023 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
2024 uint32_t offsetInSection = atom->getSectionOffset();
2025 uint32_t indexInSection = offsetInSection / atom->getSize();
2026 uint32_t undefinedSymbolIndex;
2027 if ( curSection->fAllStubs ) {
2028 ObjectFile::Atom& stubTarget =ref->getTarget();
2029 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
2030 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
2031 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
2034 if ( curSection->fAllNonLazyPointers
2035 && (ref->getTarget().getScope() == ObjectFile::Atom::scopeLinkageUnit)
2036 && !fOptions.keepPrivateExterns() )
2037 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2039 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
2041 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2042 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2043 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
2044 fIndirectTableAtom->fTable.push_back(entry);
2045 if ( curSection->fAllLazyPointers ) {
2046 ObjectFile::Atom& target = ref->getTarget();
2047 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2048 if ( &fromTarget == NULL ) {
2049 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
2052 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
2053 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
2054 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
2055 macho_relocation_info<P> reloc1;
2056 reloc1.set_r_address(atom->getSectionOffset());
2057 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
2058 reloc1.set_r_pcrel(false);
2059 reloc1.set_r_length();
2060 reloc1.set_r_extern(isExtern);
2061 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2062 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2066 else if ( curSection->fAllStubs ) {
2067 relocIndex += this->addObjectRelocs(atom, ref);
2071 relocIndex += this->addObjectRelocs(atom, ref);
2075 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
2080 // now reverse reloc entries
2081 for(int i=0; i < segCount; ++i) {
2082 SegmentInfo* curSegment = segmentInfos[i];
2083 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2084 const int sectionCount = sectionInfos.size();
2085 for(int j=0; j < sectionCount; ++j) {
2086 SectionInfo* curSection = sectionInfos[j];
2087 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
2094 bool Writer<ppc>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
2097 case ppc::kAbsLow16:
2098 case ppc::kAbsLow14:
2099 case ppc::kAbsHigh16:
2100 case ppc::kAbsHigh16AddLow:
2109 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
2112 case ppc::kAbsLow16:
2113 case ppc::kAbsLow14:
2114 case ppc::kAbsHigh16:
2115 case ppc::kAbsHigh16AddLow:
2123 bool Writer<x86>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
2130 template <typename A>
2131 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
2133 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2135 switch ( target.getDefinitionKind() ) {
2136 case ObjectFile::Atom::kTentativeDefinition:
2137 case ObjectFile::Atom::kRegularDefinition:
2138 // for flat-namespace or interposable two-level-namespace
2139 // all references to exported symbols get indirected
2140 if ( this->shouldExport(target) &&
2141 ((fOptions.nameSpace() == Options::kFlatNameSpace)
2142 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
2143 || fOptions.interposable()) )
2144 return kRelocExternal;
2145 else if ( slideable )
2146 return kRelocInternal;
2149 case ObjectFile::Atom::kWeakDefinition:
2150 // all calls to global weak definitions get indirected
2151 if ( this->shouldExport(target) )
2152 return kRelocExternal;
2153 else if ( slideable )
2154 return kRelocInternal;
2157 case ObjectFile::Atom::kExternalDefinition:
2158 case ObjectFile::Atom::kExternalWeakDefinition:
2159 return kRelocExternal;
2164 template <typename A>
2165 void Writer<A>::buildExecutableFixups()
2167 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2168 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
2169 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2170 const int segCount = segmentInfos.size();
2171 for(int i=0; i < segCount; ++i) {
2172 SegmentInfo* curSegment = segmentInfos[i];
2173 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2174 const int sectionCount = sectionInfos.size();
2175 for(int j=0; j < sectionCount; ++j) {
2176 SectionInfo* curSection = sectionInfos[j];
2177 //fprintf(stderr, "starting section %p\n", curSection->fSectionName);
2178 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2179 if ( ! curSection->fAllZeroFill ) {
2180 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
2181 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2182 const int atomCount = sectionAtoms.size();
2183 for (int k=0; k < atomCount; ++k) {
2184 ObjectFile::Atom* atom = sectionAtoms[k];
2185 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2186 const int refCount = refs.size();
2187 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
2188 for (int l=0; l < refCount; ++l) {
2189 ObjectFile::Reference* ref = refs[l];
2190 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
2191 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
2192 if ( atom->getSize() != sizeof(pint_t) ) {
2193 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
2195 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
2196 if ( curSection->fAllLazyPointers ) {
2197 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
2199 uint32_t offsetInSection = atom->getSectionOffset();
2200 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
2201 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2202 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
2203 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
2204 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2205 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2206 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
2207 fIndirectTableAtom->fTable.push_back(entry);
2208 if ( slideable && curSection->fAllLazyPointers ) {
2209 // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
2210 macho_relocation_info<P> pblaReloc;
2211 uint32_t sectionNum = 1;
2212 if ( fDyldHelper != NULL )
2213 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
2214 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
2215 pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
2216 pblaReloc.set_r_symbolnum(sectionNum);
2217 pblaReloc.set_r_pcrel(false);
2218 pblaReloc.set_r_length();
2219 pblaReloc.set_r_extern(false);
2220 pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
2221 fInternalRelocs.push_back(pblaReloc);
2224 else if ( ref->getKind() == A::kPointer ) {
2225 if ( slideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
2226 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
2228 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
2232 case kRelocInternal:
2234 macho_relocation_info<P> internalReloc;
2235 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
2236 uint32_t sectionNum = sectInfo->getIndex();
2237 // special case _mh_dylib_header and friends which are not in any real section
2238 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
2240 internalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
2241 internalReloc.set_r_symbolnum(sectionNum);
2242 internalReloc.set_r_pcrel(false);
2243 internalReloc.set_r_length();
2244 internalReloc.set_r_extern(false);
2245 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2246 fInternalRelocs.push_back(internalReloc);
2249 case kRelocExternal:
2251 macho_relocation_info<P> externalReloc;
2252 externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
2253 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
2254 externalReloc.set_r_pcrel(false);
2255 externalReloc.set_r_length();
2256 externalReloc.set_r_extern(true);
2257 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2258 fExternalRelocs.push_back(externalReloc);
2263 else if ( this->illegalRelocInFinalLinkedImage(ref->getKind(), slideable) ) {
2264 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
2267 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
2268 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
2269 uint32_t undefinedSymbolIndex = this->symbolIndex(*stubTarget);
2270 uint32_t offsetInSection = atom->getSectionOffset();
2271 uint32_t indexInSection = offsetInSection / atom->getSize();
2272 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2273 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2274 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
2275 fIndirectTableAtom->fTable.push_back(entry);
2285 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
2288 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2289 for (uint32_t p=from; p < to; p += 4)
2290 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2294 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
2297 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2298 for (uint32_t p=from; p < to; p += 4)
2299 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2303 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
2305 uint8_t x86Nop = 0x90;
2306 for (uint32_t p=from; p < to; ++p)
2307 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
2311 template <typename A>
2312 uint64_t Writer<A>::writeAtoms()
2315 uint8_t* buffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
2316 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2317 const int segCount = segmentInfos.size();
2318 for(int i=0; i < segCount; ++i) {
2319 SegmentInfo* curSegment = segmentInfos[i];
2320 bool isTextSeg = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
2321 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2322 const int sectionCount = sectionInfos.size();
2323 for(int j=0; j < sectionCount; ++j) {
2324 SectionInfo* curSection = sectionInfos[j];
2325 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2326 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
2327 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
2328 if ( ! curSection->fAllZeroFill ) {
2329 const int atomCount = sectionAtoms.size();
2330 end = curSection->fFileOffset;
2331 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
2332 for (int k=0; k < atomCount; ++k) {
2333 ObjectFile::Atom* atom = sectionAtoms[k];
2334 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
2335 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) ) {
2336 uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
2337 if ( offset != end ) {
2339 // fill gaps with no-ops
2340 writeNoOps(end, offset);
2344 if ( (offset-end) == 4 ) {
2346 ::pwrite(fFileDescriptor, &zero, 4, end);
2349 uint8_t zero = 0x00;
2350 for (uint32_t p=end; p < offset; ++p)
2351 ::pwrite(fFileDescriptor, &zero, 1, p);
2355 uint64_t atomSize = atom->getSize();
2356 if ( atomSize > fLargestAtomSize ) {
2357 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
2358 atom->getDisplayName(), atomSize, fLargestAtomSize);
2360 end = offset+atomSize;
2362 atom->copyRawContent(buffer);
2363 // apply any fix-ups
2365 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2366 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
2367 ObjectFile::Reference* ref = *it;
2368 if ( fOptions.outputKind() == Options::kObjectFile ) {
2370 // skip fix-ups for undefined targets
2371 if ( &(ref->getTarget()) != NULL )
2372 this->fixUpReferenceRelocatable(ref, atom, buffer);
2375 // producing final linked image
2376 this->fixUpReferenceFinal(ref, atom, buffer);
2380 catch (const char* msg) {
2381 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
2383 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s\n", offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName());
2385 ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
2397 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2399 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2400 switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
2402 case x86::kFollowOn:
2405 case x86::kPointerWeakImport:
2408 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition ) {
2409 // external realocation ==> pointer contains addend
2410 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2413 // internal relocation => pointer contains target address
2414 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2415 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2419 case x86::kPointerDiff:
2420 LittleEndian::set32(*fixUp,
2421 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2423 case x86::kPCRel32WeakImport:
2425 int64_t displacement = 0;
2426 switch ( ref->getTarget().getDefinitionKind() ) {
2427 case ObjectFile::Atom::kRegularDefinition:
2428 case ObjectFile::Atom::kWeakDefinition:
2429 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2431 case ObjectFile::Atom::kExternalDefinition:
2432 case ObjectFile::Atom::kExternalWeakDefinition:
2433 throw "codegen problem, can't use rel32 to external symbol";
2434 case ObjectFile::Atom::kTentativeDefinition:
2438 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2439 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2440 //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());
2441 throw "rel32 out of range";
2443 LittleEndian::set32(*fixUp, (int32_t)displacement);
2449 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2451 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2452 bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2453 && shouldExport(ref->getTarget()) );
2454 switch (ref->getKind()) {
2456 case x86::kFollowOn:
2462 // external realocation ==> pointer contains addend
2463 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2466 // internal relocation
2467 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
2468 // pointer contains target address
2469 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2472 // pointer contains addend
2473 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2478 case x86::kPointerDiff:
2479 LittleEndian::set32(*fixUp,
2480 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2483 int64_t displacement = 0;
2485 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2487 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2488 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2489 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2490 //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());
2491 throw "rel32 out of range";
2493 LittleEndian::set32(*fixUp, (int32_t)displacement);
2500 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2502 fixUpReference_powerpc(ref, inAtom, buffer, true);
2506 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2508 fixUpReference_powerpc(ref, inAtom, buffer, true);
2512 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2514 fixUpReference_powerpc(ref, inAtom, buffer, false);
2518 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2520 fixUpReference_powerpc(ref, inAtom, buffer, false);
2524 // ppc and ppc64 are mostly the same, so they share a template specialzation
2526 template <typename A>
2527 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
2529 uint32_t instruction;
2530 uint32_t newInstruction;
2531 int64_t displacement;
2532 uint64_t targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
2533 uint64_t picBaseAddr;
2534 uint16_t instructionLowHalf;
2535 uint16_t instructionHighHalf;
2536 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2537 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
2538 bool relocateableExternal;
2540 if ( finalLinkedImage )
2541 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
2543 relocateableExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2544 && shouldExport(ref->getTarget()) );
2546 const int64_t picbase_twoGigLimit = 0x80000000;
2548 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
2553 case A::kPointerWeakImport:
2556 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
2557 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
2558 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
2559 if ( fDyldHelper == NULL )
2560 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2561 P::setP(*fixUpPointer, fDyldHelper->getAddress());
2563 else if ( relocateableExternal ) {
2564 // external realocation ==> pointer contains addend
2565 P::setP(*fixUpPointer, ref->getTargetOffset());
2568 // internal relocation
2569 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
2570 // pointer contains target address
2571 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2572 P::setP(*fixUpPointer, targetAddr);
2575 // pointer contains addend
2576 P::setP(*fixUpPointer, ref->getTargetOffset());
2581 case A::kPointerDiff64:
2582 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2584 case A::kPointerDiff32:
2585 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2587 case A::kBranch24WeakImport:
2590 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
2591 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
2592 if ( relocateableExternal ) {
2593 // doing "ld -r" to an external symbol
2594 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
2595 displacement -= ref->getTarget().getAddress();
2598 const int64_t bl_eightMegLimit = 0x00FFFFFF;
2599 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
2600 //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());
2601 throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s",
2602 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
2603 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
2606 instruction = BigEndian::get32(*fixUp);
2607 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
2608 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
2609 BigEndian::set32(*fixUp, newInstruction);
2614 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
2615 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
2616 if ( relocateableExternal ) {
2617 // doing "ld -r" to an external symbol
2618 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
2619 displacement -= ref->getTarget().getAddress();
2622 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
2623 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
2624 //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());
2625 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
2626 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
2627 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
2630 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
2631 instruction = BigEndian::get32(*fixUp);
2632 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
2633 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
2634 BigEndian::set32(*fixUp, newInstruction);
2637 case A::kPICBaseLow16:
2638 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
2639 displacement = targetAddr - picBaseAddr;
2640 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
2641 throw "32-bit pic-base out of range";
2642 instructionLowHalf = (displacement & 0xFFFF);
2643 instruction = BigEndian::get32(*fixUp);
2644 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
2645 BigEndian::set32(*fixUp, newInstruction);
2647 case A::kPICBaseLow14:
2648 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
2649 displacement = targetAddr - picBaseAddr;
2650 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
2651 throw "32-bit pic-base out of range";
2652 if ( (displacement & 0x3) != 0 )
2653 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
2654 instructionLowHalf = (displacement & 0xFFFC);
2655 instruction = BigEndian::get32(*fixUp);
2656 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
2657 BigEndian::set32(*fixUp, newInstruction);
2659 case A::kPICBaseHigh16:
2660 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
2661 displacement = targetAddr - picBaseAddr;
2662 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
2663 throw "32-bit pic-base out of range";
2664 instructionLowHalf = displacement >> 16;
2665 if ( (displacement & 0x00008000) != 0 )
2666 ++instructionLowHalf;
2667 instruction = BigEndian::get32(*fixUp);
2668 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
2669 BigEndian::set32(*fixUp, newInstruction);
2672 if ( relocateableExternal )
2673 targetAddr -= ref->getTarget().getAddress();
2674 instructionLowHalf = (targetAddr & 0xFFFF);
2675 instruction = BigEndian::get32(*fixUp);
2676 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
2677 BigEndian::set32(*fixUp, newInstruction);
2680 if ( relocateableExternal )
2681 targetAddr -= ref->getTarget().getAddress();
2682 if ( (targetAddr & 0x3) != 0 )
2683 throw "bad address for absolute lo14 instruction fix-up";
2684 instructionLowHalf = (targetAddr & 0xFFFF);
2685 instruction = BigEndian::get32(*fixUp);
2686 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
2687 BigEndian::set32(*fixUp, newInstruction);
2690 if ( relocateableExternal )
2691 targetAddr -= ref->getTarget().getAddress();
2692 instructionHighHalf = (targetAddr >> 16);
2693 instruction = BigEndian::get32(*fixUp);
2694 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
2695 BigEndian::set32(*fixUp, newInstruction);
2697 case A::kAbsHigh16AddLow:
2698 if ( relocateableExternal )
2699 targetAddr -= ref->getTarget().getAddress();
2700 if ( targetAddr & 0x00008000 )
2701 targetAddr += 0x00010000;
2702 instruction = BigEndian::get32(*fixUp);
2703 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
2704 BigEndian::set32(*fixUp, newInstruction);
2710 bool Writer<ppc>::stubableReferenceKind(uint8_t kind)
2712 return (kind == ppc::kBranch24 || kind == ppc::kBranch24WeakImport);
2716 bool Writer<ppc64>::stubableReferenceKind(uint8_t kind)
2718 return (kind == ppc64::kBranch24 || kind == ppc64::kBranch24WeakImport);
2722 bool Writer<x86>::stubableReferenceKind(uint8_t kind)
2724 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
2729 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
2731 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
2735 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
2737 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
2741 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
2743 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
2749 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
2755 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
2761 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
2768 template <typename A>
2769 void Writer<A>::synthesizeStubs()
2771 switch ( fOptions.outputKind() ) {
2772 case Options::kStaticExecutable:
2773 case Options::kDyld:
2774 case Options::kObjectFile:
2775 // these output kinds never have stubs
2777 case Options::kDynamicLibrary:
2778 case Options::kDynamicBundle:
2779 case Options::kDynamicExecutable:
2780 // try to synthesize stubs for these
2784 // walk every atom and reference
2785 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2786 ObjectFile::Atom* atom = *it;
2787 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2788 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2789 ObjectFile::Reference* ref = *rit;
2790 ObjectFile::Atom& target = ref->getTarget();
2791 // build map of which symbols need weak importing
2792 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
2793 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
2794 bool weakImport = this->weakImportReferenceKind(ref->getKind());
2795 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
2796 if ( pos == fWeakImportMap.end() ) {
2797 // target not in fWeakImportMap, so add
2798 fWeakImportMap[&target] = weakImport;
2801 // target in fWeakImportMap, check for weakness mismatch
2802 if ( pos->second != weakImport ) {
2804 switch ( fOptions.weakReferenceMismatchTreatment() ) {
2805 case Options::kWeakReferenceMismatchError:
2806 throwf("mismatching weak references for symbol: %s", target.getName());
2807 case Options::kWeakReferenceMismatchWeak:
2810 case Options::kWeakReferenceMismatchNonWeak:
2811 pos->second = false;
2817 // create stubs as needed
2818 if ( this->stubableReferenceKind(ref->getKind())
2819 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
2820 ObjectFile::Atom* stub = NULL;
2821 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
2822 if ( pos == fStubsMap.end() ) {
2823 stub = new StubAtom<A>(*this, target);
2824 fStubsMap[&target] = stub;
2829 // alter reference to use stub instead
2830 ref->setTarget(*stub, 0);
2832 // create GOT slots (non-lazy pointers) as needed
2833 else if ( this->GOTReferenceKind(ref->getKind()) ) {
2834 ObjectFile::Atom* nlp = NULL;
2835 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
2836 if ( pos == fGOTMap.end() ) {
2837 nlp = new NonLazyPointerAtom<A>(*this, target);
2838 fGOTMap[&target] = nlp;
2843 // alter reference to use non lazy pointer instead
2844 ref->setTarget(*nlp, 0);
2851 // sort lazy pointers
2853 // add stubs to fAllAtoms
2854 if ( fAllSynthesizedStubs.size() != 0 ) {
2855 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
2856 std::vector<ObjectFile::Atom*> mergedStubs;
2857 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
2858 // when we have stubs and helpers, insert both into fAllAtoms
2859 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
2860 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
2861 stubs = &mergedStubs;
2863 ObjectFile::Section* curSection = NULL;
2864 ObjectFile::Atom* prevAtom = NULL;
2865 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2866 ObjectFile::Atom* atom = *it;
2867 ObjectFile::Section* nextSection = atom->getSection();
2868 if ( nextSection != curSection ) {
2869 // HACK HACK for i386 where stubs are not in _TEXT segment
2870 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
2871 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
2872 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
2873 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
2874 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
2879 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
2880 // found end of __text section, insert stubs here
2881 fAllAtoms->insert(it, stubs->begin(), stubs->end());
2885 curSection = nextSection;
2892 // add lazy pointers to fAllAtoms
2893 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
2894 ObjectFile::Section* curSection = NULL;
2895 ObjectFile::Atom* prevAtom = NULL;
2896 bool inserted = false;
2897 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2898 ObjectFile::Atom* atom = *it;
2899 ObjectFile::Section* nextSection = atom->getSection();
2900 if ( nextSection != curSection ) {
2901 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
2902 // found end of __dyld section, insert lazy pointers here
2903 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
2907 curSection = nextSection;
2912 throw "can't insert lazy pointers, __dyld section not found";
2916 // add non-lazy pointers to fAllAtoms
2917 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
2918 ObjectFile::Section* curSection = NULL;
2919 ObjectFile::Atom* prevAtom = NULL;
2920 bool inserted = false;
2921 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2922 ObjectFile::Atom* atom = *it;
2923 ObjectFile::Section* nextSection = atom->getSection();
2924 if ( nextSection != curSection ) {
2925 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
2926 // found end of __dyld section, insert lazy pointers here
2927 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
2931 curSection = nextSection;
2936 throw "can't insert non-lazy pointers, __dyld section not found";
2942 template <typename A>
2943 void Writer<A>::partitionIntoSections()
2945 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
2947 // for every atom, set its sectionInfo object and section offset
2948 // build up fSegmentInfos along the way
2949 ObjectFile::Section* curSection = NULL;
2950 SectionInfo* currentSectionInfo = NULL;
2951 SegmentInfo* currentSegmentInfo = NULL;
2952 unsigned int sectionIndex = 1;
2953 fSegmentInfos.reserve(8);
2954 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
2955 ObjectFile::Atom* atom = (*fAllAtoms)[i];
2956 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
2957 if ( oneSegmentCommand ) {
2958 if ( currentSegmentInfo == NULL ) {
2959 currentSegmentInfo = new SegmentInfo();
2960 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
2961 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
2962 this->fSegmentInfos.push_back(currentSegmentInfo);
2964 currentSectionInfo = new SectionInfo();
2965 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
2966 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
2967 currentSectionInfo->fAlignment = atom->getAlignment();
2968 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
2969 currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') || (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) );
2970 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
2971 currentSectionInfo->setIndex(sectionIndex++);
2972 currentSegmentInfo->fSections.push_back(currentSectionInfo);
2975 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
2976 currentSegmentInfo = new SegmentInfo();
2977 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
2978 uint32_t initprot = 0;
2979 if ( atom->getSegment().isContentReadable() )
2980 initprot |= VM_PROT_READ;
2981 if ( atom->getSegment().isContentWritable() )
2982 initprot |= VM_PROT_WRITE;
2983 if ( atom->getSegment().isContentExecutable() )
2984 initprot |= VM_PROT_EXECUTE;
2985 currentSegmentInfo->fInitProtection = initprot;
2986 if ( initprot == 0 )
2987 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
2989 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
2990 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
2991 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
2992 this->fSegmentInfos.push_back(currentSegmentInfo);
2994 currentSectionInfo = new SectionInfo();
2995 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
2996 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
2997 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
2998 currentSectionInfo->fAlignment = atom->getAlignment();
2999 // check for -sectalign override
3000 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
3001 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
3002 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
3003 currentSectionInfo->fAlignment = it->alignment;
3005 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
3006 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
3007 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
3008 currentSectionInfo->setIndex(sectionIndex++);
3009 currentSegmentInfo->fSections.push_back(currentSectionInfo);
3011 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
3012 fLoadCommandsSection = currentSectionInfo;
3013 fLoadCommandsSegment = currentSegmentInfo;
3015 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
3016 currentSectionInfo->fAllLazyPointers = true;
3017 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
3018 currentSectionInfo->fAllLazyPointers = true;
3019 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
3020 currentSectionInfo->fAllNonLazyPointers = true;
3021 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
3022 currentSectionInfo->fAllNonLazyPointers = true;
3023 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
3024 currentSectionInfo->fAllStubs = true;
3025 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
3026 currentSectionInfo->fAllStubs = true;
3027 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
3028 currentSectionInfo->fAllStubs = true;
3029 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
3030 currentSectionInfo->fAllStubs = true;
3031 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) )
3032 currentSectionInfo->fAllSelfModifyingStubs = true;
3033 curSection = atom->getSection();
3035 // any non-zero fill atoms make whole section marked not-zero-fill
3036 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
3037 currentSectionInfo->fAllZeroFill = false;
3038 // change section object to be Writer's SectionInfo object
3039 atom->setSection(currentSectionInfo);
3040 // section alignment is that of a contained atom with the greatest alignment
3041 uint8_t atomAlign = atom->getAlignment();
3042 if ( currentSectionInfo->fAlignment < atomAlign )
3043 currentSectionInfo->fAlignment = atomAlign;
3044 // calculate section offset for this atom
3045 uint64_t offset = currentSectionInfo->fSize;
3046 uint64_t alignment = 1 << atomAlign;
3047 offset = ( (offset+alignment-1) & (-alignment) );
3048 atom->setSectionOffset(offset);
3049 uint64_t curAtomSize = atom->getSize();
3050 currentSectionInfo->fSize = offset + curAtomSize;
3051 // add atom to section vector
3052 currentSectionInfo->fAtoms.push_back(atom);
3053 // update largest size
3054 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
3055 fLargestAtomSize = curAtomSize;
3060 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
3061 class TargetAndOffsetComparor
3064 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
3066 if ( left.atom != right.atom )
3067 return ( left.atom < right.atom );
3068 return ( left.offset < right.offset );
3073 bool Writer<ppc>::addBranchIslands()
3075 return this->addPPCBranchIslands();
3079 bool Writer<ppc64>::addBranchIslands()
3081 return this->addPPCBranchIslands();
3085 bool Writer<x86>::addBranchIslands()
3087 // x86 branches can reach entire 4G address space, so no need for branch islands
3093 inline uint8_t Writer<ppc>::branch24Reference()
3095 return ppc::kBranch24;
3099 inline uint8_t Writer<ppc64>::branch24Reference()
3101 return ppc64::kBranch24;
3105 // PowerPC can do PC relative branches as far as +/-16MB.
3106 // If a branch target is >16MB then we insert one or more
3107 // "branch islands" between the branch and its target that
3108 // allows island hoping to the target.
3110 // Branch Island Algorithm
3112 // If the __TEXT segment < 16MB, then no branch islands needed
3113 // Otherwise, every 15MB into the __TEXT segment is region is
3114 // added which can contain branch islands. Every out of range
3115 // bl instruction is checked. If it crosses a region, an island
3116 // is added to that region with the same target and the bl is
3117 // adjusted to target the island instead.
3119 // In theory, if too many islands are added to one region, it
3120 // could grow the __TEXT enough that other previously in-range
3121 // bl branches could be pushed out of range. We reduce the
3122 // probability this could happen by placing the ranges every
3123 // 15MB which means the region would have to be 1MB (256K islands)
3124 // before any branches could be pushed out of range.
3126 template <typename A>
3127 bool Writer<A>::addPPCBranchIslands()
3129 bool result = false;
3130 // Can only possibly need branch islands if __TEXT segment > 16M
3131 if ( fLoadCommandsSegment->fSize > 16000000 ) {
3132 //fprintf(stderr, "ld64: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
3133 const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
3134 SectionInfo* textSection = NULL;
3135 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
3136 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
3138 //fprintf(stderr, "ld64: checking for branch islands, __text section size=%llu\n", textSection->fSize);
3142 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
3143 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
3144 AtomToIsland regionsMap[kIslandRegionsCount];
3145 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
3146 unsigned int islandCount = 0;
3148 // create islands for branch references that are out of range
3149 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3150 ObjectFile::Atom* atom = *it;
3151 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3152 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3153 ObjectFile::Reference* ref = *rit;
3154 if ( ref->getKind() == this->branch24Reference() ) {
3155 ObjectFile::Atom& target = ref->getTarget();
3156 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
3157 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
3158 int64_t displacement = dstAddr - srcAddr;
3159 const int64_t kFifteenMegLimit = kBetweenRegions;
3160 if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
3161 for (int i=0; i < kIslandRegionsCount; ++i) {
3162 AtomToIsland* region=®ionsMap[i];
3163 int64_t islandRegionAddr = kBetweenRegions * (i+1);
3164 if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
3165 ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
3166 TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
3167 AtomToIsland::iterator pos = region->find(islandTarget);
3168 if ( pos == region->end() ) {
3169 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
3170 island->setSection(textSection);
3171 (*region)[islandTarget] = island;
3172 regionsIslands[i].push_back(island);
3174 ref->setTarget(*island, 0);
3177 ref->setTarget(*(pos->second), 0);
3186 // insert islands into __text section and adjust section offsets
3187 if ( islandCount > 0 ) {
3188 //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
3189 std::vector<ObjectFile::Atom*> newAtomList;
3190 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
3191 uint64_t islandRegionAddr = kBetweenRegions;
3192 int regionIndex = 0;
3193 uint64_t sectionOffset = 0;
3194 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
3195 ObjectFile::Atom* atom = *it;
3196 newAtomList.push_back(atom);
3197 if ( atom->getAddress() > islandRegionAddr ) {
3198 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
3199 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3200 ObjectFile::Atom* islandAtom = *rit;
3201 newAtomList.push_back(islandAtom);
3202 uint64_t alignment = 1 << (islandAtom->getAlignment());
3203 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3204 islandAtom->setSectionOffset(sectionOffset);
3205 sectionOffset += islandAtom->getSize();
3208 islandRegionAddr += kBetweenRegions;
3210 uint64_t alignment = 1 << (atom->getAlignment());
3211 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3212 atom->setSectionOffset(sectionOffset);
3213 sectionOffset += atom->getSize();
3215 // put any remaining islands at end of __text section
3216 if ( regionIndex < kIslandRegionsCount ) {
3217 sectionOffset = textSection->fSize;
3218 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
3219 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3220 ObjectFile::Atom* islandAtom = *rit;
3221 newAtomList.push_back(islandAtom);
3222 uint64_t alignment = 1 << (islandAtom->getAlignment());
3223 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3224 islandAtom->setSectionOffset(sectionOffset);
3225 sectionOffset += islandAtom->getSize();
3229 textSection->fAtoms = newAtomList;
3230 textSection->fSize = sectionOffset;
3239 template <typename A>
3240 void Writer<A>::adjustLoadCommandsAndPadding()
3242 fSegmentCommands->computeSize();
3244 // recompute load command section offsets
3245 uint64_t offset = 0;
3246 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
3247 const unsigned int atomCount = loadCommandAtoms.size();
3248 for (unsigned int i=0; i < atomCount; ++i) {
3249 ObjectFile::Atom* atom = loadCommandAtoms[i];
3250 uint64_t alignment = 1 << atom->getAlignment();
3251 offset = ( (offset+alignment-1) & (-alignment) );
3252 atom->setSectionOffset(offset);
3253 uint32_t atomSize = atom->getSize();
3254 if ( atomSize > fLargestAtomSize )
3255 fLargestAtomSize = atomSize;
3257 fLoadCommandsSection->fSize = offset;
3260 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
3261 const int sectionCount = sectionInfos.size();
3262 uint64_t paddingSize = 0;
3263 if ( fOptions.outputKind() == Options::kDyld ) {
3264 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
3265 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
3266 for(int j=0; j < sectionCount; ++j) {
3267 SectionInfo* curSection = sectionInfos[j];
3268 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
3269 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3272 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
3274 else if ( fOptions.outputKind() == Options::kObjectFile ) {
3275 // mach-o .o files need no padding between load commands and first section
3279 // calculate max padding to keep segment size same, but all free space at end of load commands
3280 uint64_t totalSize = 0;
3281 uint64_t worstCaseAlignmentPadding = 0;
3282 for(int j=0; j < sectionCount; ++j) {
3283 SectionInfo* curSection = sectionInfos[j];
3284 totalSize += curSection->fSize;
3285 if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
3286 worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
3288 uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
3289 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
3290 paddingSize = segmentSize - (totalSize+worstCaseAlignmentPadding);
3292 // if command line requires more padding than this
3293 if ( paddingSize < fOptions.minimumHeaderPad() ) {
3294 int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
3295 paddingSize += extraPages * 4096;
3299 // adjust atom size and update section size
3300 fHeaderPadding->setSize(paddingSize);
3301 for(int j=0; j < sectionCount; ++j) {
3302 SectionInfo* curSection = sectionInfos[j];
3303 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3304 curSection->fSize = paddingSize;
3308 // assign file offsets and logical address to all segments
3309 template <typename A>
3310 void Writer<A>::assignFileOffsets()
3312 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
3313 bool haveFixedSegments = false;
3314 uint64_t fileOffset = 0;
3315 uint64_t nextContiguousAddress = fOptions.baseAddress();
3317 // Run through the segments and each segment's sections to assign addresses
3318 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3319 SegmentInfo* curSegment = *segit;
3321 fileOffset = (fileOffset+4095) & (-4096);
3322 curSegment->fFileOffset = fileOffset;
3324 // Set the segment base address
3325 if ( curSegment->fFixedAddress )
3326 haveFixedSegments = true;
3328 curSegment->fBaseAddress = nextContiguousAddress;
3330 // We've set the segment address, now run through each section.
3331 uint64_t address = curSegment->fBaseAddress;
3332 SectionInfo* firstZeroFillSection = NULL;
3333 SectionInfo* prevSection = NULL;
3335 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3337 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
3338 SectionInfo* curSection = *it;
3340 // adjust section address based on alignment
3341 uint64_t alignment = 1 << curSection->fAlignment;
3342 address = ( (address+alignment-1) & (-alignment) );
3344 // adjust file offset to match address
3345 if ( prevSection != NULL ) {
3346 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
3349 // update section info
3350 curSection->fFileOffset = fileOffset;
3351 curSection->setBaseAddress(address);
3353 // keep track of trailing zero fill sections
3354 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
3355 firstZeroFillSection = curSection;
3356 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
3357 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
3359 // update running pointers
3360 address += curSection->fSize;
3361 fileOffset += curSection->fSize;
3363 // update segment info
3364 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
3365 curSegment->fSize = curSegment->fFileSize;
3366 prevSection = curSection;
3369 if ( fOptions.outputKind() == Options::kObjectFile ) {
3370 // don't page align .o files
3373 // optimize trailing zero-fill sections to not occupy disk space
3374 if ( firstZeroFillSection != NULL ) {
3375 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
3376 fileOffset = firstZeroFillSection->fFileOffset;
3378 // page align segment size
3379 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
3380 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
3381 if ( curSegment->fBaseAddress == nextContiguousAddress )
3382 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
3386 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
3387 if ( haveFixedSegments ) {
3388 int segCount = fSegmentInfos.size();
3390 for(int i=0; i < segCount; ++i) {
3391 SegmentInfo* segment1 = fSegmentInfos[i];
3393 for(int j=0; j < segCount; ++j) {
3395 SegmentInfo* segment2 = fSegmentInfos[j];
3397 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
3398 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
3399 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3400 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3402 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
3403 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
3404 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3405 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3408 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3409 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3417 template <typename A>
3418 void Writer<A>::adjustLinkEditSections()
3420 // link edit content is always in last segment
3421 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
3422 unsigned int firstLinkEditSectionIndex = 0;
3423 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
3424 ++firstLinkEditSectionIndex;
3426 const unsigned int sectionCount = lastSeg->fSections.size();
3427 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
3428 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
3429 for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
3430 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
3431 const unsigned int atomCount = atoms.size();
3432 uint64_t sectionOffset = 0;
3433 lastSeg->fSections[i]->fFileOffset = fileOffset;
3434 lastSeg->fSections[i]->setBaseAddress(address);
3435 for (unsigned int j=0; j < atomCount; ++j) {
3436 ObjectFile::Atom* atom = atoms[j];
3437 uint64_t alignment = 1 << atom->getAlignment();
3438 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3439 atom->setSectionOffset(sectionOffset);
3440 uint64_t size = atom->getSize();
3441 sectionOffset += size;
3442 if ( size > fLargestAtomSize )
3443 fLargestAtomSize = size;
3445 lastSeg->fSections[i]->fSize = sectionOffset;
3446 fileOffset += sectionOffset;
3447 address += sectionOffset;
3449 if ( fOptions.outputKind() == Options::kObjectFile ) {
3450 //lastSeg->fBaseAddress = 0;
3451 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
3452 //lastSeg->fFileOffset = 0;
3453 //lastSeg->fFileSize =
3456 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
3457 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
3462 template <typename A>
3463 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
3465 switch ( fWriter.fOptions.outputKind() ) {
3466 case Options::kDynamicExecutable:
3467 case Options::kStaticExecutable:
3468 return ObjectFile::Atom::scopeGlobal;
3469 case Options::kDynamicLibrary:
3470 case Options::kDynamicBundle:
3471 case Options::kDyld:
3472 case Options::kObjectFile:
3473 return ObjectFile::Atom::scopeLinkageUnit;
3475 throw "unknown header type";
3478 template <typename A>
3479 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
3481 switch ( fWriter.fOptions.outputKind() ) {
3482 case Options::kDynamicExecutable:
3483 case Options::kStaticExecutable:
3484 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
3485 case Options::kDynamicLibrary:
3486 case Options::kDynamicBundle:
3487 case Options::kDyld:
3488 return ObjectFile::Atom::kSymbolTableIn;
3489 case Options::kObjectFile:
3490 return ObjectFile::Atom::kSymbolTableNotIn;
3492 throw "unknown header type";
3495 template <typename A>
3496 const char* MachHeaderAtom<A>::getName() const
3498 switch ( fWriter.fOptions.outputKind() ) {
3499 case Options::kDynamicExecutable:
3500 case Options::kStaticExecutable:
3501 return "__mh_execute_header";
3502 case Options::kDynamicLibrary:
3503 return "__mh_dylib_header";
3504 case Options::kDynamicBundle:
3505 return "__mh_bundle_header";
3506 case Options::kObjectFile:
3508 case Options::kDyld:
3509 return "__mh_dylinker_header";
3511 throw "unknown header type";
3514 template <typename A>
3515 const char* MachHeaderAtom<A>::getDisplayName() const
3517 switch ( fWriter.fOptions.outputKind() ) {
3518 case Options::kDynamicExecutable:
3519 case Options::kStaticExecutable:
3520 case Options::kDynamicLibrary:
3521 case Options::kDynamicBundle:
3522 case Options::kDyld:
3523 return this->getName();
3524 case Options::kObjectFile:
3525 return "mach header";
3527 throw "unknown header type";
3530 template <typename A>
3531 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
3534 uint32_t fileType = 0;
3535 switch ( fWriter.fOptions.outputKind() ) {
3536 case Options::kDynamicExecutable:
3537 case Options::kStaticExecutable:
3538 fileType = MH_EXECUTE;
3540 case Options::kDynamicLibrary:
3541 fileType = MH_DYLIB;
3543 case Options::kDynamicBundle:
3544 fileType = MH_BUNDLE;
3546 case Options::kObjectFile:
3547 fileType = MH_OBJECT;
3549 case Options::kDyld:
3550 fileType = MH_DYLINKER;
3556 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
3557 if ( ! fWriter.fSeenFollowOnReferences )
3558 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
3561 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
3562 flags |= MH_NOUNDEFS;
3565 flags = MH_DYLDLINK;
3566 if ( fWriter.fOptions.bindAtLoad() )
3567 flags |= MH_BINDATLOAD;
3568 switch ( fWriter.fOptions.nameSpace() ) {
3569 case Options::kTwoLevelNameSpace:
3570 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
3572 case Options::kFlatNameSpace:
3574 case Options::kForceFlatNameSpace:
3575 flags |= MH_FORCE_FLAT;
3578 if ( fWriter.fHasWeakExports )
3579 flags |= MH_WEAK_DEFINES;
3580 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
3581 flags |= MH_BINDS_TO_WEAK;
3583 if ( fWriter.fOptions.hasExecutableStack() )
3584 flags |= MH_ALLOW_STACK_EXECUTION;
3587 // get commands info
3588 uint32_t commandsSize = 0;
3589 uint32_t commandsCount = 0;
3591 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
3592 const unsigned int atomCount = loadCommandAtoms.size();
3593 for (unsigned int i=0; i < atomCount; ++i) {
3594 ObjectFile::Atom* atom = loadCommandAtoms[i];
3595 commandsSize += atom->getSize();
3596 // segment and symbol table atoms can contain more than one load command
3597 if ( atom == fWriter.fSegmentCommands )
3598 commandsCount += fWriter.fSegmentCommands->commandCount();
3599 else if ( atom == fWriter.fSymbolTableCommands )
3600 commandsCount += fWriter.fSymbolTableCommands->commandCount();
3601 else if ( atom->getSize() != 0)
3605 // fill out mach_header
3606 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
3608 mh->set_filetype(fileType);
3609 mh->set_ncmds(commandsCount);
3610 mh->set_sizeofcmds(commandsSize);
3611 mh->set_flags(flags);
3615 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
3617 header.set_magic(MH_MAGIC);
3618 header.set_cputype(CPU_TYPE_POWERPC);
3619 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
3623 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
3625 header.set_magic(MH_MAGIC_64);
3626 header.set_cputype(CPU_TYPE_POWERPC64);
3627 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
3628 header.set_reserved(0);
3632 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
3634 header.set_magic(MH_MAGIC);
3635 header.set_cputype(CPU_TYPE_I386);
3636 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
3640 template <typename A>
3641 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
3642 : WriterAtom<A>(writer, Segment::fgStackSegment)
3644 if ( stackGrowsDown() )
3645 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
3647 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
3652 bool CustomStackAtom<ppc>::stackGrowsDown()
3658 bool CustomStackAtom<ppc64>::stackGrowsDown()
3664 bool CustomStackAtom<x86>::stackGrowsDown()
3670 template <typename A>
3671 void SegmentLoadCommandsAtom<A>::computeSize()
3674 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
3675 const int segCount = segmentInfos.size();
3676 for(int i=0; i < segCount; ++i) {
3677 size += sizeof(macho_segment_command<P>);
3678 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
3679 const int sectionCount = sectionInfos.size();
3680 for(int j=0; j < sectionCount; ++j) {
3681 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
3682 size += sizeof(macho_section<P>);
3686 fCommandCount = segCount;
3690 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
3692 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
3696 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
3698 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
3702 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
3704 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
3709 template <typename A>
3710 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3712 uint64_t size = this->getSize();
3713 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
3714 bzero(buffer, size);
3715 uint8_t* p = buffer;
3716 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
3717 const int segCount = segmentInfos.size();
3718 for(int i=0; i < segCount; ++i) {
3719 SegmentInfo* segInfo = segmentInfos[i];
3720 const int sectionCount = segInfo->fSections.size();
3721 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
3722 cmd->set_cmd(macho_segment_command<P>::CMD);
3723 cmd->set_segname(segInfo->fName);
3724 cmd->set_vmaddr(segInfo->fBaseAddress);
3725 cmd->set_vmsize(segInfo->fSize);
3726 cmd->set_fileoff(segInfo->fFileOffset);
3727 cmd->set_filesize(segInfo->fFileSize);
3728 cmd->set_maxprot(segInfo->fMaxProtection);
3729 cmd->set_initprot(segInfo->fInitProtection);
3730 // add sections array
3731 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
3732 unsigned int sectionsEmitted = 0;
3733 for (int j=0; j < sectionCount; ++j) {
3734 SectionInfo* sectInfo = segInfo->fSections[j];
3735 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
3736 macho_section<P>* sect = §ions[sectionsEmitted++];
3738 // .o file segment does not cover load commands, so recalc at first real section
3739 if ( sectionsEmitted == 1 ) {
3740 cmd->set_vmaddr(sectInfo->getBaseAddress());
3741 cmd->set_fileoff(sectInfo->fFileOffset);
3743 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
3744 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
3746 sect->set_sectname(sectInfo->fSectionName);
3747 sect->set_segname(sectInfo->fSegmentName);
3748 sect->set_addr(sectInfo->getBaseAddress());
3749 sect->set_size(sectInfo->fSize);
3750 sect->set_offset(sectInfo->fFileOffset);
3751 sect->set_align(sectInfo->fAlignment);
3752 if ( sectInfo->fRelocCount != 0 ) {
3753 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
3754 sect->set_nreloc(sectInfo->fRelocCount);
3756 if ( sectInfo->fAllZeroFill ) {
3757 sect->set_flags(S_ZEROFILL);
3758 sect->set_offset(0);
3760 else if ( sectInfo->fAllLazyPointers ) {
3761 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
3762 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3764 else if ( sectInfo->fAllNonLazyPointers ) {
3765 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
3766 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3768 else if ( sectInfo->fAllStubs ) {
3769 sect->set_flags(S_SYMBOL_STUBS);
3770 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3771 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
3773 else if ( sectInfo->fAllSelfModifyingStubs ) {
3774 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
3775 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3776 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
3778 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3779 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
3781 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3782 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
3784 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3785 sect->set_flags(S_COALESCED);
3787 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3788 sect->set_flags(S_COALESCED);
3790 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3791 sect->set_flags(S_COALESCED);
3793 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3794 sect->set_flags(S_INTERPOSING);
3796 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3797 sect->set_flags(S_CSTRING_LITERALS);
3799 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3800 sect->set_flags(S_4BYTE_LITERALS);
3802 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3803 sect->set_flags(S_8BYTE_LITERALS);
3805 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
3806 sect->set_flags(S_LITERAL_POINTERS);
3810 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
3811 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
3812 cmd->set_nsects(sectionsEmitted);
3817 template <typename A>
3818 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
3819 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
3821 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
3822 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
3823 writer.fSymbolTableCommands = this;
3826 template <typename A>
3827 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
3829 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable )
3830 return this->alignedSize(sizeof(macho_symtab_command<P>));
3832 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
3835 template <typename A>
3836 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3838 // build LC_DYSYMTAB command
3839 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
3840 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
3841 symbolTableCmd->set_cmd(LC_SYMTAB);
3842 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
3843 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
3844 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
3845 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
3846 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
3848 // build LC_DYSYMTAB command
3849 if ( fWriter.fOptions.outputKind() != Options::kStaticExecutable ) {
3850 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
3851 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
3852 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
3853 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
3854 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
3855 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
3856 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
3857 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
3858 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
3859 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
3860 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
3861 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
3862 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
3863 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
3864 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
3865 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
3866 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
3871 template <typename A>
3872 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
3874 return (fWriter.fOptions.outputKind() == Options::kStaticExecutable) ? 1 : 2;
3877 template <typename A>
3878 uint64_t DyldLoadCommandsAtom<A>::getSize() const
3880 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
3883 template <typename A>
3884 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3886 uint64_t size = this->getSize();
3887 bzero(buffer, size);
3888 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
3889 if ( fWriter.fOptions.outputKind() == Options::kDyld )
3890 cmd->set_cmd(LC_ID_DYLINKER);
3892 cmd->set_cmd(LC_LOAD_DYLINKER);
3893 cmd->set_cmdsize(this->getSize());
3894 cmd->set_name_offset();
3895 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
3898 template <typename A>
3899 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
3901 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
3904 template <typename A>
3905 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3907 uint64_t size = this->getSize();
3909 bzero(buffer, size);
3910 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
3911 cmd->set_cmd(LC_SUB_CLIENT);
3912 cmd->set_cmdsize(size);
3913 cmd->set_client_offset();
3914 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
3918 template <typename A>
3919 uint64_t DylibLoadCommandsAtom<A>::getSize() const
3921 const char* path = fInfo.reader->getInstallPath();
3922 if ( fInfo.options.fInstallPathOverride != NULL )
3923 path = fInfo.options.fInstallPathOverride;
3924 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
3927 template <typename A>
3928 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3930 uint64_t size = this->getSize();
3931 bzero(buffer, size);
3932 const char* path = fInfo.reader->getInstallPath();
3933 if ( fInfo.options.fInstallPathOverride != NULL )
3934 path = fInfo.options.fInstallPathOverride;
3935 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
3936 if ( fInfo.options.fWeakImport )
3937 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
3939 cmd->set_cmd(LC_LOAD_DYLIB);
3940 cmd->set_cmdsize(this->getSize());
3941 cmd->set_timestamp(fInfo.reader->getTimestamp());
3942 cmd->set_current_version(fInfo.reader->getCurrentVersion());
3943 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
3944 cmd->set_name_offset();
3945 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
3950 template <typename A>
3951 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
3953 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
3956 template <typename A>
3957 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3959 struct timeval currentTime = { 0 , 0 };
3960 gettimeofday(¤tTime, NULL);
3961 time_t timestamp = currentTime.tv_sec;
3962 uint64_t size = this->getSize();
3963 bzero(buffer, size);
3964 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
3965 cmd->set_cmd(LC_ID_DYLIB);
3966 cmd->set_cmdsize(this->getSize());
3967 cmd->set_name_offset();
3968 cmd->set_timestamp(timestamp);
3969 cmd->set_current_version(fWriter.fOptions.currentVersion());
3970 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
3971 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
3975 template <typename A>
3976 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3978 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
3979 bzero(buffer, sizeof(macho_routines_command<P>));
3980 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
3981 cmd->set_cmd(macho_routines_command<P>::CMD);
3982 cmd->set_cmdsize(this->getSize());
3983 cmd->set_init_address(initAddr);
3987 template <typename A>
3988 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
3990 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
3993 template <typename A>
3994 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3996 uint64_t size = this->getSize();
3997 bzero(buffer, size);
3998 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
3999 cmd->set_cmd(LC_SUB_UMBRELLA);
4000 cmd->set_cmdsize(this->getSize());
4001 cmd->set_sub_umbrella_offset();
4002 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
4005 template <typename A>
4006 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
4009 uint64_t size = this->getSize();
4010 bzero(buffer, size);
4011 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
4012 cmd->set_cmd(LC_UUID);
4013 cmd->set_cmdsize(this->getSize());
4014 cmd->set_uuid((uint8_t*)fUUID);
4018 template <typename A>
4019 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
4021 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
4024 template <typename A>
4025 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4027 uint64_t size = this->getSize();
4028 bzero(buffer, size);
4029 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
4030 cmd->set_cmd(LC_SUB_LIBRARY);
4031 cmd->set_cmdsize(this->getSize());
4032 cmd->set_sub_library_offset();
4033 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
4034 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
4037 template <typename A>
4038 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
4040 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
4043 template <typename A>
4044 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4046 uint64_t size = this->getSize();
4047 bzero(buffer, size);
4048 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
4049 cmd->set_cmd(LC_SUB_FRAMEWORK);
4050 cmd->set_cmdsize(this->getSize());
4051 cmd->set_umbrella_offset();
4052 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
4056 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
4058 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
4062 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
4064 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
4068 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
4070 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
4075 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4077 uint64_t size = this->getSize();
4078 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4079 bzero(buffer, size);
4080 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
4081 cmd->set_cmd(LC_UNIXTHREAD);
4082 cmd->set_cmdsize(size);
4083 cmd->set_flavor(1); // PPC_THREAD_STATE
4084 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
4085 cmd->set_thread_register(0, start);
4086 if ( fWriter.fOptions.hasCustomStack() )
4087 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
4092 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4094 uint64_t size = this->getSize();
4095 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4096 bzero(buffer, size);
4097 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
4098 cmd->set_cmd(LC_UNIXTHREAD);
4099 cmd->set_cmdsize(size);
4100 cmd->set_flavor(5); // PPC_THREAD_STATE64
4101 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
4102 cmd->set_thread_register(0, start);
4103 if ( fWriter.fOptions.hasCustomStack() )
4104 cmd->set_thread_register(6, fWriter.fOptions.customStackAddr()); // r1
4108 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
4110 uint64_t size = this->getSize();
4111 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4112 bzero(buffer, size);
4113 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
4114 cmd->set_cmd(LC_UNIXTHREAD);
4115 cmd->set_cmdsize(size);
4116 cmd->set_flavor(1); // i386_THREAD_STATE
4117 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
4118 cmd->set_thread_register(10, start);
4119 if ( fWriter.fOptions.hasCustomStack() )
4120 cmd->set_thread_register(15, fWriter.fOptions.customStackAddr()); // uesp
4126 template <typename A>
4127 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
4129 bzero(buffer, fSize);
4132 template <typename A>
4133 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
4136 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
4137 if ( fWriter.fLargestAtomSize < newSize )
4138 fWriter.fLargestAtomSize = newSize;
4141 template <typename A>
4142 uint64_t LinkEditAtom<A>::getFileOffset() const
4144 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
4148 template <typename A>
4149 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
4151 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
4154 template <typename A>
4155 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4157 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
4161 template <typename A>
4162 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
4164 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
4167 template <typename A>
4168 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4170 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
4175 template <typename A>
4176 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
4178 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
4181 template <typename A>
4182 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4184 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
4187 template <typename A>
4188 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
4190 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
4193 template <typename A>
4194 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4196 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
4201 template <typename A>
4202 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
4204 return fTable.size() * sizeof(uint32_t);
4207 template <typename A>
4208 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4210 uint64_t size = this->getSize();
4211 bzero(buffer, size);
4212 const uint32_t indirectTableSize = fTable.size();
4213 uint32_t* indirectTable = (uint32_t*)buffer;
4214 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
4215 if ( it->indirectIndex < indirectTableSize ) {
4216 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
4219 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
4226 template <typename A>
4227 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
4228 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
4230 fCurrentBuffer = new char[kBufferSize];
4231 // burn first byte of string pool (so zero is never a valid string offset)
4232 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
4233 // make offset 1 always point to an empty string
4234 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
4237 template <typename A>
4238 uint64_t StringsLinkEditAtom<A>::getSize() const
4240 return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4243 template <typename A>
4244 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4246 uint64_t offset = 0;
4247 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
4248 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
4249 offset += kBufferSize;
4251 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
4254 template <typename A>
4255 int32_t StringsLinkEditAtom<A>::add(const char* name)
4257 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4258 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
4259 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
4260 fCurrentBufferUsed += lenNeeded;
4263 int copied = kBufferSize-fCurrentBufferUsed-1;
4264 // change trailing '\0' that strlcpy added to real char
4265 fCurrentBuffer[kBufferSize-1] = name[copied];
4266 // alloc next buffer
4267 fFullBuffers.push_back(fCurrentBuffer);
4268 fCurrentBuffer = new char[kBufferSize];
4269 fCurrentBufferUsed = 0;
4270 // append rest of string
4271 this->add(&name[copied+1]);
4277 template <typename A>
4278 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
4280 StringToOffset::iterator pos = fUniqueStrings.find(name);
4281 if ( pos != fUniqueStrings.end() ) {
4285 int32_t offset = this->add(name);
4286 fUniqueStrings[name] = offset;
4292 template <typename A>
4293 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
4294 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
4296 char* buf = new char[strlen(name)+32];
4297 if ( targetOffset == 0 ) {
4298 if ( islandRegion == 0 )
4299 sprintf(buf, "%s$island", name);
4301 sprintf(buf, "%s$island_%d", name, islandRegion);
4304 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
4311 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4313 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4314 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4315 OSWriteBigInt32(buffer, 0, branchInstruction);
4319 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4321 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4322 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4323 OSWriteBigInt32(buffer, 0, branchInstruction);
4327 uint64_t BranchIslandAtom<ppc>::getSize() const
4333 uint64_t BranchIslandAtom<ppc64>::getSize() const
4340 bool StubAtom<ppc64>::pic() const
4342 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
4343 // This usually only happens when a large zero-page is requested
4344 switch ( fWriter.fOptions.outputKind() ) {
4345 case Options::kDynamicExecutable:
4346 return (fWriter.fOptions.zeroPageSize() > 4096);
4347 case Options::kDynamicLibrary:
4348 case Options::kDynamicBundle:
4350 case Options::kObjectFile:
4351 case Options::kDyld:
4352 case Options::kStaticExecutable:
4355 throw "internal ld64 error: file type does not use stubs";
4359 bool StubAtom<ppc>::pic() const
4361 return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
4366 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
4367 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4369 writer.fAllSynthesizedStubs.push_back(this);
4371 LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
4373 // picbase is 8 bytes into atom
4374 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, NULL, 8));
4375 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, NULL, 8));
4378 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
4379 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
4384 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
4385 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4387 writer.fAllSynthesizedStubs.push_back(this);
4389 LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
4391 // picbase is 8 bytes into atom
4392 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, NULL, 8));
4393 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, NULL, 8));
4396 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
4397 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
4401 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
4403 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
4404 : WriterAtom<x86>(writer, Segment::fgImportSegment), fName(stubName(target.getName())), fTarget(target)
4406 writer.fAllSynthesizedStubs.push_back(this);
4410 template <typename A>
4411 const char* StubAtom<A>::stubName(const char* name)
4414 asprintf(&buf, "%s$stub", name);
4419 uint64_t StubAtom<ppc>::getSize() const
4421 return ( pic() ? 32 : 16 );
4425 uint64_t StubAtom<ppc64>::getSize() const
4427 return ( pic() ? 32 : 16 );
4431 uint64_t StubAtom<x86>::getSize() const
4438 uint8_t StubAtom<x86>::getAlignment() const
4440 // special case x86 fast stubs to be byte aligned
4445 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4448 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
4449 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
4450 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
4451 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
4452 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
4453 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
4454 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
4455 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
4458 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
4459 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
4460 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
4461 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
4466 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4469 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
4470 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
4471 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
4472 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
4473 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
4474 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
4475 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
4476 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
4479 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
4480 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
4481 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
4482 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
4487 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
4498 const char* StubAtom<ppc>::getSectionName() const
4500 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
4504 const char* StubAtom<ppc64>::getSectionName() const
4506 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
4510 const char* StubAtom<x86>::getSectionName() const
4512 return "__jump_table";
4519 template <typename A>
4520 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
4521 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
4523 writer.fAllSynthesizedLazyPointers.push_back(this);
4525 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
4530 template <typename A>
4531 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
4534 asprintf(&buf, "%s$lazy_pointer", name);
4538 template <typename A>
4539 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
4541 bzero(buffer, getSize());
4545 template <typename A>
4546 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
4547 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
4549 writer.fAllSynthesizedNonLazyPointers.push_back(this);
4551 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
4554 template <typename A>
4555 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
4558 asprintf(&buf, "%s$non_lazy_pointer", name);
4562 template <typename A>
4563 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
4565 bzero(buffer, getSize());
4570 }; // namespace executable
4571 }; // namespace mach_o
4574 #endif // __EXECUTABLE_MACH_O__