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 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
193 bool referenceRequiresRuntimeFixUp(const ObjectFile::Reference* ref, bool slideable) const;
194 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
195 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
196 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
197 uint8_t buffer[], bool finalLinkedImage) const;
198 uint32_t symbolIndex(ObjectFile::Atom& atom);
199 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
200 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
201 uint8_t getRelocPointerSize();
202 bool stubableReferenceKind(uint8_t kind);
203 bool GOTReferenceKind(uint8_t kind);
204 bool weakImportReferenceKind(uint8_t kind);
205 unsigned int collectStabs();
206 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
207 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
208 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
209 void addStabs(uint32_t startIndex);
210 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
211 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&, bool slideable);
212 bool mightNeedPadSegment();
213 void scanForAbsoluteReferences();
216 struct DirectLibrary {
217 class ObjectFile::Reader* fLibrary;
222 friend class WriterAtom<A>;
223 friend class PageZeroAtom<A>;
224 friend class CustomStackAtom<A>;
225 friend class MachHeaderAtom<A>;
226 friend class SegmentLoadCommandsAtom<A>;
227 friend class SymbolTableLoadCommandsAtom<A>;
228 friend class ThreadsLoadCommandsAtom<A>;
229 friend class DylibIDLoadCommandsAtom<A>;
230 friend class RoutinesLoadCommandsAtom<A>;
231 friend class DyldLoadCommandsAtom<A>;
232 friend class UUIDLoadCommandAtom<A>;
233 friend class LinkEditAtom<A>;
234 friend class SectionRelocationsLinkEditAtom<A>;
235 friend class LocalRelocationsLinkEditAtom<A>;
236 friend class ExternalRelocationsLinkEditAtom<A>;
237 friend class SymbolTableLinkEditAtom<A>;
238 // friend class IndirectTableLinkEditAtom<A>;
239 friend class StringsLinkEditAtom<A>;
240 friend class LoadCommandsPaddingAtom<A>;
241 friend class StubAtom<A>;
242 friend class StubHelperAtom<A>;
243 friend class LazyPointerAtom<A>;
244 friend class NonLazyPointerAtom<A>;
246 const char* fFilePath;
249 std::vector<class ObjectFile::Atom*>* fAllAtoms;
250 std::vector<class ObjectFile::Reader::Stab>* fStabs;
251 class SectionInfo* fLoadCommandsSection;
252 class SegmentInfo* fLoadCommandsSegment;
253 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
254 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
255 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
256 class UUIDLoadCommandAtom<A>* fUUIDAtom;
257 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
258 std::vector<SegmentInfo*> fSegmentInfos;
259 class SegmentInfo* fPadSegmentInfo;
260 class ObjectFile::Atom* fEntryPoint;
261 class ObjectFile::Atom* fDyldHelper;
262 std::vector<DirectLibrary> fDirectLibraries;
263 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
264 std::vector<class ObjectFile::Atom*> fExportedAtoms;
265 std::vector<class ObjectFile::Atom*> fImportedAtoms;
266 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
267 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
268 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
269 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
270 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
271 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
272 class StringsLinkEditAtom<A>* fStringsAtom;
273 class PageZeroAtom<A>* fPageZeroAtom;
274 macho_nlist<P>* fSymbolTable;
275 std::vector<macho_relocation_info<P> > fSectionRelocs;
276 std::vector<macho_relocation_info<P> > fInternalRelocs;
277 std::vector<macho_relocation_info<P> > fExternalRelocs;
278 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
279 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
280 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
281 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
282 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
283 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
284 uint32_t fSymbolTableCount;
285 uint32_t fSymbolTableStabsCount;
286 uint32_t fSymbolTableStabsStartIndex;
287 uint32_t fSymbolTableLocalCount;
288 uint32_t fSymbolTableLocalStartIndex;
289 uint32_t fSymbolTableExportCount;
290 uint32_t fSymbolTableExportStartIndex;
291 uint32_t fSymbolTableImportCount;
292 uint32_t fSymbolTableImportStartIndex;
293 uint32_t fLargestAtomSize;
294 bool fEmitVirtualSections;
295 bool fHasWeakExports;
296 bool fReferencesWeakImports;
297 bool fSeenFollowOnReferences;
298 bool fWritableSegmentPastFirst4GB;
299 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
300 SegmentInfo* fFirstWritableSegment;
304 class Segment : public ObjectFile::Segment
307 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
308 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
309 virtual const char* getName() const { return fName; }
310 virtual bool isContentReadable() const { return fReadable; }
311 virtual bool isContentWritable() const { return fWritable; }
312 virtual bool isContentExecutable() const { return fExecutable; }
313 virtual bool hasFixedAddress() const { return fFixedAddress; }
315 static Segment fgTextSegment;
316 static Segment fgPageZeroSegment;
317 static Segment fgLinkEditSegment;
318 static Segment fgStackSegment;
319 static Segment fgImportSegment;
320 static Segment fgDataSegment;
324 const bool fReadable;
325 const bool fWritable;
326 const bool fExecutable;
327 const bool fFixedAddress;
330 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
331 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
332 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
333 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
334 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
335 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
338 template <typename A>
339 class WriterAtom : public ObjectFile::Atom
342 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
343 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
345 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
346 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
347 virtual const char* getName() const { return NULL; }
348 virtual const char* getDisplayName() const { return this->getName(); }
349 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
350 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
351 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
352 virtual bool dontDeadStrip() const { return true; }
353 virtual bool isZeroFill() const { return false; }
354 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
355 virtual bool mustRemainInSection() const { return true; }
356 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
357 virtual bool requiresFollowOnAtom() const { return false; }
358 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
359 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
360 virtual uint8_t getAlignment() const { return 2; }
361 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
362 virtual void setScope(Scope) { }
366 virtual ~WriterAtom() {}
367 typedef typename A::P P;
368 typedef typename A::P::E E;
370 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
376 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
379 template <typename A>
380 class PageZeroAtom : public WriterAtom<A>
383 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
384 fSize(fWriter.fOptions.zeroPageSize()) {}
385 virtual const char* getDisplayName() const { return "page zero content"; }
386 virtual bool isZeroFill() const { return true; }
387 virtual uint64_t getSize() const { return fSize; }
388 virtual const char* getSectionName() const { return "._zeropage"; }
389 virtual uint8_t getAlignment() const { return 12; }
390 void setSize(uint64_t size) { fSize = size; }
392 using WriterAtom<A>::fWriter;
393 typedef typename A::P P;
398 template <typename A>
399 class DsoHandleAtom : public WriterAtom<A>
402 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
403 virtual const char* getName() const { return "___dso_handle"; }
404 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
405 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
406 virtual uint64_t getSize() const { return 0; }
407 virtual uint8_t getAlignment() const { return 12; }
408 virtual const char* getSectionName() const { return "._mach_header"; }
409 virtual void copyRawContent(uint8_t buffer[]) const {}
413 template <typename A>
414 class MachHeaderAtom : public WriterAtom<A>
417 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
418 virtual const char* getName() const;
419 virtual const char* getDisplayName() const;
420 virtual ObjectFile::Atom::Scope getScope() const;
421 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
422 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
423 virtual uint8_t getAlignment() const { return 12; }
424 virtual const char* getSectionName() const { return "._mach_header"; }
425 virtual void copyRawContent(uint8_t buffer[]) const;
427 using WriterAtom<A>::fWriter;
428 typedef typename A::P P;
429 void setHeaderInfo(macho_header<typename A::P>& header) const;
432 template <typename A>
433 class CustomStackAtom : public WriterAtom<A>
436 CustomStackAtom(Writer<A>& writer);
437 virtual const char* getDisplayName() const { return "custom stack content"; }
438 virtual bool isZeroFill() const { return true; }
439 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
440 virtual const char* getSectionName() const { return "._stack"; }
441 virtual uint8_t getAlignment() const { return 12; }
443 using WriterAtom<A>::fWriter;
444 typedef typename A::P P;
445 static bool stackGrowsDown();
448 template <typename A>
449 class LoadCommandAtom : public WriterAtom<A>
452 LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment) {}
453 static uint64_t alignedSize(uint64_t size);
457 template <typename A>
458 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
461 SegmentLoadCommandsAtom(Writer<A>& writer)
462 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0)
463 { writer.fSegmentCommands = this; }
464 virtual const char* getDisplayName() const { return "segment load commands"; }
465 virtual uint64_t getSize() const { return fSize; }
466 virtual uint8_t getAlignment() const { return 2; }
467 virtual const char* getSectionName() const { return "._load_commands"; }
468 virtual void copyRawContent(uint8_t buffer[]) const;
472 unsigned int commandCount() { return fCommandCount; }
474 using WriterAtom<A>::fWriter;
475 typedef typename A::P P;
476 unsigned int fCommandCount;
481 template <typename A>
482 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
485 SymbolTableLoadCommandsAtom(Writer<A>&);
486 virtual const char* getDisplayName() const { return "symbol table load commands"; }
487 virtual uint64_t getSize() const;
488 virtual uint8_t getAlignment() const { return 2; }
489 virtual const char* getSectionName() const { return "._load_commands"; }
490 virtual void copyRawContent(uint8_t buffer[]) const;
491 unsigned int commandCount();
494 using WriterAtom<A>::fWriter;
495 typedef typename A::P P;
496 macho_symtab_command<typename A::P> fSymbolTable;
497 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
500 template <typename A>
501 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
504 ThreadsLoadCommandsAtom(Writer<A>& writer)
505 : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
506 virtual const char* getDisplayName() const { return "thread load commands"; }
507 virtual uint64_t getSize() const;
508 virtual uint8_t getAlignment() const { return 2; }
509 virtual const char* getSectionName() const { return "._load_commands"; }
510 virtual void copyRawContent(uint8_t buffer[]) const;
512 using WriterAtom<A>::fWriter;
513 typedef typename A::P P;
515 uint32_t fBufferSize;
518 template <typename A>
519 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
522 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
523 virtual const char* getDisplayName() const { return "dyld load command"; }
524 virtual uint64_t getSize() const;
525 virtual uint8_t getAlignment() const { return 2; }
526 virtual const char* getSectionName() const { return "._load_commands"; }
527 virtual void copyRawContent(uint8_t buffer[]) const;
529 using WriterAtom<A>::fWriter;
530 typedef typename A::P P;
533 template <typename A>
534 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
537 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
538 LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
539 virtual const char* getDisplayName() const { return "allowable_client load command"; }
540 virtual uint64_t getSize() const;
541 virtual uint8_t getAlignment() const { return 2; }
542 virtual const char* getSectionName() const { return "._load_commands"; }
543 virtual void copyRawContent(uint8_t buffer[]) const;
545 using WriterAtom<A>::fWriter;
546 typedef typename A::P P;
547 const char* clientString;
550 template <typename A>
551 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
554 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
555 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info) {}
556 virtual const char* getDisplayName() const { return "dylib load command"; }
557 virtual uint64_t getSize() const;
558 virtual uint8_t getAlignment() const { return 2; }
559 virtual const char* getSectionName() const { return "._load_commands"; }
560 virtual void copyRawContent(uint8_t buffer[]) const;
562 using WriterAtom<A>::fWriter;
563 typedef typename A::P P;
564 ExecutableFile::DyLibUsed& fInfo;
567 template <typename A>
568 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
571 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
572 virtual const char* getDisplayName() const { return "dylib ID load command"; }
573 virtual uint64_t getSize() const;
574 virtual uint8_t getAlignment() const { return 2; }
575 virtual const char* getSectionName() const { return "._load_commands"; }
576 virtual void copyRawContent(uint8_t buffer[]) const;
578 using WriterAtom<A>::fWriter;
579 typedef typename A::P P;
582 template <typename A>
583 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
586 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
587 virtual const char* getDisplayName() const { return "routines load command"; }
588 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
589 virtual uint8_t getAlignment() const { return 2; }
590 virtual const char* getSectionName() const { return "._load_commands"; }
591 virtual void copyRawContent(uint8_t buffer[]) const;
593 using WriterAtom<A>::fWriter;
594 typedef typename A::P P;
597 template <typename A>
598 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
601 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
602 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
603 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
604 virtual uint64_t getSize() const;
605 virtual uint8_t getAlignment() const { return 2; }
606 virtual const char* getSectionName() const { return "._load_commands"; }
607 virtual void copyRawContent(uint8_t buffer[]) const;
609 typedef typename A::P P;
613 template <typename A>
614 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
617 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
618 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
619 virtual const char* getDisplayName() const { return "sub-library load command"; }
620 virtual uint64_t getSize() const;
621 virtual uint8_t getAlignment() const { return 2; }
622 virtual const char* getSectionName() const { return "._load_commands"; }
623 virtual void copyRawContent(uint8_t buffer[]) const;
625 using WriterAtom<A>::fWriter;
626 typedef typename A::P P;
627 const char* fNameStart;
631 template <typename A>
632 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
635 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
636 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
637 virtual const char* getDisplayName() const { return "umbrella load command"; }
638 virtual uint64_t getSize() const;
639 virtual uint8_t getAlignment() const { return 2; }
640 virtual const char* getSectionName() const { return "._load_commands"; }
641 virtual void copyRawContent(uint8_t buffer[]) const;
643 using WriterAtom<A>::fWriter;
644 typedef typename A::P P;
648 template <typename A>
649 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
652 UUIDLoadCommandAtom(Writer<A>& writer)
653 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) { ::uuid_generate_random(fUUID);}
654 virtual const char* getDisplayName() const { return "uuid load command"; }
655 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
656 virtual uint8_t getAlignment() const { return 2; }
657 virtual const char* getSectionName() const { return "._load_commands"; }
658 virtual void copyRawContent(uint8_t buffer[]) const;
659 virtual void emit() { fEmit = true; }
661 using WriterAtom<A>::fWriter;
662 typedef typename A::P P;
667 template <typename A>
668 class LoadCommandsPaddingAtom : public WriterAtom<A>
671 LoadCommandsPaddingAtom(Writer<A>& writer)
672 : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
673 virtual const char* getDisplayName() const { return "header padding"; }
674 virtual uint64_t getSize() const { return fSize; }
675 virtual uint8_t getAlignment() const { return 2; }
676 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
677 virtual void copyRawContent(uint8_t buffer[]) const;
679 void setSize(uint64_t newSize);
681 using WriterAtom<A>::fWriter;
682 typedef typename A::P P;
686 template <typename A>
687 class LinkEditAtom : public WriterAtom<A>
690 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment) {}
691 uint64_t getFileOffset() const;
693 typedef typename A::P P;
696 template <typename A>
697 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
700 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
701 virtual const char* getDisplayName() const { return "section relocations"; }
702 virtual uint64_t getSize() const;
703 virtual uint8_t getAlignment() const { return 3; }
704 virtual const char* getSectionName() const { return "._section_relocs"; }
705 virtual void copyRawContent(uint8_t buffer[]) const;
707 using WriterAtom<A>::fWriter;
708 typedef typename A::P P;
711 template <typename A>
712 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
715 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
716 virtual const char* getDisplayName() const { return "local relocations"; }
717 virtual uint64_t getSize() const;
718 virtual uint8_t getAlignment() const { return 3; }
719 virtual const char* getSectionName() const { return "._local_relocs"; }
720 virtual void copyRawContent(uint8_t buffer[]) const;
722 using WriterAtom<A>::fWriter;
723 typedef typename A::P P;
726 template <typename A>
727 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
730 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
731 virtual const char* getDisplayName() const { return "symbol table"; }
732 virtual uint64_t getSize() const;
733 virtual uint8_t getAlignment() const { return 2; }
734 virtual const char* getSectionName() const { return "._symbol_table"; }
735 virtual void copyRawContent(uint8_t buffer[]) const;
737 using WriterAtom<A>::fWriter;
738 typedef typename A::P P;
741 template <typename A>
742 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
745 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
746 virtual const char* getDisplayName() const { return "external relocations"; }
747 virtual uint64_t getSize() const;
748 virtual uint8_t getAlignment() const { return 3; }
749 virtual const char* getSectionName() const { return "._extern_relocs"; }
750 virtual void copyRawContent(uint8_t buffer[]) const;
752 using WriterAtom<A>::fWriter;
753 typedef typename A::P P;
756 struct IndirectEntry {
757 uint32_t indirectIndex;
758 uint32_t symbolIndex;
761 template <typename A>
762 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
765 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
766 virtual const char* getDisplayName() const { return "indirect symbol table"; }
767 virtual uint64_t getSize() const;
768 virtual uint8_t getAlignment() const { return 2; }
769 virtual const char* getSectionName() const { return "._indirect_syms"; }
770 virtual void copyRawContent(uint8_t buffer[]) const;
772 std::vector<IndirectEntry> fTable;
775 using WriterAtom<A>::fWriter;
776 typedef typename A::P P;
782 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
785 template <typename A>
786 class StringsLinkEditAtom : public LinkEditAtom<A>
789 StringsLinkEditAtom(Writer<A>& writer);
790 virtual const char* getDisplayName() const { return "string pool"; }
791 virtual uint64_t getSize() const;
792 virtual uint8_t getAlignment() const { return 2; }
793 virtual const char* getSectionName() const { return "._string_pool"; }
794 virtual void copyRawContent(uint8_t buffer[]) const;
796 int32_t add(const char* name);
797 int32_t addUnique(const char* name);
798 int32_t emptyString() { return 1; }
801 using WriterAtom<A>::fWriter;
802 typedef typename A::P P;
803 enum { kBufferSize = 0x01000000 };
804 class CStringComparor {
806 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
808 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
810 std::vector<char*> fFullBuffers;
811 char* fCurrentBuffer;
812 uint32_t fCurrentBufferUsed;
813 StringToOffset fUniqueStrings;
818 template <typename A>
819 class UndefinedSymbolProxyAtom : public WriterAtom<A>
822 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
823 virtual const char* getName() const { return fName; }
824 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
825 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
826 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
827 virtual uint64_t getSize() const { return 0; }
828 virtual const char* getSectionName() const { return "._imports"; }
830 using WriterAtom<A>::fWriter;
831 typedef typename A::P P;
835 template <typename A>
836 class BranchIslandAtom : public WriterAtom<A>
839 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
840 virtual const char* getName() const { return fName; }
841 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
842 virtual uint64_t getSize() const;
843 virtual const char* getSectionName() const { return "__text"; }
844 virtual void copyRawContent(uint8_t buffer[]) const;
846 using WriterAtom<A>::fWriter;
848 ObjectFile::Atom& fTarget;
849 uint32_t fTargetOffset;
852 template <typename A>
853 class StubAtom : public WriterAtom<A>
856 StubAtom(Writer<A>& writer, ObjectFile::Atom& target);
857 virtual const char* getName() const { return fName; }
858 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
859 virtual uint8_t getAlignment() const { return 2; }
860 virtual uint64_t getSize() const;
861 virtual const char* getSectionName() const { return "__symbol_stub1"; }
862 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
863 virtual void copyRawContent(uint8_t buffer[]) const;
864 ObjectFile::Atom* getTarget() { return &fTarget; }
866 static const char* stubName(const char* importName);
868 using WriterAtom<A>::fWriter;
870 ObjectFile::Atom& fTarget;
871 std::vector<ObjectFile::Reference*> fReferences;
874 template <typename A>
875 class StubHelperAtom : public WriterAtom<A>
878 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer);
879 virtual const char* getName() const { return fName; }
880 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
881 virtual uint8_t getAlignment() const { return 2; }
882 virtual uint64_t getSize() const;
883 virtual const char* getSectionName() const { return "__stub_helper"; }
884 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
885 virtual void copyRawContent(uint8_t buffer[]) const;
886 ObjectFile::Atom* getTarget() { return &fTarget; }
888 static const char* stubName(const char* importName);
889 using WriterAtom<A>::fWriter;
891 ObjectFile::Atom& fTarget;
892 std::vector<ObjectFile::Reference*> fReferences;
895 template <typename A>
896 class LazyPointerAtom : public WriterAtom<A>
899 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
900 virtual const char* getName() const { return fName; }
901 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
902 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
903 virtual const char* getSectionName() const { return "__la_symbol_ptr"; }
904 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
905 virtual void copyRawContent(uint8_t buffer[]) const;
906 ObjectFile::Atom* getTarget() { return &fTarget; }
908 using WriterAtom<A>::fWriter;
909 static const char* lazyPointerName(const char* importName);
911 ObjectFile::Atom& fTarget;
912 std::vector<ObjectFile::Reference*> fReferences;
916 template <typename A>
917 class NonLazyPointerAtom : public WriterAtom<A>
920 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
921 virtual const char* getName() const { return fName; }
922 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
923 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
924 virtual const char* getSectionName() const { return "__nl_symbol_ptr"; }
925 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
926 virtual void copyRawContent(uint8_t buffer[]) const;
927 ObjectFile::Atom* getTarget() { return &fTarget; }
929 using WriterAtom<A>::fWriter;
930 static const char* nonlazyPointerName(const char* importName);
932 ObjectFile::Atom& fTarget;
933 std::vector<ObjectFile::Reference*> fReferences;
937 template <typename A>
938 class WriterReference : public ObjectFile::Reference
941 typedef typename A::ReferenceKinds Kinds;
943 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
944 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
945 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target),
946 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
948 virtual ~WriterReference() {}
950 virtual bool isTargetUnbound() const { return false; }
951 virtual bool isFromTargetUnbound() const { return false; }
952 virtual uint8_t getKind() const { return (uint8_t)fKind; }
953 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
954 virtual const char* getTargetName() const { return fTarget->getName(); }
955 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
956 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
957 virtual bool hasFromTarget() const { return (fFromTarget != NULL); }
958 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
959 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
960 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = ⌖ fTargetOffset = offset; }
961 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ }
962 virtual void setFromTargetName(const char* name) { }
963 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
964 virtual const char* getDescription() const { return "writer refrence"; }
965 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
969 uint32_t fFixUpOffsetInSrc;
970 ObjectFile::Atom* fTarget;
971 uint32_t fTargetOffset;
972 ObjectFile::Atom* fFromTarget;
973 uint32_t fFromTargetOffset;
980 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
982 return (strcmp(left->getName(), right->getName()) < 0);
989 template <typename A>
990 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
991 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
992 fLoadCommandsSegment(NULL), fPadSegmentInfo(NULL), fPageZeroAtom(NULL), fLargestAtomSize(1),
993 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
994 fSeenFollowOnReferences(false), fWritableSegmentPastFirst4GB(false), fFirstWritableSegment(NULL)
996 int permissions = 0777;
997 if ( fOptions.outputKind() == Options::kObjectFile )
999 // Calling unlink first assures the file is gone so that open creates it with correct permissions
1000 // It also handles the case where fFilePath file is not writeable but its directory is
1001 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
1002 (void)unlink(fFilePath);
1003 fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
1004 if ( fFileDescriptor == -1 ) {
1005 throw "can't open file for writing";
1008 switch ( fOptions.outputKind() ) {
1009 case Options::kDynamicExecutable:
1010 case Options::kStaticExecutable:
1011 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
1012 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1013 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1014 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1015 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1016 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1017 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1018 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1019 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1020 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1021 if ( fOptions.hasCustomStack() )
1022 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
1023 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1024 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1025 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1026 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1027 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1028 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1029 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1031 case Options::kDynamicLibrary:
1032 case Options::kDynamicBundle:
1033 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1035 case Options::kObjectFile:
1036 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1037 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1038 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
1039 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
1040 if ( fOptions.initFunctionName() != NULL )
1041 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
1043 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1044 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1045 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1046 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1047 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1048 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1049 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1050 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1051 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1053 case Options::kDyld:
1054 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1055 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1056 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1057 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1058 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1059 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1060 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1061 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1062 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1063 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1064 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1065 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1066 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1070 // add extra commmands
1071 uint8_t ordinal = 1;
1072 switch ( fOptions.outputKind() ) {
1073 case Options::kDynamicExecutable:
1074 case Options::kDynamicLibrary:
1075 case Options::kDynamicBundle:
1077 // add dylib load command atoms for all dynamic libraries
1078 const unsigned int libCount = dynamicLibraries.size();
1079 for (unsigned int i=0; i < libCount; ++i) {
1080 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
1081 if ( dylibInfo.options.fBundleLoader ) {
1082 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
1084 else if ( dylibInfo.indirect ) {
1085 // find ordinal of direct reader
1086 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
1088 for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1089 if ( it->first == dylibInfo.directReader ) {
1090 //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
1091 fLibraryToOrdinal[dylibInfo.reader] = it->second;
1097 fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
1101 // see if a DylibLoadCommandsAtom has already been created for this install path
1102 bool newDylib = true;
1103 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
1104 if ( dylibInfo.options.fInstallPathOverride != NULL )
1105 dylibInstallPath = dylibInfo.options.fInstallPathOverride;
1106 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
1107 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
1108 if ( !seenDylibInfo.indirect && !seenDylibInfo.options.fBundleLoader ) {
1109 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
1110 if ( seenDylibInfo.options.fInstallPathOverride != NULL )
1111 seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
1112 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
1113 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
1121 // assign new ordinal and check for other paired load commands
1122 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
1123 fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom<A>(*this, dylibInfo));
1124 if ( dylibInfo.options.fReExport ) {
1125 // this dylib also needs a sub_x load command
1126 bool isFrameworkReExport = false;
1127 const char* lastSlash = strrchr(dylibInstallPath, '/');
1128 if ( lastSlash != NULL ) {
1129 char frameworkName[strlen(lastSlash)+20];
1130 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
1131 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
1133 if ( isFrameworkReExport ) {
1134 // needs a LC_SUB_UMBRELLA command
1135 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
1138 // needs a LC_SUB_LIBRARY command
1139 const char* nameStart = &lastSlash[1];
1140 if ( lastSlash == NULL )
1141 nameStart = dylibInstallPath;
1142 int len = strlen(nameStart);
1143 const char* dot = strchr(nameStart, '.');
1145 len = dot - nameStart;
1146 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
1152 // add umbrella command if needed
1153 if ( fOptions.umbrellaName() != NULL ) {
1154 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
1156 std::vector<const char*>& allowableClients = fOptions.allowableClients();
1157 if ( allowableClients.size() != 0 ) {
1158 for (std::vector<const char*>::iterator it=allowableClients.begin();
1159 it != allowableClients.end();
1161 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
1165 case Options::kStaticExecutable:
1166 case Options::kObjectFile:
1167 case Options::kDyld:
1171 //fprintf(stderr, "ordinals table:\n");
1172 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1173 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
1177 template <typename A>
1178 Writer<A>::~Writer()
1180 if ( fFilePath != NULL )
1181 free((void*)fFilePath);
1182 if ( fSymbolTable != NULL )
1183 delete [] fSymbolTable;
1187 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
1188 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
1189 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
1192 template <typename A>
1193 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
1195 if ( (fOptions.outputKind() == Options::kObjectFile)
1196 || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
1197 return new UndefinedSymbolProxyAtom<A>(*this, name);
1202 template <typename A>
1203 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
1205 // flat namespace images use zero for all ordinals
1206 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
1209 // is an UndefinedSymbolProxyAtom
1211 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
1212 return DYNAMIC_LOOKUP_ORDINAL;
1214 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
1215 if ( pos != fLibraryToOrdinal.end() )
1218 throw "can't find ordinal for imported symbol";
1222 template <typename A>
1223 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
1224 std::vector<class ObjectFile::Reader::Stab>& stabs,
1225 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
1230 fEntryPoint = entryPointAtom;
1231 fDyldHelper = dyldHelperAtom;
1234 // Set for create UUID
1238 // check for mdynamic-no-pic codegen which force code into low 4GB
1239 scanForAbsoluteReferences();
1241 // create inter-library stubs
1244 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
1245 partitionIntoSections();
1247 // segment load command can now be sized and padding can be set
1248 adjustLoadCommandsAndPadding();
1250 // assign each section a file offset
1251 assignFileOffsets();
1253 // if need to add branch islands, reassign file offsets
1254 if ( addBranchIslands() )
1255 assignFileOffsets();
1257 // build symbol table and relocations
1261 return writeAtoms();
1263 // clean up if any errors
1264 close(fFileDescriptor);
1265 (void)unlink(fFilePath);
1270 template <typename A>
1271 void Writer<A>::buildLinkEdit()
1273 this->collectExportedAndImportedAndLocalAtoms();
1274 this->buildSymbolTable();
1275 this->buildFixups();
1276 this->adjustLinkEditSections();
1281 template <typename A>
1282 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
1284 return atom->getAddress();
1285 // SectionInfo* info = (SectionInfo*)atom->getSection();
1286 // return info->getBaseAddress() + atom->getSectionOffset();
1289 template <typename A>
1290 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1293 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
1294 entry->set_n_type(N_EXT | N_ABS);
1297 entry->set_n_type(N_EXT | N_SECT);
1298 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
1299 if ( fOptions.keepPrivateExterns() )
1300 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
1304 // set n_sect (section number of implementation )
1305 uint8_t sectionIndex = atom->getSection()->getIndex();
1306 entry->set_n_sect(sectionIndex);
1308 // the __mh_execute_header is magic and must be an absolute symbol
1309 if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0)
1310 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
1311 entry->set_n_type(N_EXT | N_ABS);
1315 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1316 desc |= REFERENCED_DYNAMICALLY;
1317 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
1319 fHasWeakExports = true;
1321 entry->set_n_desc(desc);
1323 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1324 entry->set_n_value(this->getAtomLoadAddress(atom));
1327 template <typename A>
1328 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1331 entry->set_n_type(N_UNDF | N_EXT);
1332 if ( fOptions.keepPrivateExterns()
1333 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
1334 && (fOptions.outputKind() == Options::kObjectFile) )
1335 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
1338 entry->set_n_sect(0);
1341 if ( fOptions.outputKind() != Options::kObjectFile ) {
1342 // set n_desc ( high byte is library ordinal, low byte is reference type )
1343 desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
1345 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
1346 SET_LIBRARY_ORDINAL(desc, ordinal);
1348 catch (const char* msg) {
1349 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
1352 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1353 desc |= REFERENCED_DYNAMICALLY;
1354 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1355 desc |= N_REF_TO_WEAK;
1356 fReferencesWeakImports = true;
1358 // set weak_import attribute
1359 if ( fWeakImportMap[atom] )
1361 entry->set_n_desc(desc);
1363 // set n_value, zero for import proxy and size for tentative definition
1364 entry->set_n_value(atom->getSize());
1367 template <typename A>
1368 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1371 uint8_t type = N_SECT;
1372 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
1374 entry->set_n_type(type);
1376 // set n_sect (section number of implementation )
1377 uint8_t sectIndex = atom->getSection()->getIndex();
1378 if ( sectIndex == 0 ) {
1379 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
1380 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
1383 entry->set_n_sect(sectIndex);
1387 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
1389 entry->set_n_desc(desc);
1391 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1392 entry->set_n_value(this->getAtomLoadAddress(atom));
1396 template <typename A>
1397 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
1399 macho_nlist<P>* entry = &fSymbolTable[startIndex];
1400 for (uint32_t i=0; i < count; ++i, ++entry) {
1401 ObjectFile::Atom* atom = atoms[i];
1402 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
1403 if ( &atoms == &fExportedAtoms ) {
1404 this->setExportNlist(atom, entry);
1406 else if ( &atoms == &fImportedAtoms ) {
1407 this->setImportNlist(atom, entry);
1410 this->setLocalNlist(atom, entry);
1415 template <typename A>
1416 void Writer<A>::buildSymbolTable()
1418 fSymbolTableStabsStartIndex = 0;
1419 fSymbolTableStabsCount = fStabs->size();
1420 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
1421 fSymbolTableLocalCount = fLocalSymbolAtoms.size();
1422 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
1423 fSymbolTableExportCount = fExportedAtoms.size();
1424 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
1425 fSymbolTableImportCount = fImportedAtoms.size();
1427 // allocate symbol table
1428 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
1429 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
1431 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
1432 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount);
1433 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
1434 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
1435 addStabs(fSymbolTableStabsStartIndex);
1440 template <typename A>
1441 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
1443 if ( atom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
1445 switch ( atom.getScope() ) {
1446 case ObjectFile::Atom::scopeGlobal:
1448 case ObjectFile::Atom::scopeLinkageUnit:
1449 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
1455 template <typename A>
1456 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
1458 const int atomCount = fAllAtoms->size();
1459 // guess at sizes of each bucket to minimize re-allocations
1460 fImportedAtoms.reserve(100);
1461 fExportedAtoms.reserve(atomCount/2);
1462 fLocalSymbolAtoms.reserve(atomCount);
1463 for (int i=0; i < atomCount; ++i) {
1464 ObjectFile::Atom* atom = (*fAllAtoms)[i];
1465 // only named atoms go in symbol table
1466 if ( atom->getName() != NULL ) {
1467 // put atom into correct bucket: imports, exports, locals
1468 //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
1469 switch ( atom->getDefinitionKind() ) {
1470 case ObjectFile::Atom::kExternalDefinition:
1471 case ObjectFile::Atom::kExternalWeakDefinition:
1472 fImportedAtoms.push_back(atom);
1474 case ObjectFile::Atom::kTentativeDefinition:
1475 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.makeTentativeDefinitionsReal() ) {
1476 fImportedAtoms.push_back(atom);
1480 case ObjectFile::Atom::kRegularDefinition:
1481 case ObjectFile::Atom::kWeakDefinition:
1482 if ( this->shouldExport(*atom) )
1483 fExportedAtoms.push_back(atom);
1484 else if ( !fOptions.stripLocalSymbols()
1485 && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) )
1486 fLocalSymbolAtoms.push_back(atom);
1492 // sort exported atoms by name
1493 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
1494 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
1495 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), ExportSorter());
1499 template <typename A>
1500 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
1502 switch ( stab.type ) {
1504 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
1505 // end of function N_FUN has size
1506 return stab.atom->getSize();
1509 // start of function N_FUN has address
1510 return getAtomLoadAddress(stab.atom);
1515 if ( stab.atom == NULL )
1516 // some weird assembly files have slines not associated with a function
1519 // all these stab types need their value changed from an offset in the atom to an address
1520 return getAtomLoadAddress(stab.atom) + stab.value;
1524 // all these need address of atom
1525 return getAtomLoadAddress(stab.atom);;
1527 return stab.atom->getSize();
1529 if ( stab.atom == NULL ) {
1533 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
1534 // end of translation unit N_SO has address of end of last atom
1535 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
1538 // start of translation unit N_SO has address of end of first atom
1539 return getAtomLoadAddress(stab.atom);
1548 template <typename A>
1549 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
1551 switch (stab.type) {
1553 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
1554 return this->fStringsAtom->emptyString();
1557 // fall into uniquing case
1561 return this->fStringsAtom->addUnique(stab.string);
1564 if ( stab.string == NULL )
1566 else if ( stab.string[0] == '\0' )
1567 return this->fStringsAtom->emptyString();
1569 return this->fStringsAtom->add(stab.string);
1574 template <typename A>
1575 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
1577 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
1578 if ( stab.type == N_FUN )
1580 else if ( stab.atom != NULL )
1581 return stab.atom->getSection()->getIndex();
1586 template <typename A>
1587 void Writer<A>::addStabs(uint32_t startIndex)
1589 macho_nlist<P>* entry = &fSymbolTable[startIndex];
1590 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
1591 const ObjectFile::Reader::Stab& stab = *it;
1592 entry->set_n_type(stab.type);
1593 entry->set_n_sect(sectionIndexForStab(stab));
1594 entry->set_n_desc(stab.desc);
1595 entry->set_n_value(valueForStab(stab));
1596 entry->set_n_strx(stringOffsetForStab(stab));
1602 template <typename A>
1603 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
1607 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
1609 return i + fSymbolTableImportStartIndex;
1615 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
1617 return i + fSymbolTableLocalStartIndex;
1623 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
1625 return i + fSymbolTableExportStartIndex;
1629 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
1633 template <typename A>
1634 void Writer<A>::buildFixups()
1636 if ( fOptions.outputKind() == Options::kObjectFile ) {
1637 this->buildObjectFileFixups();
1640 if ( fOptions.keepRelocations() )
1641 this->buildObjectFileFixups();
1642 this->buildExecutableFixups();
1647 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1649 ObjectFile::Atom& target = ref->getTarget();
1650 bool external = (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
1651 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
1652 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1653 macho_relocation_info<P> reloc1;
1654 macho_relocation_info<P> reloc2;
1655 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
1658 case x86_64::kNoFixUp:
1659 case x86_64::kFollowOn:
1662 case x86_64::kPointer:
1663 case x86_64::kPointerWeakImport:
1664 reloc1.set_r_address(address);
1665 reloc1.set_r_symbolnum(symbolIndex);
1666 reloc1.set_r_pcrel(false);
1667 reloc1.set_r_length(3);
1668 reloc1.set_r_extern(external);
1669 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
1670 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1673 case x86_64::kPointerDiff32:
1674 case x86_64::kPointerDiff:
1676 ObjectFile::Atom& fromTarget = ref->getFromTarget();
1677 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
1678 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
1679 reloc1.set_r_address(address);
1680 reloc1.set_r_symbolnum(symbolIndex);
1681 reloc1.set_r_pcrel(false);
1682 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
1683 reloc1.set_r_extern(external);
1684 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
1685 reloc2.set_r_address(address);
1686 reloc2.set_r_symbolnum(fromSymbolIndex);
1687 reloc2.set_r_pcrel(false);
1688 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
1689 reloc2.set_r_extern(fromExternal);
1690 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
1691 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1692 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1696 case x86_64::kBranchPCRel32:
1697 case x86_64::kBranchPCRel32WeakImport:
1698 reloc1.set_r_address(address);
1699 reloc1.set_r_symbolnum(symbolIndex);
1700 reloc1.set_r_pcrel(true);
1701 reloc1.set_r_length(2);
1702 reloc1.set_r_extern(external);
1703 reloc1.set_r_type(X86_64_RELOC_BRANCH);
1704 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1707 case x86_64::kPCRel32:
1708 case x86_64::kPCRel32_1:
1709 case x86_64::kPCRel32_2:
1710 case x86_64::kPCRel32_4:
1711 reloc1.set_r_address(address);
1712 reloc1.set_r_symbolnum(symbolIndex);
1713 reloc1.set_r_pcrel(true);
1714 reloc1.set_r_length(2);
1715 reloc1.set_r_extern(external);
1716 reloc1.set_r_type(X86_64_RELOC_SIGNED);
1717 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1720 case x86_64::kPCRel32GOT:
1721 case x86_64::kPCRel32GOTWeakImport:
1722 reloc1.set_r_address(address);
1723 reloc1.set_r_symbolnum(symbolIndex);
1724 reloc1.set_r_pcrel(true);
1725 reloc1.set_r_length(2);
1726 reloc1.set_r_extern(external);
1727 reloc1.set_r_type(X86_64_RELOC_GOT);
1728 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1731 case x86_64::kPCRel32GOTLoad:
1732 case x86_64::kPCRel32GOTLoadWeakImport:
1733 reloc1.set_r_address(address);
1734 reloc1.set_r_symbolnum(symbolIndex);
1735 reloc1.set_r_pcrel(true);
1736 reloc1.set_r_length(2);
1737 reloc1.set_r_extern(external);
1738 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
1739 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1746 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1748 ObjectFile::Atom& target = ref->getTarget();
1749 bool isExtern = false;
1750 switch ( target.getDefinitionKind() ) {
1751 case ObjectFile::Atom::kRegularDefinition:
1754 case ObjectFile::Atom::kWeakDefinition:
1755 case ObjectFile::Atom::kTentativeDefinition:
1756 case ObjectFile::Atom::kExternalDefinition:
1757 case ObjectFile::Atom::kExternalWeakDefinition:
1758 isExtern = shouldExport(target);
1761 uint32_t symbolIndex = 0;
1763 symbolIndex = this->symbolIndex(target);
1764 uint32_t sectionNum = target.getSection()->getIndex();
1765 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1766 macho_relocation_info<P> reloc1;
1767 macho_relocation_info<P> reloc2;
1768 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1769 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1770 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
1774 case x86::kFollowOn:
1778 case x86::kPointerWeakImport:
1779 case x86::kAbsolute32:
1780 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1781 // use scattered reloc is target offset is non-zero
1782 sreloc1->set_r_scattered(true);
1783 sreloc1->set_r_pcrel(false);
1784 sreloc1->set_r_length(2);
1785 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1786 sreloc1->set_r_address(address);
1787 sreloc1->set_r_value(target.getAddress());
1790 reloc1.set_r_address(address);
1791 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1792 reloc1.set_r_pcrel(false);
1793 reloc1.set_r_length(2);
1794 reloc1.set_r_extern(isExtern);
1795 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1797 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1800 case x86::kPointerDiff:
1802 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1803 sreloc1->set_r_scattered(true);
1804 sreloc1->set_r_pcrel(false);
1805 sreloc1->set_r_length(2);
1806 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
1807 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
1809 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
1810 sreloc1->set_r_address(address);
1811 sreloc1->set_r_value(target.getAddress());
1812 sreloc2->set_r_scattered(true);
1813 sreloc2->set_r_pcrel(false);
1814 sreloc2->set_r_length(2);
1815 sreloc2->set_r_type(PPC_RELOC_PAIR);
1816 sreloc2->set_r_address(0);
1817 sreloc2->set_r_value(fromAddr);
1818 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1819 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1823 case x86::kPCRel32WeakImport:
1825 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1826 // use scattered reloc is target offset is non-zero
1827 sreloc1->set_r_scattered(true);
1828 sreloc1->set_r_pcrel(true);
1829 sreloc1->set_r_length(2);
1830 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1831 sreloc1->set_r_address(address);
1832 sreloc1->set_r_value(target.getAddress());
1835 reloc1.set_r_address(address);
1836 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1837 reloc1.set_r_pcrel(true);
1838 reloc1.set_r_length(2);
1839 reloc1.set_r_extern(isExtern);
1840 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1842 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1852 uint8_t Writer<ppc>::getRelocPointerSize()
1858 uint8_t Writer<ppc64>::getRelocPointerSize()
1864 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1866 return addObjectRelocs_powerpc(atom, ref);
1870 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1872 return addObjectRelocs_powerpc(atom, ref);
1876 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
1877 // they use a common addObjectRelocs_powerpc() method.
1879 template <typename A>
1880 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1882 ObjectFile::Atom& target = ref->getTarget();
1883 bool isExtern = false;
1884 switch ( target.getDefinitionKind() ) {
1885 case ObjectFile::Atom::kRegularDefinition:
1888 case ObjectFile::Atom::kWeakDefinition:
1889 case ObjectFile::Atom::kTentativeDefinition:
1890 case ObjectFile::Atom::kExternalDefinition:
1891 case ObjectFile::Atom::kExternalWeakDefinition:
1892 isExtern = shouldExport(target);
1896 uint32_t symbolIndex = 0;
1898 symbolIndex = this->symbolIndex(target);
1899 uint32_t sectionNum = target.getSection()->getIndex();
1900 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1901 macho_relocation_info<P> reloc1;
1902 macho_relocation_info<P> reloc2;
1903 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1904 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1905 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
1913 case A::kPointerWeakImport:
1914 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
1915 // use scattered reloc is target offset is outside target
1916 sreloc1->set_r_scattered(true);
1917 sreloc1->set_r_pcrel(false);
1918 sreloc1->set_r_length(getRelocPointerSize());
1919 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1920 sreloc1->set_r_address(address);
1921 sreloc1->set_r_value(target.getAddress());
1924 reloc1.set_r_address(address);
1926 reloc1.set_r_symbolnum(symbolIndex);
1928 reloc1.set_r_symbolnum(sectionNum);
1929 reloc1.set_r_pcrel(false);
1930 reloc1.set_r_length(getRelocPointerSize());
1931 reloc1.set_r_extern(isExtern);
1932 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1934 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1937 case A::kPointerDiff32:
1938 case A::kPointerDiff64:
1940 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1941 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1942 sreloc1->set_r_scattered(true);
1943 sreloc1->set_r_pcrel(false);
1944 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1945 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
1946 sreloc1->set_r_address(address);
1947 sreloc1->set_r_value(toAddr);
1948 sreloc2->set_r_scattered(true);
1949 sreloc2->set_r_pcrel(false);
1950 sreloc2->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1951 sreloc2->set_r_type(PPC_RELOC_PAIR);
1952 sreloc2->set_r_address(0);
1953 sreloc2->set_r_value(fromAddr);
1954 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1955 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1959 case A::kBranch24WeakImport:
1961 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1962 reloc1.set_r_address(address);
1964 reloc1.set_r_symbolnum(symbolIndex);
1966 reloc1.set_r_symbolnum(sectionNum);
1967 reloc1.set_r_pcrel(true);
1968 reloc1.set_r_length(2);
1969 reloc1.set_r_type(PPC_RELOC_BR24);
1970 reloc1.set_r_extern(isExtern);
1973 sreloc1->set_r_scattered(true);
1974 sreloc1->set_r_pcrel(true);
1975 sreloc1->set_r_length(2);
1976 sreloc1->set_r_type(PPC_RELOC_BR24);
1977 sreloc1->set_r_address(address);
1978 sreloc1->set_r_value(target.getAddress());
1980 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1984 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1985 reloc1.set_r_address(address);
1987 reloc1.set_r_symbolnum(symbolIndex);
1989 reloc1.set_r_symbolnum(sectionNum);
1990 reloc1.set_r_pcrel(true);
1991 reloc1.set_r_length(2);
1992 reloc1.set_r_type(PPC_RELOC_BR14);
1993 reloc1.set_r_extern(isExtern);
1996 sreloc1->set_r_scattered(true);
1997 sreloc1->set_r_pcrel(true);
1998 sreloc1->set_r_length(2);
1999 sreloc1->set_r_type(PPC_RELOC_BR14);
2000 sreloc1->set_r_address(address);
2001 sreloc1->set_r_value(target.getAddress());
2003 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2006 case A::kPICBaseLow16:
2007 case A::kPICBaseLow14:
2009 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2010 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2011 sreloc1->set_r_scattered(true);
2012 sreloc1->set_r_pcrel(false);
2013 sreloc1->set_r_length(2);
2014 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
2015 sreloc1->set_r_address(address);
2016 sreloc1->set_r_value(target.getAddress());
2017 sreloc2->set_r_scattered(true);
2018 sreloc2->set_r_pcrel(false);
2019 sreloc2->set_r_length(2);
2020 sreloc2->set_r_type(PPC_RELOC_PAIR);
2021 sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
2022 sreloc2->set_r_value(fromAddr);
2023 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2024 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2028 case A::kPICBaseHigh16:
2030 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2031 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2032 sreloc1->set_r_scattered(true);
2033 sreloc1->set_r_pcrel(false);
2034 sreloc1->set_r_length(2);
2035 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
2036 sreloc1->set_r_address(address);
2037 sreloc1->set_r_value(target.getAddress());
2038 sreloc2->set_r_scattered(true);
2039 sreloc2->set_r_pcrel(false);
2040 sreloc2->set_r_length(2);
2041 sreloc2->set_r_type(PPC_RELOC_PAIR);
2042 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
2043 sreloc2->set_r_value(fromAddr);
2044 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2045 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2052 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2053 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2054 reloc1.set_r_address(address);
2056 reloc1.set_r_symbolnum(symbolIndex);
2058 reloc1.set_r_symbolnum(sectionNum);
2059 reloc1.set_r_pcrel(false);
2060 reloc1.set_r_length(2);
2061 reloc1.set_r_extern(isExtern);
2062 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2065 sreloc1->set_r_scattered(true);
2066 sreloc1->set_r_pcrel(false);
2067 sreloc1->set_r_length(2);
2068 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2069 sreloc1->set_r_address(address);
2070 sreloc1->set_r_value(target.getAddress());
2073 reloc2.set_r_address(ref->getTargetOffset() >> 16);
2075 reloc2.set_r_address(toAddr >> 16);
2076 reloc2.set_r_symbolnum(0);
2077 reloc2.set_r_pcrel(false);
2078 reloc2.set_r_length(2);
2079 reloc2.set_r_extern(false);
2080 reloc2.set_r_type(PPC_RELOC_PAIR);
2081 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2082 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2088 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2089 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2090 reloc1.set_r_address(address);
2092 reloc1.set_r_symbolnum(symbolIndex);
2094 reloc1.set_r_symbolnum(sectionNum);
2095 reloc1.set_r_pcrel(false);
2096 reloc1.set_r_length(2);
2097 reloc1.set_r_extern(isExtern);
2098 reloc1.set_r_type(PPC_RELOC_HI16);
2101 sreloc1->set_r_scattered(true);
2102 sreloc1->set_r_pcrel(false);
2103 sreloc1->set_r_length(2);
2104 sreloc1->set_r_type(PPC_RELOC_HI16);
2105 sreloc1->set_r_address(address);
2106 sreloc1->set_r_value(target.getAddress());
2109 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2111 reloc2.set_r_address(toAddr & 0xFFFF);
2112 reloc2.set_r_symbolnum(0);
2113 reloc2.set_r_pcrel(false);
2114 reloc2.set_r_length(2);
2115 reloc2.set_r_extern(false);
2116 reloc2.set_r_type(PPC_RELOC_PAIR);
2117 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2118 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2122 case A::kAbsHigh16AddLow:
2124 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2125 uint32_t overflow = 0;
2126 if ( (toAddr & 0x00008000) != 0 )
2128 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2129 reloc1.set_r_address(address);
2131 reloc1.set_r_symbolnum(symbolIndex);
2133 reloc1.set_r_symbolnum(sectionNum);
2134 reloc1.set_r_pcrel(false);
2135 reloc1.set_r_length(2);
2136 reloc1.set_r_extern(isExtern);
2137 reloc1.set_r_type(PPC_RELOC_HA16);
2140 sreloc1->set_r_scattered(true);
2141 sreloc1->set_r_pcrel(false);
2142 sreloc1->set_r_length(2);
2143 sreloc1->set_r_type(PPC_RELOC_HA16);
2144 sreloc1->set_r_address(address);
2145 sreloc1->set_r_value(target.getAddress());
2148 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2150 reloc2.set_r_address(toAddr & 0xFFFF);
2151 reloc2.set_r_symbolnum(0);
2152 reloc2.set_r_pcrel(false);
2153 reloc2.set_r_length(2);
2154 reloc2.set_r_extern(false);
2155 reloc2.set_r_type(PPC_RELOC_PAIR);
2156 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2157 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2166 template <typename A>
2167 void Writer<A>::buildObjectFileFixups()
2169 uint32_t relocIndex = 0;
2170 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2171 const int segCount = segmentInfos.size();
2172 for(int i=0; i < segCount; ++i) {
2173 SegmentInfo* curSegment = segmentInfos[i];
2174 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2175 const int sectionCount = sectionInfos.size();
2176 for(int j=0; j < sectionCount; ++j) {
2177 SectionInfo* curSection = sectionInfos[j];
2178 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
2179 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2180 if ( ! curSection->fAllZeroFill ) {
2181 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
2182 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2183 curSection->fRelocOffset = relocIndex;
2184 const int atomCount = sectionAtoms.size();
2185 for (int k=0; k < atomCount; ++k) {
2186 ObjectFile::Atom* atom = sectionAtoms[k];
2187 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
2188 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2189 const int refCount = refs.size();
2190 for (int l=0; l < refCount; ++l) {
2191 ObjectFile::Reference* ref = refs[l];
2192 if ( ref->getKind() == A::kFollowOn )
2193 fSeenFollowOnReferences = true;
2194 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
2195 uint32_t offsetInSection = atom->getSectionOffset();
2196 uint32_t indexInSection = offsetInSection / atom->getSize();
2197 uint32_t undefinedSymbolIndex;
2198 if ( curSection->fAllStubs ) {
2199 ObjectFile::Atom& stubTarget =ref->getTarget();
2200 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
2201 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
2202 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
2205 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table
2206 if ( curSection->fAllNonLazyPointers && (ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) )
2207 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2209 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
2211 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2212 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2213 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
2214 fIndirectTableAtom->fTable.push_back(entry);
2215 if ( curSection->fAllLazyPointers ) {
2216 ObjectFile::Atom& target = ref->getTarget();
2217 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2218 if ( &fromTarget == NULL ) {
2219 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
2222 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
2223 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
2224 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
2225 macho_relocation_info<P> reloc1;
2226 reloc1.set_r_address(atom->getSectionOffset());
2227 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
2228 reloc1.set_r_pcrel(false);
2229 reloc1.set_r_length();
2230 reloc1.set_r_extern(isExtern);
2231 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2232 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2236 else if ( curSection->fAllStubs ) {
2237 relocIndex += this->addObjectRelocs(atom, ref);
2240 else if ( ref->getKind() != A::kNoFixUp ) {
2241 relocIndex += this->addObjectRelocs(atom, ref);
2245 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
2250 // now reverse reloc entries
2251 for(int i=0; i < segCount; ++i) {
2252 SegmentInfo* curSegment = segmentInfos[i];
2253 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2254 const int sectionCount = sectionInfos.size();
2255 for(int j=0; j < sectionCount; ++j) {
2256 SectionInfo* curSection = sectionInfos[j];
2257 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
2264 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2266 switch ( ref.getKind() ) {
2267 case ppc::kAbsLow16:
2268 case ppc::kAbsLow14:
2269 case ppc::kAbsHigh16:
2270 case ppc::kAbsHigh16AddLow:
2279 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2281 switch ( ref.getKind() ) {
2282 case ppc::kAbsLow16:
2283 case ppc::kAbsLow14:
2284 case ppc::kAbsHigh16:
2285 case ppc::kAbsHigh16AddLow:
2293 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2295 if ( ref.getKind() == x86::kAbsolute32 ) {
2296 switch ( ref.getTarget().getDefinitionKind() ) {
2297 case ObjectFile::Atom::kTentativeDefinition:
2298 case ObjectFile::Atom::kRegularDefinition:
2299 // illegal in dylibs/bundles, until we support TEXT relocs
2301 case ObjectFile::Atom::kWeakDefinition:
2302 // illegal if an exported weak symbol, until we support TEXT relocs
2303 return this->shouldExport(ref.getTarget());
2304 case ObjectFile::Atom::kExternalDefinition:
2305 case ObjectFile::Atom::kExternalWeakDefinition:
2306 // illegal until we support TEXT relocs
2314 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2320 template <typename A>
2321 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
2323 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2325 switch ( target.getDefinitionKind() ) {
2326 case ObjectFile::Atom::kTentativeDefinition:
2327 case ObjectFile::Atom::kRegularDefinition:
2328 // for flat-namespace or interposable two-level-namespace
2329 // all references to exported symbols get indirected
2330 if ( this->shouldExport(target) &&
2331 ((fOptions.nameSpace() == Options::kFlatNameSpace)
2332 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
2333 || fOptions.interposable()) )
2334 return kRelocExternal;
2335 else if ( slideable )
2336 return kRelocInternal;
2339 case ObjectFile::Atom::kWeakDefinition:
2340 // all calls to global weak definitions get indirected
2341 if ( this->shouldExport(target) )
2342 return kRelocExternal;
2343 else if ( slideable )
2344 return kRelocInternal;
2347 case ObjectFile::Atom::kExternalDefinition:
2348 case ObjectFile::Atom::kExternalWeakDefinition:
2349 return kRelocExternal;
2354 template <typename A>
2355 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
2357 // for 32-bit architectures, the r_address field in relocs
2358 // for final linked images is the offset from the base address
2359 uint64_t result = address - fOptions.baseAddress();
2360 if ( result > 0x7FFFFFFF ) {
2361 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
2362 atom->getDisplayName(), atom->getFile()->getPath());
2368 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
2370 // for x86_64, the r_address field in relocs for final linked images
2371 // is the offset from the start address of the first writable segment
2372 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
2373 if ( result > 0xFFFFFFFF ) {
2374 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
2375 atom->getDisplayName(), atom->getFile()->getPath());
2381 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
2383 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
2384 // the 10.5 dyld, iterprets the r_address as:
2385 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
2386 // 2) an offset from the base address of the first writable segment
2387 // For dyld, r_address is always the offset from the base address
2389 bool badFor10_4 = false;
2390 if ( fWritableSegmentPastFirst4GB ) {
2391 if ( fOptions.macosxVersionMin() < Options::k10_5 )
2393 result = address - fFirstWritableSegment->fBaseAddress;
2394 if ( result > 0xFFFFFFFF ) {
2395 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
2396 atom->getDisplayName(), atom->getFile()->getPath());
2400 result = address - fOptions.baseAddress();
2401 if ( (fOptions.macosxVersionMin() < Options::k10_5) && (result > 0x7FFFFFFF) )
2405 throwf("image or pagezero_size too large for Mac OS X 10.4: address can't fit in 31-bit r_address field for %s from %s",
2406 atom->getDisplayName(), atom->getFile()->getPath());
2412 template <typename A>
2413 void Writer<A>::buildExecutableFixups()
2415 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2416 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
2417 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2418 const int segCount = segmentInfos.size();
2419 for(int i=0; i < segCount; ++i) {
2420 SegmentInfo* curSegment = segmentInfos[i];
2421 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2422 const int sectionCount = sectionInfos.size();
2423 for(int j=0; j < sectionCount; ++j) {
2424 SectionInfo* curSection = sectionInfos[j];
2425 //fprintf(stderr, "starting section %p\n", curSection->fSectionName);
2426 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2427 if ( ! curSection->fAllZeroFill ) {
2428 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
2429 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2430 const int atomCount = sectionAtoms.size();
2431 for (int k=0; k < atomCount; ++k) {
2432 ObjectFile::Atom* atom = sectionAtoms[k];
2433 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2434 const int refCount = refs.size();
2435 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
2436 for (int l=0; l < refCount; ++l) {
2437 ObjectFile::Reference* ref = refs[l];
2438 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
2439 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
2440 if ( atom->getSize() != sizeof(pint_t) ) {
2441 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
2443 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
2444 if ( curSection->fAllLazyPointers ) {
2445 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
2447 uint32_t offsetInSection = atom->getSectionOffset();
2448 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
2449 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2450 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
2451 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
2452 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2453 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2454 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
2455 fIndirectTableAtom->fTable.push_back(entry);
2456 if ( slideable && curSection->fAllLazyPointers ) {
2457 // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
2458 macho_relocation_info<P> pblaReloc;
2459 uint32_t sectionNum = 1;
2460 if ( fDyldHelper != NULL )
2461 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
2462 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
2463 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
2464 pblaReloc.set_r_symbolnum(sectionNum);
2465 pblaReloc.set_r_pcrel(false);
2466 pblaReloc.set_r_length();
2467 pblaReloc.set_r_extern(false);
2468 pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
2469 fInternalRelocs.push_back(pblaReloc);
2472 else if ( ref->getKind() == A::kPointer ) {
2473 if ( slideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
2474 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
2475 atom->getDisplayName(), atom->getFile()->getPath());
2477 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
2481 case kRelocInternal:
2483 macho_relocation_info<P> internalReloc;
2484 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
2485 uint32_t sectionNum = sectInfo->getIndex();
2486 // special case _mh_dylib_header and friends which are not in any real section
2487 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
2489 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
2490 internalReloc.set_r_symbolnum(sectionNum);
2491 internalReloc.set_r_pcrel(false);
2492 internalReloc.set_r_length();
2493 internalReloc.set_r_extern(false);
2494 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2495 fInternalRelocs.push_back(internalReloc);
2498 case kRelocExternal:
2500 macho_relocation_info<P> externalReloc;
2501 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
2502 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
2503 externalReloc.set_r_pcrel(false);
2504 externalReloc.set_r_length();
2505 externalReloc.set_r_extern(true);
2506 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2507 fExternalRelocs.push_back(externalReloc);
2512 else if ( this->illegalRelocInFinalLinkedImage(*ref, slideable) ) {
2513 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
2516 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
2517 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
2518 uint32_t undefinedSymbolIndex = this->symbolIndex(*stubTarget);
2519 uint32_t offsetInSection = atom->getSectionOffset();
2520 uint32_t indexInSection = offsetInSection / atom->getSize();
2521 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2522 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2523 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
2524 fIndirectTableAtom->fTable.push_back(entry);
2534 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
2537 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2538 for (uint32_t p=from; p < to; p += 4)
2539 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2543 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
2546 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2547 for (uint32_t p=from; p < to; p += 4)
2548 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2552 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
2554 uint8_t x86Nop = 0x90;
2555 for (uint32_t p=from; p < to; ++p)
2556 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
2560 void Writer<x86_64>::writeNoOps(uint32_t from, uint32_t to)
2562 uint8_t x86Nop = 0x90;
2563 for (uint32_t p=from; p < to; ++p)
2564 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
2567 template <typename A>
2568 uint64_t Writer<A>::writeAtoms()
2571 uint8_t* buffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
2572 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2573 const int segCount = segmentInfos.size();
2574 for(int i=0; i < segCount; ++i) {
2575 SegmentInfo* curSegment = segmentInfos[i];
2576 bool isTextSeg = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
2577 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2578 const int sectionCount = sectionInfos.size();
2579 for(int j=0; j < sectionCount; ++j) {
2580 SectionInfo* curSection = sectionInfos[j];
2581 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2582 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
2583 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
2584 if ( ! curSection->fAllZeroFill ) {
2585 const int atomCount = sectionAtoms.size();
2586 end = curSection->fFileOffset;
2587 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
2588 for (int k=0; k < atomCount; ++k) {
2589 ObjectFile::Atom* atom = sectionAtoms[k];
2590 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
2591 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) ) {
2592 uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
2593 if ( offset != end ) {
2595 // fill gaps with no-ops
2596 writeNoOps(end, offset);
2600 if ( (offset-end) == 4 ) {
2602 ::pwrite(fFileDescriptor, &zero, 4, end);
2605 uint8_t zero = 0x00;
2606 for (uint32_t p=end; p < offset; ++p)
2607 ::pwrite(fFileDescriptor, &zero, 1, p);
2611 uint64_t atomSize = atom->getSize();
2612 if ( atomSize > fLargestAtomSize ) {
2613 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
2614 atom->getDisplayName(), atomSize, fLargestAtomSize);
2616 end = offset+atomSize;
2618 atom->copyRawContent(buffer);
2619 // apply any fix-ups
2621 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2622 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
2623 ObjectFile::Reference* ref = *it;
2624 if ( fOptions.outputKind() == Options::kObjectFile ) {
2626 // skip fix-ups for undefined targets
2627 if ( &(ref->getTarget()) != NULL )
2628 this->fixUpReferenceRelocatable(ref, atom, buffer);
2631 // producing final linked image
2632 this->fixUpReferenceFinal(ref, atom, buffer);
2636 catch (const char* msg) {
2637 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
2639 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
2640 // offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
2642 ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
2649 close(fFileDescriptor);
2655 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2657 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2658 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2659 int64_t displacement;
2660 switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
2662 case x86::kFollowOn:
2665 case x86::kPointerWeakImport:
2668 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
2669 // external realocation ==> pointer contains addend
2670 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2673 // pointer contains target address
2674 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2675 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2679 case x86::kPointerDiff:
2680 LittleEndian::set32(*fixUp,
2681 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2683 case x86::kPCRel32WeakImport:
2686 switch ( ref->getTarget().getDefinitionKind() ) {
2687 case ObjectFile::Atom::kRegularDefinition:
2688 case ObjectFile::Atom::kWeakDefinition:
2689 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2691 case ObjectFile::Atom::kExternalDefinition:
2692 case ObjectFile::Atom::kExternalWeakDefinition:
2693 throw "codegen problem, can't use rel32 to external symbol";
2694 case ObjectFile::Atom::kTentativeDefinition:
2698 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2699 //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());
2700 throw "rel32 out of range";
2702 LittleEndian::set32(*fixUp, (int32_t)displacement);
2704 case x86::kAbsolute32:
2705 switch ( ref->getTarget().getDefinitionKind() ) {
2706 case ObjectFile::Atom::kRegularDefinition:
2707 case ObjectFile::Atom::kWeakDefinition:
2708 case ObjectFile::Atom::kTentativeDefinition:
2709 // pointer contains target address
2710 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2712 case ObjectFile::Atom::kExternalDefinition:
2713 case ObjectFile::Atom::kExternalWeakDefinition:
2714 // external realocation ==> pointer contains addend
2715 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2723 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2725 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2726 bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2727 && shouldExport(ref->getTarget()) );
2728 switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
2730 case x86::kFollowOn:
2734 case x86::kPointerWeakImport:
2735 case x86::kAbsolute32:
2738 // external realocation ==> pointer contains addend
2739 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2742 // internal relocation
2743 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
2744 // pointer contains target address
2745 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2748 // pointer contains addend
2749 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2754 case x86::kPointerDiff:
2755 LittleEndian::set32(*fixUp,
2756 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2759 case x86::kPCRel32WeakImport:
2760 int64_t displacement = 0;
2762 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2764 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2765 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2766 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2767 //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());
2768 throw "rel32 out of range";
2770 LittleEndian::set32(*fixUp, (int32_t)displacement);
2776 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2778 const int64_t twoGigLimit = 0x7FFFFFFF;
2779 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
2780 int64_t displacement = 0;
2781 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
2782 case x86_64::kNoFixUp:
2783 case x86_64::kFollowOn:
2786 case x86_64::kPointerWeakImport:
2787 case x86_64::kPointer:
2789 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
2790 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
2791 // external realocation ==> pointer contains addend
2792 LittleEndian::set64(*fixUp, ref->getTargetOffset());
2795 // internal relocation
2796 // pointer contains target address
2797 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2798 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2802 case x86_64::kPointerDiff32:
2803 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
2804 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
2805 throw "32-bit pointer difference out of range";
2806 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
2808 case x86_64::kPointerDiff:
2809 LittleEndian::set64(*fixUp,
2810 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2812 case x86_64::kBranchPCRel32WeakImport:
2813 case x86_64::kBranchPCRel32:
2814 case x86_64::kPCRel32:
2815 case x86_64::kPCRel32_1:
2816 case x86_64::kPCRel32_2:
2817 case x86_64::kPCRel32_4:
2818 case x86_64::kPCRel32GOT:
2819 case x86_64::kPCRel32GOTWeakImport:
2820 case x86_64::kPCRel32GOTLoad:
2821 case x86_64::kPCRel32GOTLoadWeakImport:
2822 switch ( ref->getTarget().getDefinitionKind() ) {
2823 case ObjectFile::Atom::kRegularDefinition:
2824 case ObjectFile::Atom::kWeakDefinition:
2825 case ObjectFile::Atom::kTentativeDefinition:
2826 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2828 case ObjectFile::Atom::kExternalDefinition:
2829 case ObjectFile::Atom::kExternalWeakDefinition:
2830 throw "codegen problem, can't use rel32 to external symbol";
2833 switch ( ref->getKind() ) {
2834 case x86_64::kPCRel32_1:
2837 case x86_64::kPCRel32_2:
2840 case x86_64::kPCRel32_4:
2844 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
2845 //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());
2846 throw "rel32 out of range";
2848 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
2854 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2856 const int64_t twoGigLimit = 0x7FFFFFFF;
2857 bool external = (ref->getTarget().getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2858 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
2859 int64_t displacement = 0;
2861 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
2862 case x86_64::kNoFixUp:
2863 case x86_64::kFollowOn:
2866 case x86_64::kPointer:
2867 case x86_64::kPointerWeakImport:
2870 // external realocation ==> pointer contains addend
2871 LittleEndian::set64(*fixUp, ref->getTargetOffset());
2874 // internal relocation ==> pointer contains target address
2875 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2879 case x86_64::kPointerDiff32:
2880 // addend in content
2881 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
2883 case x86_64::kPointerDiff:
2884 // addend in content
2885 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
2887 case x86_64::kBranchPCRel32:
2888 case x86_64::kBranchPCRel32WeakImport:
2889 case x86_64::kPCRel32:
2890 case x86_64::kPCRel32_1:
2891 case x86_64::kPCRel32_2:
2892 case x86_64::kPCRel32_4:
2893 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
2894 temp32 = ref->getTargetOffset();
2896 // extern relocation contains addend
2897 displacement = temp32;
2900 // internal relocations contain delta to target address
2901 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2903 switch ( ref->getKind() ) {
2904 case x86_64::kPCRel32_1:
2907 case x86_64::kPCRel32_2:
2910 case x86_64::kPCRel32_4:
2914 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
2915 //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());
2916 throw "rel32 out of range";
2918 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
2920 case x86_64::kPCRel32GOT:
2921 case x86_64::kPCRel32GOTLoad:
2922 case x86_64::kPCRel32GOTWeakImport:
2923 case x86_64::kPCRel32GOTLoadWeakImport:
2924 // contains addend (usually zero)
2925 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
2931 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2933 fixUpReference_powerpc(ref, inAtom, buffer, true);
2937 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2939 fixUpReference_powerpc(ref, inAtom, buffer, true);
2943 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2945 fixUpReference_powerpc(ref, inAtom, buffer, false);
2949 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2951 fixUpReference_powerpc(ref, inAtom, buffer, false);
2955 // ppc and ppc64 are mostly the same, so they share a template specialzation
2957 template <typename A>
2958 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
2960 uint32_t instruction;
2961 uint32_t newInstruction;
2962 int64_t displacement;
2963 uint64_t targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
2964 uint64_t picBaseAddr;
2965 uint16_t instructionLowHalf;
2966 uint16_t instructionHighHalf;
2967 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2968 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
2969 bool relocateableExternal;
2971 if ( finalLinkedImage )
2972 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
2974 relocateableExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2975 && shouldExport(ref->getTarget()) );
2977 const int64_t picbase_twoGigLimit = 0x80000000;
2979 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
2984 case A::kPointerWeakImport:
2987 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
2988 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
2989 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
2990 if ( fDyldHelper == NULL )
2991 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2992 P::setP(*fixUpPointer, fDyldHelper->getAddress());
2994 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
2995 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
2996 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
2997 P::setP(*fixUpPointer, targetAddr);
2999 P::setP(*fixUpPointer, 0);
3001 else if ( relocateableExternal ) {
3002 // external realocation ==> pointer contains addend
3003 P::setP(*fixUpPointer, ref->getTargetOffset());
3006 // internal relocation
3007 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
3008 // pointer contains target address
3009 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
3010 P::setP(*fixUpPointer, targetAddr);
3013 // pointer contains addend
3014 P::setP(*fixUpPointer, ref->getTargetOffset());
3019 case A::kPointerDiff64:
3020 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
3022 case A::kPointerDiff32:
3023 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
3025 case A::kBranch24WeakImport:
3028 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
3029 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
3030 if ( relocateableExternal ) {
3031 // doing "ld -r" to an external symbol
3032 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
3033 displacement -= ref->getTarget().getAddress();
3036 const int64_t bl_eightMegLimit = 0x00FFFFFF;
3037 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
3038 //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());
3039 throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s",
3040 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
3041 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
3044 instruction = BigEndian::get32(*fixUp);
3045 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
3046 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
3047 BigEndian::set32(*fixUp, newInstruction);
3052 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
3053 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
3054 if ( relocateableExternal ) {
3055 // doing "ld -r" to an external symbol
3056 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
3057 displacement -= ref->getTarget().getAddress();
3060 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
3061 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
3062 //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());
3063 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
3064 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
3065 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
3068 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
3069 instruction = BigEndian::get32(*fixUp);
3070 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
3071 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
3072 BigEndian::set32(*fixUp, newInstruction);
3075 case A::kPICBaseLow16:
3076 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
3077 displacement = targetAddr - picBaseAddr;
3078 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
3079 throw "32-bit pic-base out of range";
3080 instructionLowHalf = (displacement & 0xFFFF);
3081 instruction = BigEndian::get32(*fixUp);
3082 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
3083 BigEndian::set32(*fixUp, newInstruction);
3085 case A::kPICBaseLow14:
3086 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
3087 displacement = targetAddr - picBaseAddr;
3088 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
3089 throw "32-bit pic-base out of range";
3090 if ( (displacement & 0x3) != 0 )
3091 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
3092 instructionLowHalf = (displacement & 0xFFFC);
3093 instruction = BigEndian::get32(*fixUp);
3094 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
3095 BigEndian::set32(*fixUp, newInstruction);
3097 case A::kPICBaseHigh16:
3098 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
3099 displacement = targetAddr - picBaseAddr;
3100 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
3101 throw "32-bit pic-base out of range";
3102 instructionLowHalf = displacement >> 16;
3103 if ( (displacement & 0x00008000) != 0 )
3104 ++instructionLowHalf;
3105 instruction = BigEndian::get32(*fixUp);
3106 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
3107 BigEndian::set32(*fixUp, newInstruction);
3110 if ( relocateableExternal )
3111 targetAddr -= ref->getTarget().getAddress();
3112 instructionLowHalf = (targetAddr & 0xFFFF);
3113 instruction = BigEndian::get32(*fixUp);
3114 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
3115 BigEndian::set32(*fixUp, newInstruction);
3118 if ( relocateableExternal )
3119 targetAddr -= ref->getTarget().getAddress();
3120 if ( (targetAddr & 0x3) != 0 )
3121 throw "bad address for absolute lo14 instruction fix-up";
3122 instructionLowHalf = (targetAddr & 0xFFFF);
3123 instruction = BigEndian::get32(*fixUp);
3124 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
3125 BigEndian::set32(*fixUp, newInstruction);
3128 if ( relocateableExternal )
3129 targetAddr -= ref->getTarget().getAddress();
3130 instructionHighHalf = (targetAddr >> 16);
3131 instruction = BigEndian::get32(*fixUp);
3132 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
3133 BigEndian::set32(*fixUp, newInstruction);
3135 case A::kAbsHigh16AddLow:
3136 if ( relocateableExternal )
3137 targetAddr -= ref->getTarget().getAddress();
3138 if ( targetAddr & 0x00008000 )
3139 targetAddr += 0x00010000;
3140 instruction = BigEndian::get32(*fixUp);
3141 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
3142 BigEndian::set32(*fixUp, newInstruction);
3148 bool Writer<ppc>::stubableReferenceKind(uint8_t kind)
3150 return (kind == ppc::kBranch24 || kind == ppc::kBranch24WeakImport);
3154 bool Writer<ppc64>::stubableReferenceKind(uint8_t kind)
3156 return (kind == ppc64::kBranch24 || kind == ppc64::kBranch24WeakImport);
3160 bool Writer<x86>::stubableReferenceKind(uint8_t kind)
3162 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
3166 bool Writer<x86_64>::stubableReferenceKind(uint8_t kind)
3168 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
3172 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
3174 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
3178 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
3180 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
3184 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
3186 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
3190 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
3193 case x86_64::kPointerWeakImport:
3194 case x86_64::kBranchPCRel32WeakImport:
3195 case x86_64::kPCRel32GOTWeakImport:
3196 case x86_64::kPCRel32GOTLoadWeakImport:
3204 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
3210 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
3216 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
3222 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
3225 case x86_64::kPCRel32GOT:
3226 case x86_64::kPCRel32GOTWeakImport:
3227 case x86_64::kPCRel32GOTLoad:
3228 case x86_64::kPCRel32GOTLoadWeakImport:
3234 template <typename A>
3235 void Writer<A>::scanForAbsoluteReferences()
3240 // for ppc64 look for any -mdynamic-no-pic codegen
3242 void Writer<ppc64>::scanForAbsoluteReferences()
3244 // only do this for main executable
3245 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
3246 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3247 ObjectFile::Atom* atom = *it;
3248 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3249 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3250 ObjectFile::Reference* ref = *rit;
3251 switch (ref->getKind()) {
3252 case ppc64::kAbsLow16:
3253 case ppc64::kAbsLow14:
3254 case ppc64::kAbsHigh16:
3255 case ppc64::kAbsHigh16AddLow:
3256 //fprintf(stderr, "found -mdyanmic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
3257 // shrink page-zero and add pad segment to compensate
3258 fPadSegmentInfo = new SegmentInfo();
3259 strcpy(fPadSegmentInfo->fName, "__4BGFILL");
3260 fPageZeroAtom->setSize(0x1000);
3269 template <typename A>
3270 void Writer<A>::synthesizeStubs()
3272 switch ( fOptions.outputKind() ) {
3273 case Options::kStaticExecutable:
3274 case Options::kObjectFile:
3275 // these output kinds never have stubs
3277 case Options::kDyld:
3278 case Options::kDynamicLibrary:
3279 case Options::kDynamicBundle:
3280 case Options::kDynamicExecutable:
3281 // try to synthesize stubs for these
3285 // walk every atom and reference
3286 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3287 ObjectFile::Atom* atom = *it;
3288 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3289 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3290 ObjectFile::Reference* ref = *rit;
3291 ObjectFile::Atom& target = ref->getTarget();
3292 // build map of which symbols need weak importing
3293 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3294 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
3295 bool weakImport = this->weakImportReferenceKind(ref->getKind());
3296 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
3297 if ( pos == fWeakImportMap.end() ) {
3298 // target not in fWeakImportMap, so add
3299 fWeakImportMap[&target] = weakImport;
3302 // target in fWeakImportMap, check for weakness mismatch
3303 if ( pos->second != weakImport ) {
3305 switch ( fOptions.weakReferenceMismatchTreatment() ) {
3306 case Options::kWeakReferenceMismatchError:
3307 throwf("mismatching weak references for symbol: %s", target.getName());
3308 case Options::kWeakReferenceMismatchWeak:
3311 case Options::kWeakReferenceMismatchNonWeak:
3312 pos->second = false;
3318 // create stubs as needed
3319 if ( this->stubableReferenceKind(ref->getKind())
3320 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
3321 ObjectFile::Atom* stub = NULL;
3322 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
3323 if ( pos == fStubsMap.end() ) {
3324 stub = new StubAtom<A>(*this, target);
3325 fStubsMap[&target] = stub;
3330 // alter reference to use stub instead
3331 ref->setTarget(*stub, 0);
3333 // create GOT slots (non-lazy pointers) as needed
3334 else if ( this->GOTReferenceKind(ref->getKind()) ) {
3335 ObjectFile::Atom* nlp = NULL;
3336 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
3337 if ( pos == fGOTMap.end() ) {
3338 nlp = new NonLazyPointerAtom<A>(*this, target);
3339 fGOTMap[&target] = nlp;
3344 // alter reference to use non lazy pointer instead
3345 ref->setTarget(*nlp, ref->getTargetOffset());
3352 // sort lazy pointers
3354 // add stubs to fAllAtoms
3355 if ( fAllSynthesizedStubs.size() != 0 ) {
3356 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
3357 std::vector<ObjectFile::Atom*> mergedStubs;
3358 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
3359 // when we have stubs and helpers, insert both into fAllAtoms
3360 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
3361 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
3362 stubs = &mergedStubs;
3364 ObjectFile::Section* curSection = NULL;
3365 ObjectFile::Atom* prevAtom = NULL;
3366 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3367 ObjectFile::Atom* atom = *it;
3368 ObjectFile::Section* nextSection = atom->getSection();
3369 if ( nextSection != curSection ) {
3370 // HACK HACK for i386 where stubs are not in _TEXT segment
3371 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
3372 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
3373 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
3374 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
3375 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
3380 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
3381 // found end of __text section, insert stubs here
3382 fAllAtoms->insert(it, stubs->begin(), stubs->end());
3386 curSection = nextSection;
3393 // add lazy pointers to fAllAtoms
3394 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
3395 ObjectFile::Section* curSection = NULL;
3396 ObjectFile::Atom* prevAtom = NULL;
3397 bool inserted = false;
3398 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3399 ObjectFile::Atom* atom = *it;
3400 ObjectFile::Section* nextSection = atom->getSection();
3401 if ( nextSection != curSection ) {
3402 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
3403 // found end of __dyld section, insert lazy pointers here
3404 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
3408 curSection = nextSection;
3413 throw "can't insert lazy pointers, __dyld section not found";
3417 // add non-lazy pointers to fAllAtoms
3418 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
3419 ObjectFile::Section* curSection = NULL;
3420 ObjectFile::Atom* prevAtom = NULL;
3421 bool inserted = false;
3422 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3423 ObjectFile::Atom* atom = *it;
3424 ObjectFile::Section* nextSection = atom->getSection();
3425 if ( nextSection != curSection ) {
3426 if ( (prevAtom != NULL)
3427 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
3428 || ((fOptions.outputKind() == Options::kDyld) && (strcmp(prevAtom->getSectionName(), "__data") == 0))) ) {
3429 // found end of __dyld section, insert lazy pointers here
3430 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
3434 curSection = nextSection;
3439 throw "can't insert non-lazy pointers, __dyld section not found";
3445 template <typename A>
3446 void Writer<A>::partitionIntoSections()
3448 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
3450 // for every atom, set its sectionInfo object and section offset
3451 // build up fSegmentInfos along the way
3452 ObjectFile::Section* curSection = NULL;
3453 SectionInfo* currentSectionInfo = NULL;
3454 SegmentInfo* currentSegmentInfo = NULL;
3455 unsigned int sectionIndex = 1;
3456 fSegmentInfos.reserve(8);
3457 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
3458 ObjectFile::Atom* atom = (*fAllAtoms)[i];
3459 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
3460 if ( oneSegmentCommand ) {
3461 if ( currentSegmentInfo == NULL ) {
3462 currentSegmentInfo = new SegmentInfo();
3463 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
3464 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
3465 this->fSegmentInfos.push_back(currentSegmentInfo);
3467 currentSectionInfo = new SectionInfo();
3468 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
3469 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
3470 currentSectionInfo->fAlignment = atom->getAlignment();
3471 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
3472 currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') ||
3473 (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) && !fOptions.makeTentativeDefinitionsReal() );
3474 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
3475 currentSectionInfo->setIndex(sectionIndex++);
3476 currentSegmentInfo->fSections.push_back(currentSectionInfo);
3479 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
3480 currentSegmentInfo = new SegmentInfo();
3481 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
3482 uint32_t initprot = 0;
3483 if ( atom->getSegment().isContentReadable() )
3484 initprot |= VM_PROT_READ;
3485 if ( atom->getSegment().isContentWritable() )
3486 initprot |= VM_PROT_WRITE;
3487 if ( atom->getSegment().isContentExecutable() )
3488 initprot |= VM_PROT_EXECUTE;
3489 currentSegmentInfo->fInitProtection = initprot;
3490 if ( initprot == 0 )
3491 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
3493 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
3494 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
3495 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
3496 this->fSegmentInfos.push_back(currentSegmentInfo);
3498 currentSectionInfo = new SectionInfo();
3499 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
3500 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
3501 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
3502 currentSectionInfo->fAlignment = atom->getAlignment();
3503 // check for -sectalign override
3504 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
3505 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
3506 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
3507 currentSectionInfo->fAlignment = it->alignment;
3509 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
3510 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
3511 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
3512 currentSectionInfo->setIndex(sectionIndex++);
3513 currentSegmentInfo->fSections.push_back(currentSectionInfo);
3515 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
3516 fLoadCommandsSection = currentSectionInfo;
3517 fLoadCommandsSegment = currentSegmentInfo;
3519 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
3520 currentSectionInfo->fAllLazyPointers = true;
3521 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
3522 currentSectionInfo->fAllLazyPointers = true;
3523 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
3524 currentSectionInfo->fAllNonLazyPointers = true;
3525 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
3526 currentSectionInfo->fAllNonLazyPointers = true;
3527 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
3528 currentSectionInfo->fAllStubs = true;
3529 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
3530 currentSectionInfo->fAllStubs = true;
3531 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
3532 currentSectionInfo->fAllStubs = true;
3533 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
3534 currentSectionInfo->fAllStubs = true;
3535 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) )
3536 currentSectionInfo->fAllSelfModifyingStubs = true;
3537 curSection = atom->getSection();
3539 // any non-zero fill atoms make whole section marked not-zero-fill
3540 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
3541 currentSectionInfo->fAllZeroFill = false;
3542 // change section object to be Writer's SectionInfo object
3543 atom->setSection(currentSectionInfo);
3544 // section alignment is that of a contained atom with the greatest alignment
3545 uint8_t atomAlign = atom->getAlignment();
3546 if ( currentSectionInfo->fAlignment < atomAlign )
3547 currentSectionInfo->fAlignment = atomAlign;
3548 // calculate section offset for this atom
3549 uint64_t offset = currentSectionInfo->fSize;
3550 uint64_t alignment = 1 << atomAlign;
3551 offset = ( (offset+alignment-1) & (-alignment) );
3552 atom->setSectionOffset(offset);
3553 uint64_t curAtomSize = atom->getSize();
3554 currentSectionInfo->fSize = offset + curAtomSize;
3555 // add atom to section vector
3556 currentSectionInfo->fAtoms.push_back(atom);
3557 // update largest size
3558 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
3559 fLargestAtomSize = curAtomSize;
3564 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
3565 class TargetAndOffsetComparor
3568 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
3570 if ( left.atom != right.atom )
3571 return ( left.atom < right.atom );
3572 return ( left.offset < right.offset );
3577 bool Writer<ppc>::addBranchIslands()
3579 return this->addPPCBranchIslands();
3583 bool Writer<ppc64>::addBranchIslands()
3585 return this->addPPCBranchIslands();
3589 bool Writer<x86>::addBranchIslands()
3591 // x86 branches can reach entire 4G address space, so no need for branch islands
3596 bool Writer<x86_64>::addBranchIslands()
3598 // x86 branches can reach entire 4G size of largest image
3603 inline uint8_t Writer<ppc>::branch24Reference()
3605 return ppc::kBranch24;
3609 inline uint8_t Writer<ppc64>::branch24Reference()
3611 return ppc64::kBranch24;
3615 // PowerPC can do PC relative branches as far as +/-16MB.
3616 // If a branch target is >16MB then we insert one or more
3617 // "branch islands" between the branch and its target that
3618 // allows island hoping to the target.
3620 // Branch Island Algorithm
3622 // If the __TEXT segment < 16MB, then no branch islands needed
3623 // Otherwise, every 15MB into the __TEXT segment is region is
3624 // added which can contain branch islands. Every out of range
3625 // bl instruction is checked. If it crosses a region, an island
3626 // is added to that region with the same target and the bl is
3627 // adjusted to target the island instead.
3629 // In theory, if too many islands are added to one region, it
3630 // could grow the __TEXT enough that other previously in-range
3631 // bl branches could be pushed out of range. We reduce the
3632 // probability this could happen by placing the ranges every
3633 // 15MB which means the region would have to be 1MB (256K islands)
3634 // before any branches could be pushed out of range.
3636 template <typename A>
3637 bool Writer<A>::addPPCBranchIslands()
3639 bool result = false;
3640 // Can only possibly need branch islands if __TEXT segment > 16M
3641 if ( fLoadCommandsSegment->fSize > 16000000 ) {
3642 //fprintf(stderr, "ld64: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
3643 const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
3644 SectionInfo* textSection = NULL;
3645 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
3646 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
3648 //fprintf(stderr, "ld64: checking for branch islands, __text section size=%llu\n", textSection->fSize);
3652 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
3653 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
3654 AtomToIsland regionsMap[kIslandRegionsCount];
3655 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
3656 unsigned int islandCount = 0;
3658 // create islands for branch references that are out of range
3659 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3660 ObjectFile::Atom* atom = *it;
3661 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3662 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3663 ObjectFile::Reference* ref = *rit;
3664 if ( ref->getKind() == this->branch24Reference() ) {
3665 ObjectFile::Atom& target = ref->getTarget();
3666 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
3667 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
3668 int64_t displacement = dstAddr - srcAddr;
3669 const int64_t kFifteenMegLimit = kBetweenRegions;
3670 if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
3671 for (int i=0; i < kIslandRegionsCount; ++i) {
3672 AtomToIsland* region=®ionsMap[i];
3673 int64_t islandRegionAddr = kBetweenRegions * (i+1);
3674 if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
3675 ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
3676 TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
3677 AtomToIsland::iterator pos = region->find(islandTarget);
3678 if ( pos == region->end() ) {
3679 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
3680 island->setSection(textSection);
3681 (*region)[islandTarget] = island;
3682 regionsIslands[i].push_back(island);
3684 ref->setTarget(*island, 0);
3687 ref->setTarget(*(pos->second), 0);
3696 // insert islands into __text section and adjust section offsets
3697 if ( islandCount > 0 ) {
3698 //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
3699 std::vector<ObjectFile::Atom*> newAtomList;
3700 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
3701 uint64_t islandRegionAddr = kBetweenRegions;
3702 int regionIndex = 0;
3703 uint64_t sectionOffset = 0;
3704 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
3705 ObjectFile::Atom* atom = *it;
3706 newAtomList.push_back(atom);
3707 if ( atom->getAddress() > islandRegionAddr ) {
3708 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
3709 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3710 ObjectFile::Atom* islandAtom = *rit;
3711 newAtomList.push_back(islandAtom);
3712 uint64_t alignment = 1 << (islandAtom->getAlignment());
3713 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3714 islandAtom->setSectionOffset(sectionOffset);
3715 sectionOffset += islandAtom->getSize();
3718 islandRegionAddr += kBetweenRegions;
3720 uint64_t alignment = 1 << (atom->getAlignment());
3721 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3722 atom->setSectionOffset(sectionOffset);
3723 sectionOffset += atom->getSize();
3725 // put any remaining islands at end of __text section
3726 if ( regionIndex < kIslandRegionsCount ) {
3727 sectionOffset = textSection->fSize;
3728 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
3729 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3730 ObjectFile::Atom* islandAtom = *rit;
3731 newAtomList.push_back(islandAtom);
3732 uint64_t alignment = 1 << (islandAtom->getAlignment());
3733 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3734 islandAtom->setSectionOffset(sectionOffset);
3735 sectionOffset += islandAtom->getSize();
3739 textSection->fAtoms = newAtomList;
3740 textSection->fSize = sectionOffset;
3749 template <typename A>
3750 void Writer<A>::adjustLoadCommandsAndPadding()
3752 fSegmentCommands->computeSize();
3754 // recompute load command section offsets
3755 uint64_t offset = 0;
3756 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
3757 const unsigned int atomCount = loadCommandAtoms.size();
3758 for (unsigned int i=0; i < atomCount; ++i) {
3759 ObjectFile::Atom* atom = loadCommandAtoms[i];
3760 uint64_t alignment = 1 << atom->getAlignment();
3761 offset = ( (offset+alignment-1) & (-alignment) );
3762 atom->setSectionOffset(offset);
3763 uint32_t atomSize = atom->getSize();
3764 if ( atomSize > fLargestAtomSize )
3765 fLargestAtomSize = atomSize;
3767 fLoadCommandsSection->fSize = offset;
3770 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
3771 const int sectionCount = sectionInfos.size();
3772 uint64_t paddingSize = 0;
3773 if ( fOptions.outputKind() == Options::kDyld ) {
3774 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
3775 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
3776 for(int j=0; j < sectionCount; ++j) {
3777 SectionInfo* curSection = sectionInfos[j];
3778 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
3779 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3782 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
3784 else if ( fOptions.outputKind() == Options::kObjectFile ) {
3785 // mach-o .o files need no padding between load commands and first section
3789 // calculate max padding to keep segment size same, but all free space at end of load commands
3790 uint64_t totalSize = 0;
3791 uint64_t worstCaseAlignmentPadding = 0;
3792 for(int j=0; j < sectionCount; ++j) {
3793 SectionInfo* curSection = sectionInfos[j];
3794 totalSize += curSection->fSize;
3795 if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
3796 worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
3798 uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
3799 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
3800 paddingSize = segmentSize - (totalSize+worstCaseAlignmentPadding);
3802 // if command line requires more padding than this
3803 if ( paddingSize < fOptions.minimumHeaderPad() ) {
3804 int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
3805 paddingSize += extraPages * 4096;
3809 // adjust atom size and update section size
3810 fHeaderPadding->setSize(paddingSize);
3811 for(int j=0; j < sectionCount; ++j) {
3812 SectionInfo* curSection = sectionInfos[j];
3813 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3814 curSection->fSize = paddingSize;
3818 // assign file offsets and logical address to all segments
3819 template <typename A>
3820 void Writer<A>::assignFileOffsets()
3822 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
3823 bool haveFixedSegments = false;
3824 uint64_t fileOffset = 0;
3825 uint64_t nextContiguousAddress = fOptions.baseAddress();
3827 // Run through the segments and each segment's sections to assign addresses
3828 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3829 SegmentInfo* curSegment = *segit;
3831 fileOffset = (fileOffset+4095) & (-4096);
3832 curSegment->fFileOffset = fileOffset;
3834 // Set the segment base address
3835 if ( curSegment->fFixedAddress )
3836 haveFixedSegments = true;
3838 curSegment->fBaseAddress = nextContiguousAddress;
3840 // We've set the segment address, now run through each section.
3841 uint64_t address = curSegment->fBaseAddress;
3842 SectionInfo* firstZeroFillSection = NULL;
3843 SectionInfo* prevSection = NULL;
3845 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3847 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
3848 SectionInfo* curSection = *it;
3850 // adjust section address based on alignment
3851 uint64_t alignment = 1 << curSection->fAlignment;
3852 address = ( (address+alignment-1) & (-alignment) );
3854 // adjust file offset to match address
3855 if ( prevSection != NULL ) {
3856 if ( finalLinkedImage || !prevSection->fVirtualSection )
3857 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
3859 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
3862 // update section info
3863 curSection->fFileOffset = fileOffset;
3864 curSection->setBaseAddress(address);
3866 // keep track of trailing zero fill sections
3867 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
3868 firstZeroFillSection = curSection;
3869 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
3870 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
3872 // update running pointers
3873 if ( finalLinkedImage || !curSection->fVirtualSection )
3874 address += curSection->fSize;
3875 fileOffset += curSection->fSize;
3877 // update segment info
3878 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
3879 curSegment->fSize = curSegment->fFileSize;
3880 prevSection = curSection;
3883 if ( fOptions.outputKind() == Options::kObjectFile ) {
3884 // don't page align .o files
3887 // optimize trailing zero-fill sections to not occupy disk space
3888 if ( firstZeroFillSection != NULL ) {
3889 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
3890 fileOffset = firstZeroFillSection->fFileOffset;
3892 // page align segment size
3893 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
3894 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
3895 if ( curSegment->fBaseAddress == nextContiguousAddress )
3896 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
3900 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
3901 if ( haveFixedSegments ) {
3902 int segCount = fSegmentInfos.size();
3903 for(int i=0; i < segCount; ++i) {
3904 SegmentInfo* segment1 = fSegmentInfos[i];
3906 for(int j=0; j < segCount; ++j) {
3908 SegmentInfo* segment2 = fSegmentInfos[j];
3910 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
3911 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
3912 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3913 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3915 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
3916 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
3917 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3918 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3920 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
3921 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3922 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3929 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
3930 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3931 SegmentInfo* curSegment = *segit;
3932 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
3933 if ( fFirstWritableSegment == NULL )
3934 fFirstWritableSegment = curSegment;
3935 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
3936 fWritableSegmentPastFirst4GB = true;
3942 template <typename A>
3943 void Writer<A>::adjustLinkEditSections()
3945 // link edit content is always in last segment
3946 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
3947 unsigned int firstLinkEditSectionIndex = 0;
3948 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
3949 ++firstLinkEditSectionIndex;
3951 const unsigned int sectionCount = lastSeg->fSections.size();
3952 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
3953 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
3954 if ( fPadSegmentInfo != NULL ) {
3955 // insert __4GBFILL segment into segments vector before LINKEDIT
3956 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
3957 if ( *it == lastSeg ) {
3958 fSegmentInfos.insert(it, fPadSegmentInfo);
3962 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
3963 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
3964 fPadSegmentInfo->fBaseAddress = address;
3965 // adjust LINKEDIT to start at zeroPageSize
3966 address = fOptions.zeroPageSize();
3967 lastSeg->fBaseAddress = fOptions.zeroPageSize();
3969 for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
3970 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
3971 const unsigned int atomCount = atoms.size();
3972 uint64_t sectionOffset = 0;
3973 lastSeg->fSections[i]->fFileOffset = fileOffset;
3974 lastSeg->fSections[i]->setBaseAddress(address);
3975 for (unsigned int j=0; j < atomCount; ++j) {
3976 ObjectFile::Atom* atom = atoms[j];
3977 uint64_t alignment = 1 << atom->getAlignment();
3978 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3979 atom->setSectionOffset(sectionOffset);
3980 uint64_t size = atom->getSize();
3981 sectionOffset += size;
3982 if ( size > fLargestAtomSize )
3983 fLargestAtomSize = size;
3985 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
3986 lastSeg->fSections[i]->fSize = sectionOffset;
3987 fileOffset += sectionOffset;
3988 address += sectionOffset;
3990 if ( fOptions.outputKind() == Options::kObjectFile ) {
3991 //lastSeg->fBaseAddress = 0;
3992 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
3993 //lastSeg->fFileOffset = 0;
3994 //lastSeg->fFileSize =
3997 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
3998 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
4003 template <typename A>
4004 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
4006 switch ( fWriter.fOptions.outputKind() ) {
4007 case Options::kDynamicExecutable:
4008 case Options::kStaticExecutable:
4009 return ObjectFile::Atom::scopeGlobal;
4010 case Options::kDynamicLibrary:
4011 case Options::kDynamicBundle:
4012 case Options::kDyld:
4013 case Options::kObjectFile:
4014 return ObjectFile::Atom::scopeLinkageUnit;
4016 throw "unknown header type";
4019 template <typename A>
4020 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
4022 switch ( fWriter.fOptions.outputKind() ) {
4023 case Options::kDynamicExecutable:
4024 case Options::kStaticExecutable:
4025 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
4026 case Options::kDynamicLibrary:
4027 case Options::kDynamicBundle:
4028 case Options::kDyld:
4029 return ObjectFile::Atom::kSymbolTableIn;
4030 case Options::kObjectFile:
4031 return ObjectFile::Atom::kSymbolTableNotIn;
4033 throw "unknown header type";
4036 template <typename A>
4037 const char* MachHeaderAtom<A>::getName() const
4039 switch ( fWriter.fOptions.outputKind() ) {
4040 case Options::kDynamicExecutable:
4041 case Options::kStaticExecutable:
4042 return "__mh_execute_header";
4043 case Options::kDynamicLibrary:
4044 return "__mh_dylib_header";
4045 case Options::kDynamicBundle:
4046 return "__mh_bundle_header";
4047 case Options::kObjectFile:
4049 case Options::kDyld:
4050 return "__mh_dylinker_header";
4052 throw "unknown header type";
4055 template <typename A>
4056 const char* MachHeaderAtom<A>::getDisplayName() const
4058 switch ( fWriter.fOptions.outputKind() ) {
4059 case Options::kDynamicExecutable:
4060 case Options::kStaticExecutable:
4061 case Options::kDynamicLibrary:
4062 case Options::kDynamicBundle:
4063 case Options::kDyld:
4064 return this->getName();
4065 case Options::kObjectFile:
4066 return "mach header";
4068 throw "unknown header type";
4071 template <typename A>
4072 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
4075 uint32_t fileType = 0;
4076 switch ( fWriter.fOptions.outputKind() ) {
4077 case Options::kDynamicExecutable:
4078 case Options::kStaticExecutable:
4079 fileType = MH_EXECUTE;
4081 case Options::kDynamicLibrary:
4082 fileType = MH_DYLIB;
4084 case Options::kDynamicBundle:
4085 fileType = MH_BUNDLE;
4087 case Options::kObjectFile:
4088 fileType = MH_OBJECT;
4090 case Options::kDyld:
4091 fileType = MH_DYLINKER;
4097 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
4098 if ( ! fWriter.fSeenFollowOnReferences )
4099 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
4102 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
4103 flags |= MH_NOUNDEFS;
4106 flags = MH_DYLDLINK;
4107 if ( fWriter.fOptions.bindAtLoad() )
4108 flags |= MH_BINDATLOAD;
4109 switch ( fWriter.fOptions.nameSpace() ) {
4110 case Options::kTwoLevelNameSpace:
4111 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
4113 case Options::kFlatNameSpace:
4115 case Options::kForceFlatNameSpace:
4116 flags |= MH_FORCE_FLAT;
4119 if ( fWriter.fHasWeakExports )
4120 flags |= MH_WEAK_DEFINES;
4121 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
4122 flags |= MH_BINDS_TO_WEAK;
4124 if ( fWriter.fOptions.hasExecutableStack() )
4125 flags |= MH_ALLOW_STACK_EXECUTION;
4128 // get commands info
4129 uint32_t commandsSize = 0;
4130 uint32_t commandsCount = 0;
4132 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
4133 const unsigned int atomCount = loadCommandAtoms.size();
4134 for (unsigned int i=0; i < atomCount; ++i) {
4135 ObjectFile::Atom* atom = loadCommandAtoms[i];
4136 commandsSize += atom->getSize();
4137 // segment and symbol table atoms can contain more than one load command
4138 if ( atom == fWriter.fSegmentCommands )
4139 commandsCount += fWriter.fSegmentCommands->commandCount();
4140 else if ( atom == fWriter.fSymbolTableCommands )
4141 commandsCount += fWriter.fSymbolTableCommands->commandCount();
4142 else if ( atom->getSize() != 0)
4146 // fill out mach_header
4147 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
4149 mh->set_filetype(fileType);
4150 mh->set_ncmds(commandsCount);
4151 mh->set_sizeofcmds(commandsSize);
4152 mh->set_flags(flags);
4156 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
4158 header.set_magic(MH_MAGIC);
4159 header.set_cputype(CPU_TYPE_POWERPC);
4160 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
4164 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
4166 header.set_magic(MH_MAGIC_64);
4167 header.set_cputype(CPU_TYPE_POWERPC64);
4168 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
4169 header.set_reserved(0);
4173 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
4175 header.set_magic(MH_MAGIC);
4176 header.set_cputype(CPU_TYPE_I386);
4177 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
4181 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
4183 header.set_magic(MH_MAGIC_64);
4184 header.set_cputype(CPU_TYPE_X86_64);
4185 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
4188 template <typename A>
4189 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
4190 : WriterAtom<A>(writer, Segment::fgStackSegment)
4192 if ( stackGrowsDown() )
4193 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
4195 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
4200 bool CustomStackAtom<ppc>::stackGrowsDown()
4206 bool CustomStackAtom<ppc64>::stackGrowsDown()
4212 bool CustomStackAtom<x86>::stackGrowsDown()
4218 bool CustomStackAtom<x86_64>::stackGrowsDown()
4223 template <typename A>
4224 void SegmentLoadCommandsAtom<A>::computeSize()
4227 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
4228 const int segCount = segmentInfos.size();
4229 for(int i=0; i < segCount; ++i) {
4230 size += sizeof(macho_segment_command<P>);
4231 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
4232 const int sectionCount = sectionInfos.size();
4233 for(int j=0; j < sectionCount; ++j) {
4234 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
4235 size += sizeof(macho_section<P>);
4239 fCommandCount = segCount;
4240 if ( fWriter.fPadSegmentInfo != NULL ) {
4242 fSize += sizeof(macho_segment_command<P>);
4247 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
4249 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
4253 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
4255 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
4259 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
4261 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
4265 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
4267 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
4271 template <typename A>
4272 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4274 uint64_t size = this->getSize();
4275 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
4276 bzero(buffer, size);
4277 uint8_t* p = buffer;
4278 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
4279 const int segCount = segmentInfos.size();
4280 for(int i=0; i < segCount; ++i) {
4281 SegmentInfo* segInfo = segmentInfos[i];
4282 const int sectionCount = segInfo->fSections.size();
4283 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
4284 cmd->set_cmd(macho_segment_command<P>::CMD);
4285 cmd->set_segname(segInfo->fName);
4286 cmd->set_vmaddr(segInfo->fBaseAddress);
4287 cmd->set_vmsize(segInfo->fSize);
4288 cmd->set_fileoff(segInfo->fFileOffset);
4289 cmd->set_filesize(segInfo->fFileSize);
4290 cmd->set_maxprot(segInfo->fMaxProtection);
4291 cmd->set_initprot(segInfo->fInitProtection);
4292 // add sections array
4293 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
4294 unsigned int sectionsEmitted = 0;
4295 for (int j=0; j < sectionCount; ++j) {
4296 SectionInfo* sectInfo = segInfo->fSections[j];
4297 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
4298 macho_section<P>* sect = §ions[sectionsEmitted++];
4300 // .o file segment does not cover load commands, so recalc at first real section
4301 if ( sectionsEmitted == 1 ) {
4302 cmd->set_vmaddr(sectInfo->getBaseAddress());
4303 cmd->set_fileoff(sectInfo->fFileOffset);
4305 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
4306 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
4308 sect->set_sectname(sectInfo->fSectionName);
4309 sect->set_segname(sectInfo->fSegmentName);
4310 sect->set_addr(sectInfo->getBaseAddress());
4311 sect->set_size(sectInfo->fSize);
4312 sect->set_offset(sectInfo->fFileOffset);
4313 sect->set_align(sectInfo->fAlignment);
4314 if ( sectInfo->fRelocCount != 0 ) {
4315 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
4316 sect->set_nreloc(sectInfo->fRelocCount);
4318 if ( sectInfo->fAllZeroFill ) {
4319 sect->set_flags(S_ZEROFILL);
4320 sect->set_offset(0);
4322 else if ( sectInfo->fAllLazyPointers ) {
4323 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
4324 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4326 else if ( sectInfo->fAllNonLazyPointers ) {
4327 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
4328 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4330 else if ( sectInfo->fAllStubs ) {
4331 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
4332 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4333 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
4335 else if ( sectInfo->fAllSelfModifyingStubs ) {
4336 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
4337 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4338 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
4340 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4341 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
4343 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4344 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
4346 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4347 sect->set_flags(S_COALESCED);
4349 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4350 sect->set_flags(S_COALESCED);
4352 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4353 sect->set_flags(S_COALESCED);
4355 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4356 sect->set_flags(S_INTERPOSING);
4358 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4359 sect->set_flags(S_CSTRING_LITERALS);
4361 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4362 sect->set_flags(S_4BYTE_LITERALS);
4364 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4365 sect->set_flags(S_8BYTE_LITERALS);
4367 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4368 sect->set_flags(S_16BYTE_LITERALS);
4370 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
4371 sect->set_flags(S_LITERAL_POINTERS);
4373 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4374 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
4378 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
4379 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
4380 cmd->set_nsects(sectionsEmitted);
4385 template <typename A>
4386 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
4387 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
4389 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
4390 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
4391 writer.fSymbolTableCommands = this;
4394 template <typename A>
4395 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
4397 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable )
4398 return this->alignedSize(sizeof(macho_symtab_command<P>));
4400 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
4403 template <typename A>
4404 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4406 // build LC_DYSYMTAB command
4407 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
4408 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
4409 symbolTableCmd->set_cmd(LC_SYMTAB);
4410 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
4411 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
4412 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
4413 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
4414 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
4416 // build LC_DYSYMTAB command
4417 if ( fWriter.fOptions.outputKind() != Options::kStaticExecutable ) {
4418 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
4419 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
4420 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
4421 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
4422 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
4423 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
4424 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
4425 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
4426 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
4427 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
4428 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
4429 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
4430 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
4431 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
4432 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
4433 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
4434 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
4439 template <typename A>
4440 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
4442 return (fWriter.fOptions.outputKind() == Options::kStaticExecutable) ? 1 : 2;
4445 template <typename A>
4446 uint64_t DyldLoadCommandsAtom<A>::getSize() const
4448 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
4451 template <typename A>
4452 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4454 uint64_t size = this->getSize();
4455 bzero(buffer, size);
4456 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
4457 if ( fWriter.fOptions.outputKind() == Options::kDyld )
4458 cmd->set_cmd(LC_ID_DYLINKER);
4460 cmd->set_cmd(LC_LOAD_DYLINKER);
4461 cmd->set_cmdsize(this->getSize());
4462 cmd->set_name_offset();
4463 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
4466 template <typename A>
4467 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
4469 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
4472 template <typename A>
4473 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4475 uint64_t size = this->getSize();
4477 bzero(buffer, size);
4478 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
4479 cmd->set_cmd(LC_SUB_CLIENT);
4480 cmd->set_cmdsize(size);
4481 cmd->set_client_offset();
4482 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
4486 template <typename A>
4487 uint64_t DylibLoadCommandsAtom<A>::getSize() const
4489 const char* path = fInfo.reader->getInstallPath();
4490 if ( fInfo.options.fInstallPathOverride != NULL )
4491 path = fInfo.options.fInstallPathOverride;
4492 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
4495 template <typename A>
4496 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4498 uint64_t size = this->getSize();
4499 bzero(buffer, size);
4500 const char* path = fInfo.reader->getInstallPath();
4501 if ( fInfo.options.fInstallPathOverride != NULL )
4502 path = fInfo.options.fInstallPathOverride;
4503 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
4504 if ( fInfo.options.fWeakImport )
4505 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
4507 cmd->set_cmd(LC_LOAD_DYLIB);
4508 cmd->set_cmdsize(this->getSize());
4509 cmd->set_timestamp(fInfo.reader->getTimestamp());
4510 cmd->set_current_version(fInfo.reader->getCurrentVersion());
4511 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
4512 cmd->set_name_offset();
4513 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
4518 template <typename A>
4519 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
4521 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
4524 template <typename A>
4525 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4527 struct timeval currentTime = { 0 , 0 };
4528 gettimeofday(¤tTime, NULL);
4529 time_t timestamp = currentTime.tv_sec;
4530 uint64_t size = this->getSize();
4531 bzero(buffer, size);
4532 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
4533 cmd->set_cmd(LC_ID_DYLIB);
4534 cmd->set_cmdsize(this->getSize());
4535 cmd->set_name_offset();
4536 cmd->set_timestamp(timestamp);
4537 cmd->set_current_version(fWriter.fOptions.currentVersion());
4538 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
4539 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
4543 template <typename A>
4544 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4546 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4547 bzero(buffer, sizeof(macho_routines_command<P>));
4548 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
4549 cmd->set_cmd(macho_routines_command<P>::CMD);
4550 cmd->set_cmdsize(this->getSize());
4551 cmd->set_init_address(initAddr);
4555 template <typename A>
4556 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
4558 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
4561 template <typename A>
4562 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4564 uint64_t size = this->getSize();
4565 bzero(buffer, size);
4566 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
4567 cmd->set_cmd(LC_SUB_UMBRELLA);
4568 cmd->set_cmdsize(this->getSize());
4569 cmd->set_sub_umbrella_offset();
4570 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
4573 template <typename A>
4574 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
4577 uint64_t size = this->getSize();
4578 bzero(buffer, size);
4579 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
4580 cmd->set_cmd(LC_UUID);
4581 cmd->set_cmdsize(this->getSize());
4582 cmd->set_uuid((uint8_t*)fUUID);
4586 template <typename A>
4587 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
4589 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
4592 template <typename A>
4593 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4595 uint64_t size = this->getSize();
4596 bzero(buffer, size);
4597 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
4598 cmd->set_cmd(LC_SUB_LIBRARY);
4599 cmd->set_cmdsize(this->getSize());
4600 cmd->set_sub_library_offset();
4601 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
4602 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
4605 template <typename A>
4606 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
4608 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
4611 template <typename A>
4612 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4614 uint64_t size = this->getSize();
4615 bzero(buffer, size);
4616 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
4617 cmd->set_cmd(LC_SUB_FRAMEWORK);
4618 cmd->set_cmdsize(this->getSize());
4619 cmd->set_umbrella_offset();
4620 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
4624 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
4626 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
4630 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
4632 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
4636 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
4638 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
4642 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
4644 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
4648 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4650 uint64_t size = this->getSize();
4651 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4652 bzero(buffer, size);
4653 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
4654 cmd->set_cmd(LC_UNIXTHREAD);
4655 cmd->set_cmdsize(size);
4656 cmd->set_flavor(1); // PPC_THREAD_STATE
4657 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
4658 cmd->set_thread_register(0, start);
4659 if ( fWriter.fOptions.hasCustomStack() )
4660 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
4665 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4667 uint64_t size = this->getSize();
4668 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4669 bzero(buffer, size);
4670 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
4671 cmd->set_cmd(LC_UNIXTHREAD);
4672 cmd->set_cmdsize(size);
4673 cmd->set_flavor(5); // PPC_THREAD_STATE64
4674 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
4675 cmd->set_thread_register(0, start);
4676 if ( fWriter.fOptions.hasCustomStack() )
4677 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
4681 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
4683 uint64_t size = this->getSize();
4684 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4685 bzero(buffer, size);
4686 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
4687 cmd->set_cmd(LC_UNIXTHREAD);
4688 cmd->set_cmdsize(size);
4689 cmd->set_flavor(1); // i386_THREAD_STATE
4690 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
4691 cmd->set_thread_register(10, start);
4692 if ( fWriter.fOptions.hasCustomStack() )
4693 cmd->set_thread_register(15, fWriter.fOptions.customStackAddr()); // uesp
4698 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
4700 uint64_t size = this->getSize();
4701 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4702 bzero(buffer, size);
4703 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
4704 cmd->set_cmd(LC_UNIXTHREAD);
4705 cmd->set_cmdsize(size);
4706 cmd->set_flavor(x86_THREAD_STATE64);
4707 cmd->set_count(x86_THREAD_STATE64_COUNT);
4708 cmd->set_thread_register(16, start); // rip
4709 if ( fWriter.fOptions.hasCustomStack() )
4710 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
4714 template <typename A>
4715 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
4717 bzero(buffer, fSize);
4720 template <typename A>
4721 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
4724 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
4725 if ( fWriter.fLargestAtomSize < newSize )
4726 fWriter.fLargestAtomSize = newSize;
4729 template <typename A>
4730 uint64_t LinkEditAtom<A>::getFileOffset() const
4732 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
4736 template <typename A>
4737 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
4739 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
4742 template <typename A>
4743 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4745 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
4749 template <typename A>
4750 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
4752 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
4755 template <typename A>
4756 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4758 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
4763 template <typename A>
4764 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
4766 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
4769 template <typename A>
4770 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4772 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
4775 template <typename A>
4776 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
4778 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
4781 template <typename A>
4782 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4784 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
4789 template <typename A>
4790 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
4792 return fTable.size() * sizeof(uint32_t);
4795 template <typename A>
4796 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4798 uint64_t size = this->getSize();
4799 bzero(buffer, size);
4800 const uint32_t indirectTableSize = fTable.size();
4801 uint32_t* indirectTable = (uint32_t*)buffer;
4802 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
4803 if ( it->indirectIndex < indirectTableSize ) {
4804 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
4807 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
4814 template <typename A>
4815 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
4816 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
4818 fCurrentBuffer = new char[kBufferSize];
4819 // burn first byte of string pool (so zero is never a valid string offset)
4820 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
4821 // make offset 1 always point to an empty string
4822 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
4825 template <typename A>
4826 uint64_t StringsLinkEditAtom<A>::getSize() const
4828 return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4831 template <typename A>
4832 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4834 uint64_t offset = 0;
4835 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
4836 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
4837 offset += kBufferSize;
4839 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
4842 template <typename A>
4843 int32_t StringsLinkEditAtom<A>::add(const char* name)
4845 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4846 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
4847 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
4848 fCurrentBufferUsed += lenNeeded;
4851 int copied = kBufferSize-fCurrentBufferUsed-1;
4852 // change trailing '\0' that strlcpy added to real char
4853 fCurrentBuffer[kBufferSize-1] = name[copied];
4854 // alloc next buffer
4855 fFullBuffers.push_back(fCurrentBuffer);
4856 fCurrentBuffer = new char[kBufferSize];
4857 fCurrentBufferUsed = 0;
4858 // append rest of string
4859 this->add(&name[copied+1]);
4865 template <typename A>
4866 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
4868 StringToOffset::iterator pos = fUniqueStrings.find(name);
4869 if ( pos != fUniqueStrings.end() ) {
4873 int32_t offset = this->add(name);
4874 fUniqueStrings[name] = offset;
4880 template <typename A>
4881 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
4882 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
4884 char* buf = new char[strlen(name)+32];
4885 if ( targetOffset == 0 ) {
4886 if ( islandRegion == 0 )
4887 sprintf(buf, "%s$island", name);
4889 sprintf(buf, "%s$island_%d", name, islandRegion);
4892 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
4899 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4901 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4902 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4903 OSWriteBigInt32(buffer, 0, branchInstruction);
4907 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4909 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4910 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4911 OSWriteBigInt32(buffer, 0, branchInstruction);
4915 uint64_t BranchIslandAtom<ppc>::getSize() const
4921 uint64_t BranchIslandAtom<ppc64>::getSize() const
4928 bool StubAtom<ppc64>::pic() const
4930 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
4931 // This usually only happens when a large zero-page is requested
4932 switch ( fWriter.fOptions.outputKind() ) {
4933 case Options::kDynamicExecutable:
4934 return (fWriter.fPageZeroAtom->getSize() > 4096);
4935 case Options::kDynamicLibrary:
4936 case Options::kDynamicBundle:
4938 case Options::kObjectFile:
4939 case Options::kDyld:
4940 case Options::kStaticExecutable:
4943 throw "internal ld64 error: file type does not use stubs";
4947 bool StubAtom<ppc>::pic() const
4949 return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
4954 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
4955 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4957 writer.fAllSynthesizedStubs.push_back(this);
4959 LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
4961 // picbase is 8 bytes into atom
4962 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, NULL, 8));
4963 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, NULL, 8));
4966 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
4967 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
4972 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
4973 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4975 writer.fAllSynthesizedStubs.push_back(this);
4977 LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
4979 // picbase is 8 bytes into atom
4980 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, NULL, 8));
4981 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, NULL, 8));
4984 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
4985 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
4989 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
4991 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
4992 : WriterAtom<x86>(writer, Segment::fgImportSegment), fName(stubName(target.getName())), fTarget(target)
4994 writer.fAllSynthesizedStubs.push_back(this);
4998 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
4999 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
5001 writer.fAllSynthesizedStubs.push_back(this);
5003 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target);
5004 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
5007 template <typename A>
5008 const char* StubAtom<A>::stubName(const char* name)
5011 asprintf(&buf, "%s$stub", name);
5016 uint64_t StubAtom<ppc>::getSize() const
5018 return ( pic() ? 32 : 16 );
5022 uint64_t StubAtom<ppc64>::getSize() const
5024 return ( pic() ? 32 : 16 );
5028 uint64_t StubAtom<x86>::getSize() const
5034 uint64_t StubAtom<x86_64>::getSize() const
5040 uint8_t StubAtom<x86>::getAlignment() const
5042 // special case x86 fast stubs to be byte aligned
5047 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
5050 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
5051 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
5052 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
5053 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
5054 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
5055 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
5056 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
5057 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
5060 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
5061 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
5062 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
5063 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
5068 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
5071 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
5072 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
5073 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
5074 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
5075 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
5076 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
5077 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
5078 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
5081 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
5082 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
5083 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
5084 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
5089 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
5099 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
5101 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
5109 // x86_64 stubs are 7 bytes and need no alignment
5111 uint8_t StubAtom<x86_64>::getAlignment() const
5117 const char* StubAtom<ppc>::getSectionName() const
5119 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
5123 const char* StubAtom<ppc64>::getSectionName() const
5125 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
5129 const char* StubAtom<x86>::getSectionName() const
5131 return "__jump_table";
5137 StubHelperAtom<x86_64>::StubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer)
5138 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
5140 writer.fAllSynthesizedStubHelpers.push_back(this);
5142 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &lazyPointer));
5143 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldHelper));
5144 if ( writer.fDyldHelper == NULL )
5145 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
5149 uint64_t StubHelperAtom<x86_64>::getSize() const
5155 void StubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
5157 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
5164 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
5171 template <typename A>
5172 const char* StubHelperAtom<A>::stubName(const char* name)
5175 asprintf(&buf, "%s$stubHelper", name);
5180 // specialize lazy pointer for x86_64 to initially pointer to stub helper
5182 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
5183 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
5185 writer.fAllSynthesizedLazyPointers.push_back(this);
5187 StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this);
5188 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
5192 template <typename A>
5193 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
5194 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
5196 writer.fAllSynthesizedLazyPointers.push_back(this);
5198 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
5203 template <typename A>
5204 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
5207 asprintf(&buf, "%s$lazy_pointer", name);
5211 template <typename A>
5212 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
5214 bzero(buffer, getSize());
5218 template <typename A>
5219 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
5220 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
5222 writer.fAllSynthesizedNonLazyPointers.push_back(this);
5224 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
5227 template <typename A>
5228 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
5231 asprintf(&buf, "%s$non_lazy_pointer", name);
5235 template <typename A>
5236 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
5238 bzero(buffer, getSize());
5243 }; // namespace executable
5244 }; // namespace mach_o
5247 #endif // __EXECUTABLE_MACH_O__