1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __EXECUTABLE_MACH_O__
26 #define __EXECUTABLE_MACH_O__
32 #include <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>
40 #include <CommonCrypto/CommonDigest.h>
46 #include <ext/hash_map>
48 #include "ObjectFile.h"
49 #include "ExecutableFile.h"
52 #include "MachOFileAbstraction.hpp"
55 #define S_DTRACE_DOF 0xF
59 #define MH_PIE 0x200000
64 // To implement architecture xxx, you must write template specializations for the following methods:
65 // MachHeaderAtom<xxx>::setHeaderInfo()
66 // ThreadsLoadCommandsAtom<xxx>::getSize()
67 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
68 // Writer<xxx>::addObjectRelocs()
69 // Writer<xxx>::fixUpReferenceRelocatable()
70 // Writer<xxx>::fixUpReferenceFinal()
71 // Writer<xxx>::stubableReference()
72 // Writer<xxx>::weakImportReferenceKind()
73 // Writer<xxx>::GOTReferenceKind()
78 namespace executable {
81 template <typename A> class WriterAtom;
82 template <typename A> class PageZeroAtom;
83 template <typename A> class CustomStackAtom;
84 template <typename A> class MachHeaderAtom;
85 template <typename A> class SegmentLoadCommandsAtom;
86 template <typename A> class SymbolTableLoadCommandsAtom;
87 template <typename A> class ThreadsLoadCommandsAtom;
88 template <typename A> class DylibIDLoadCommandsAtom;
89 template <typename A> class RoutinesLoadCommandsAtom;
90 template <typename A> class DyldLoadCommandsAtom;
91 template <typename A> class UUIDLoadCommandAtom;
92 template <typename A> class LinkEditAtom;
93 template <typename A> class SectionRelocationsLinkEditAtom;
94 template <typename A> class LocalRelocationsLinkEditAtom;
95 template <typename A> class ExternalRelocationsLinkEditAtom;
96 template <typename A> class SymbolTableLinkEditAtom;
97 template <typename A> class SegmentSplitInfoLoadCommandsAtom;
98 template <typename A> class SegmentSplitInfoContentAtom;
99 template <typename A> class IndirectTableLinkEditAtom;
100 template <typename A> class ModuleInfoLinkEditAtom;
101 template <typename A> class StringsLinkEditAtom;
102 template <typename A> class LoadCommandsPaddingAtom;
103 template <typename A> class StubAtom;
104 template <typename A> class StubHelperAtom;
105 template <typename A> class LazyPointerAtom;
106 template <typename A> class NonLazyPointerAtom;
107 template <typename A> class DylibLoadCommandsAtom;
110 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
111 class SectionInfo : public ObjectFile::Section {
113 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0),
114 fAlignment(0), fAllLazyPointers(false), fAllNonLazyPointers(false), fAllStubs(false),
115 fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false)
116 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
117 void setIndex(unsigned int index) { fIndex=index; }
118 std::vector<ObjectFile::Atom*> fAtoms;
119 char fSegmentName[20];
120 char fSectionName[20];
121 uint64_t fFileOffset;
123 uint32_t fRelocCount;
124 uint32_t fRelocOffset;
125 uint32_t fIndirectSymbolOffset;
127 bool fAllLazyPointers;
128 bool fAllNonLazyPointers;
130 bool fAllSelfModifyingStubs;
132 bool fVirtualSection;
135 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
139 SegmentInfo() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
140 fBaseAddress(0), fSize(0), fFixedAddress(false),
141 fIndependentAddress(false) { fName[0] = '\0'; }
142 std::vector<class SectionInfo*> fSections;
144 uint32_t fInitProtection;
145 uint32_t fMaxProtection;
146 uint64_t fFileOffset;
148 uint64_t fBaseAddress;
151 bool fIndependentAddress;
154 template <typename A>
155 class Writer : public ExecutableFile::Writer
158 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
161 virtual const char* getPath() { return fFilePath; }
162 virtual time_t getModificationTime() { return 0; }
163 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
164 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
165 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
166 virtual std::vector<Stab>* getStabs() { return NULL; }
168 virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint,
169 bool objcReplacementClasses);
170 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
171 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
172 std::vector<class ObjectFile::Reader::Stab>& stabs,
173 class ObjectFile::Atom* entryPointAtom,
174 class ObjectFile::Atom* dyldHelperAtom,
175 bool createUUID, bool canScatter,
176 ObjectFile::Reader::CpuConstraint cpuConstraint,
177 bool biggerThanTwoGigs);
180 typedef typename A::P P;
181 typedef typename A::P::uint_t pint_t;
183 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
185 void assignFileOffsets();
186 void synthesizeStubs();
187 void insertDummyStubs();
188 void partitionIntoSections();
189 bool addBranchIslands();
190 bool addPPCBranchIslands();
191 bool isBranch24Reference(uint8_t kind);
192 void adjustLoadCommandsAndPadding();
193 void createDynamicLinkerCommand();
194 void createDylibCommands();
195 void buildLinkEdit();
196 const char* getArchString();
198 uint64_t writeAtoms();
199 void writeNoOps(uint32_t from, uint32_t to);
200 void copyNoOps(uint8_t* from, uint8_t* to);
201 bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
202 void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
203 void collectExportedAndImportedAndLocalAtoms();
204 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
205 void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
206 void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
207 void buildSymbolTable();
208 const char* symbolTableName(const ObjectFile::Atom* atom);
209 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
210 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
211 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
212 void copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
213 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
214 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
215 bool shouldExport(const ObjectFile::Atom& atom) const;
217 void adjustLinkEditSections();
218 void buildObjectFileFixups();
219 void buildExecutableFixups();
220 bool preboundLazyPointerType(uint8_t* type);
221 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
222 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
223 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
224 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
225 uint8_t buffer[], bool finalLinkedImage) const;
226 uint32_t symbolIndex(ObjectFile::Atom& atom);
227 bool makesExternalRelocatableReference(ObjectFile::Atom& target) const;
228 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
229 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
230 uint8_t getRelocPointerSize();
231 uint64_t maxAddress();
232 bool stubableReference(const ObjectFile::Reference* ref);
233 bool GOTReferenceKind(uint8_t kind);
234 bool optimizableGOTReferenceKind(uint8_t kind);
235 bool weakImportReferenceKind(uint8_t kind);
236 unsigned int collectStabs();
237 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
238 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
239 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
240 void addStabs(uint32_t startIndex);
241 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
242 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
243 bool mightNeedPadSegment();
244 void scanForAbsoluteReferences();
245 bool needsModuleTable();
246 void optimizeDylibReferences();
247 bool indirectSymbolIsLocal(const ObjectFile::Reference* ref) const;
249 struct DirectLibrary {
250 class ObjectFile::Reader* fLibrary;
255 friend class WriterAtom<A>;
256 friend class PageZeroAtom<A>;
257 friend class CustomStackAtom<A>;
258 friend class MachHeaderAtom<A>;
259 friend class SegmentLoadCommandsAtom<A>;
260 friend class SymbolTableLoadCommandsAtom<A>;
261 friend class ThreadsLoadCommandsAtom<A>;
262 friend class DylibIDLoadCommandsAtom<A>;
263 friend class RoutinesLoadCommandsAtom<A>;
264 friend class DyldLoadCommandsAtom<A>;
265 friend class UUIDLoadCommandAtom<A>;
266 friend class LinkEditAtom<A>;
267 friend class SectionRelocationsLinkEditAtom<A>;
268 friend class LocalRelocationsLinkEditAtom<A>;
269 friend class ExternalRelocationsLinkEditAtom<A>;
270 friend class SymbolTableLinkEditAtom<A>;
271 friend class SegmentSplitInfoLoadCommandsAtom<A>;
272 friend class SegmentSplitInfoContentAtom<A>;
273 // friend class IndirectTableLinkEditAtom<A>;
274 friend class ModuleInfoLinkEditAtom<A>;
275 friend class StringsLinkEditAtom<A>;
276 friend class LoadCommandsPaddingAtom<A>;
277 friend class StubAtom<A>;
278 friend class StubHelperAtom<A>;
279 friend class LazyPointerAtom<A>;
280 friend class NonLazyPointerAtom<A>;
281 friend class DylibLoadCommandsAtom<A>;
283 const char* fFilePath;
286 std::vector<class ObjectFile::Atom*>* fAllAtoms;
287 std::vector<class ObjectFile::Reader::Stab>* fStabs;
288 class SectionInfo* fLoadCommandsSection;
289 class SegmentInfo* fLoadCommandsSegment;
290 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
291 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
292 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
293 class UUIDLoadCommandAtom<A>* fUUIDAtom;
294 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
295 std::vector<SegmentInfo*> fSegmentInfos;
296 class SegmentInfo* fPadSegmentInfo;
297 class ObjectFile::Atom* fEntryPoint;
298 class ObjectFile::Atom* fDyldHelper;
299 std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*> fLibraryToLoadCommand;
300 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
301 std::map<class ObjectFile::Reader*, class ObjectFile::Reader*> fLibraryAliases;
302 std::vector<class ObjectFile::Atom*> fExportedAtoms;
303 std::vector<class ObjectFile::Atom*> fImportedAtoms;
304 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
305 std::vector<macho_nlist<P> > fLocalExtraLabels;
306 std::vector<macho_nlist<P> > fGlobalExtraLabels;
307 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
308 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
309 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
310 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
311 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
312 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
313 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
314 class StringsLinkEditAtom<A>* fStringsAtom;
315 class PageZeroAtom<A>* fPageZeroAtom;
316 macho_nlist<P>* fSymbolTable;
317 std::vector<macho_relocation_info<P> > fSectionRelocs;
318 std::vector<macho_relocation_info<P> > fInternalRelocs;
319 std::vector<macho_relocation_info<P> > fExternalRelocs;
320 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
321 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
322 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
323 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
324 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
325 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
326 uint32_t fSymbolTableCount;
327 uint32_t fSymbolTableStabsCount;
328 uint32_t fSymbolTableStabsStartIndex;
329 uint32_t fSymbolTableLocalCount;
330 uint32_t fSymbolTableLocalStartIndex;
331 uint32_t fSymbolTableExportCount;
332 uint32_t fSymbolTableExportStartIndex;
333 uint32_t fSymbolTableImportCount;
334 uint32_t fSymbolTableImportStartIndex;
335 uint32_t fLargestAtomSize;
336 bool fEmitVirtualSections;
337 bool fHasWeakExports;
338 bool fReferencesWeakImports;
340 bool fWritableSegmentPastFirst4GB;
341 bool fNoReExportedDylibs;
342 bool fBiggerThanTwoGigs;
344 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
345 SegmentInfo* fFirstWritableSegment;
346 ObjectFile::Reader::CpuConstraint fCpuConstraint;
347 uint32_t fAnonNameIndex;
351 class Segment : public ObjectFile::Segment
354 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
355 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
356 virtual const char* getName() const { return fName; }
357 virtual bool isContentReadable() const { return fReadable; }
358 virtual bool isContentWritable() const { return fWritable; }
359 virtual bool isContentExecutable() const { return fExecutable; }
360 virtual bool hasFixedAddress() const { return fFixedAddress; }
362 static Segment fgTextSegment;
363 static Segment fgPageZeroSegment;
364 static Segment fgLinkEditSegment;
365 static Segment fgStackSegment;
366 static Segment fgImportSegment;
367 static Segment fgROImportSegment;
368 static Segment fgDataSegment;
369 static Segment fgObjCSegment;
374 const bool fReadable;
375 const bool fWritable;
376 const bool fExecutable;
377 const bool fFixedAddress;
380 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
381 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
382 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
383 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
384 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
385 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
386 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
387 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
390 template <typename A>
391 class WriterAtom : public ObjectFile::Atom
394 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
395 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
397 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
398 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
399 virtual const char* getName() const { return NULL; }
400 virtual const char* getDisplayName() const { return this->getName(); }
401 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
402 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
403 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
404 virtual bool dontDeadStrip() const { return true; }
405 virtual bool isZeroFill() const { return false; }
406 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
407 virtual bool mustRemainInSection() const { return true; }
408 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
409 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
410 virtual uint32_t getOrdinal() const { return 0; }
411 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
412 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
413 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
414 virtual void setScope(Scope) { }
418 virtual ~WriterAtom() {}
419 typedef typename A::P P;
420 typedef typename A::P::E E;
422 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
428 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
431 template <typename A>
432 class PageZeroAtom : public WriterAtom<A>
435 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
436 fSize(fWriter.fOptions.zeroPageSize()) {}
437 virtual const char* getDisplayName() const { return "page zero content"; }
438 virtual bool isZeroFill() const { return true; }
439 virtual uint64_t getSize() const { return fSize; }
440 virtual const char* getSectionName() const { return "._zeropage"; }
441 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
442 void setSize(uint64_t size) { fSize = size; }
444 using WriterAtom<A>::fWriter;
445 typedef typename A::P P;
450 template <typename A>
451 class DsoHandleAtom : public WriterAtom<A>
454 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
455 virtual const char* getName() const { return "___dso_handle"; }
456 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
457 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
458 virtual uint64_t getSize() const { return 0; }
459 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
460 virtual const char* getSectionName() const { return "._mach_header"; }
461 virtual void copyRawContent(uint8_t buffer[]) const {}
465 template <typename A>
466 class MachHeaderAtom : public WriterAtom<A>
469 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
470 virtual const char* getName() const;
471 virtual const char* getDisplayName() const;
472 virtual ObjectFile::Atom::Scope getScope() const;
473 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
474 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
475 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
476 virtual const char* getSectionName() const { return "._mach_header"; }
477 virtual uint32_t getOrdinal() const { return 1; }
478 virtual void copyRawContent(uint8_t buffer[]) const;
480 using WriterAtom<A>::fWriter;
481 typedef typename A::P P;
482 void setHeaderInfo(macho_header<typename A::P>& header) const;
485 template <typename A>
486 class CustomStackAtom : public WriterAtom<A>
489 CustomStackAtom(Writer<A>& writer);
490 virtual const char* getDisplayName() const { return "custom stack content"; }
491 virtual bool isZeroFill() const { return true; }
492 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
493 virtual const char* getSectionName() const { return "._stack"; }
494 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
496 using WriterAtom<A>::fWriter;
497 typedef typename A::P P;
498 static bool stackGrowsDown();
501 template <typename A>
502 class LoadCommandAtom : public WriterAtom<A>
505 LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment), fOrdinal(fgCurrentOrdinal++) {}
506 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
507 virtual const char* getSectionName() const { return "._load_commands"; }
508 virtual uint32_t getOrdinal() const { return fOrdinal; }
509 static uint64_t alignedSize(uint64_t size);
512 static uint32_t fgCurrentOrdinal;
515 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
517 template <typename A>
518 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
521 SegmentLoadCommandsAtom(Writer<A>& writer)
522 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0)
523 { writer.fSegmentCommands = this; }
524 virtual const char* getDisplayName() const { return "segment load commands"; }
525 virtual uint64_t getSize() const { return fSize; }
526 virtual void copyRawContent(uint8_t buffer[]) const;
530 unsigned int commandCount() { return fCommandCount; }
532 using WriterAtom<A>::fWriter;
533 typedef typename A::P P;
534 unsigned int fCommandCount;
539 template <typename A>
540 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
543 SymbolTableLoadCommandsAtom(Writer<A>&);
544 virtual const char* getDisplayName() const { return "symbol table load commands"; }
545 virtual uint64_t getSize() const;
546 virtual void copyRawContent(uint8_t buffer[]) const;
547 unsigned int commandCount();
548 void needDynamicTable();
550 using WriterAtom<A>::fWriter;
551 typedef typename A::P P;
552 bool fNeedsDynamicSymbolTable;
553 macho_symtab_command<typename A::P> fSymbolTable;
554 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
557 template <typename A>
558 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
561 ThreadsLoadCommandsAtom(Writer<A>& writer)
562 : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
563 virtual const char* getDisplayName() const { return "thread load commands"; }
564 virtual uint64_t getSize() const;
565 virtual void copyRawContent(uint8_t buffer[]) const;
567 using WriterAtom<A>::fWriter;
568 typedef typename A::P P;
570 uint32_t fBufferSize;
573 template <typename A>
574 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
577 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
578 virtual const char* getDisplayName() const { return "dyld load command"; }
579 virtual uint64_t getSize() const;
580 virtual void copyRawContent(uint8_t buffer[]) const;
582 using WriterAtom<A>::fWriter;
583 typedef typename A::P P;
586 template <typename A>
587 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
590 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
591 virtual const char* getDisplayName() const { return "segment split info load command"; }
592 virtual uint64_t getSize() const;
593 virtual void copyRawContent(uint8_t buffer[]) const;
595 using WriterAtom<A>::fWriter;
596 typedef typename A::P P;
599 template <typename A>
600 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
603 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
604 LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
605 virtual const char* getDisplayName() const { return "allowable_client load command"; }
606 virtual uint64_t getSize() const;
607 virtual void copyRawContent(uint8_t buffer[]) const;
609 using WriterAtom<A>::fWriter;
610 typedef typename A::P P;
611 const char* clientString;
614 template <typename A>
615 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
618 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
619 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info), fOptimizedAway(false) {}
620 virtual const char* getDisplayName() const { return "dylib load command"; }
621 virtual uint64_t getSize() const;
622 virtual void copyRawContent(uint8_t buffer[]) const;
623 virtual void optimizeAway() { fOptimizedAway = true; }
625 using WriterAtom<A>::fWriter;
626 typedef typename A::P P;
627 ExecutableFile::DyLibUsed fInfo;
631 template <typename A>
632 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
635 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
636 virtual const char* getDisplayName() const { return "dylib ID load command"; }
637 virtual uint64_t getSize() const;
638 virtual void copyRawContent(uint8_t buffer[]) const;
640 using WriterAtom<A>::fWriter;
641 typedef typename A::P P;
644 template <typename A>
645 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
648 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
649 virtual const char* getDisplayName() const { return "routines load command"; }
650 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
651 virtual void copyRawContent(uint8_t buffer[]) const;
653 using WriterAtom<A>::fWriter;
654 typedef typename A::P P;
657 template <typename A>
658 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
661 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
662 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
663 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
664 virtual uint64_t getSize() const;
665 virtual void copyRawContent(uint8_t buffer[]) const;
667 typedef typename A::P P;
671 template <typename A>
672 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
675 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
676 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
677 virtual const char* getDisplayName() const { return "sub-library load command"; }
678 virtual uint64_t getSize() const;
679 virtual void copyRawContent(uint8_t buffer[]) const;
681 using WriterAtom<A>::fWriter;
682 typedef typename A::P P;
683 const char* fNameStart;
687 template <typename A>
688 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
691 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
692 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
693 virtual const char* getDisplayName() const { return "umbrella load command"; }
694 virtual uint64_t getSize() const;
695 virtual void copyRawContent(uint8_t buffer[]) const;
697 using WriterAtom<A>::fWriter;
698 typedef typename A::P P;
702 template <typename A>
703 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
706 UUIDLoadCommandAtom(Writer<A>& writer)
707 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) {}
708 virtual const char* getDisplayName() const { return "uuid load command"; }
709 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
710 virtual void copyRawContent(uint8_t buffer[]) const;
711 virtual void generate();
712 void setContent(const uint8_t uuid[16]);
713 const uint8_t* getUUID() { return fUUID; }
715 using WriterAtom<A>::fWriter;
716 typedef typename A::P P;
722 template <typename A>
723 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
726 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
727 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fPath(path) {}
728 virtual const char* getDisplayName() const { return "rpath load command"; }
729 virtual uint64_t getSize() const;
730 virtual void copyRawContent(uint8_t buffer[]) const;
732 using WriterAtom<A>::fWriter;
733 typedef typename A::P P;
738 template <typename A>
739 class LoadCommandsPaddingAtom : public WriterAtom<A>
742 LoadCommandsPaddingAtom(Writer<A>& writer)
743 : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
744 virtual const char* getDisplayName() const { return "header padding"; }
745 virtual uint64_t getSize() const { return fSize; }
746 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
747 virtual void copyRawContent(uint8_t buffer[]) const;
749 void setSize(uint64_t newSize);
751 using WriterAtom<A>::fWriter;
752 typedef typename A::P P;
756 template <typename A>
757 class LinkEditAtom : public WriterAtom<A>
760 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
761 uint64_t getFileOffset() const;
762 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
763 virtual uint32_t getOrdinal() const { return fOrdinal; }
766 static uint32_t fgCurrentOrdinal;
768 typedef typename A::P P;
771 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
773 template <typename A>
774 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
777 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
778 virtual const char* getDisplayName() const { return "section relocations"; }
779 virtual uint64_t getSize() const;
780 virtual const char* getSectionName() const { return "._section_relocs"; }
781 virtual void copyRawContent(uint8_t buffer[]) const;
783 using WriterAtom<A>::fWriter;
784 typedef typename A::P P;
787 template <typename A>
788 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
791 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
792 virtual const char* getDisplayName() const { return "local relocations"; }
793 virtual uint64_t getSize() const;
794 virtual const char* getSectionName() const { return "._local_relocs"; }
795 virtual void copyRawContent(uint8_t buffer[]) const;
797 using WriterAtom<A>::fWriter;
798 typedef typename A::P P;
801 template <typename A>
802 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
805 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
806 virtual const char* getDisplayName() const { return "symbol table"; }
807 virtual uint64_t getSize() const;
808 virtual const char* getSectionName() const { return "._symbol_table"; }
809 virtual void copyRawContent(uint8_t buffer[]) const;
811 using WriterAtom<A>::fWriter;
812 typedef typename A::P P;
815 template <typename A>
816 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
819 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
820 virtual const char* getDisplayName() const { return "external relocations"; }
821 virtual uint64_t getSize() const;
822 virtual const char* getSectionName() const { return "._extern_relocs"; }
823 virtual void copyRawContent(uint8_t buffer[]) const;
825 using WriterAtom<A>::fWriter;
826 typedef typename A::P P;
829 struct IndirectEntry {
830 uint32_t indirectIndex;
831 uint32_t symbolIndex;
835 template <typename A>
836 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
839 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
840 virtual const char* getDisplayName() const { return "split segment info"; }
841 virtual uint64_t getSize() const;
842 virtual const char* getSectionName() const { return "._split_info"; }
843 virtual void copyRawContent(uint8_t buffer[]) const;
844 bool canEncode() { return !fCantEncode; }
845 void setCantEncode() { fCantEncode = true; }
846 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
847 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
848 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
849 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
853 using WriterAtom<A>::fWriter;
854 typedef typename A::P P;
855 typedef typename A::P::uint_t pint_t;
856 struct AtomAndOffset {
857 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
858 const ObjectFile::Atom* atom;
861 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
863 std::vector<AtomAndOffset> fKind1Locations;
864 std::vector<AtomAndOffset> fKind2Locations;
865 std::vector<AtomAndOffset> fKind3Locations;
866 std::vector<AtomAndOffset> fKind4Locations;
867 std::vector<uint8_t> fEncodedData;
871 template <typename A>
872 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
875 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
876 virtual const char* getDisplayName() const { return "indirect symbol table"; }
877 virtual uint64_t getSize() const;
878 virtual const char* getSectionName() const { return "._indirect_syms"; }
879 virtual void copyRawContent(uint8_t buffer[]) const;
881 std::vector<IndirectEntry> fTable;
884 using WriterAtom<A>::fWriter;
885 typedef typename A::P P;
888 template <typename A>
889 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
892 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
893 virtual const char* getDisplayName() const { return "modulel table"; }
894 virtual uint64_t getSize() const;
895 virtual const char* getSectionName() const { return "._module_info"; }
896 virtual void copyRawContent(uint8_t buffer[]) const;
898 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
899 uint32_t getTableOfContentsFileOffset() const;
900 uint32_t getModuleTableFileOffset() const;
901 uint32_t getReferencesFileOffset() const;
902 uint32_t getReferencesCount() const;
905 using WriterAtom<A>::fWriter;
906 typedef typename A::P P;
907 uint32_t fModuleNameOffset;
914 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
917 template <typename A>
918 class StringsLinkEditAtom : public LinkEditAtom<A>
921 StringsLinkEditAtom(Writer<A>& writer);
922 virtual const char* getDisplayName() const { return "string pool"; }
923 virtual uint64_t getSize() const;
924 virtual const char* getSectionName() const { return "._string_pool"; }
925 virtual void copyRawContent(uint8_t buffer[]) const;
927 int32_t add(const char* name);
928 int32_t addUnique(const char* name);
929 int32_t emptyString() { return 1; }
930 const char* stringForIndex(int32_t) const;
933 using WriterAtom<A>::fWriter;
934 typedef typename A::P P;
935 enum { kBufferSize = 0x01000000 };
936 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
938 std::vector<char*> fFullBuffers;
939 char* fCurrentBuffer;
940 uint32_t fCurrentBufferUsed;
941 StringToOffset fUniqueStrings;
946 template <typename A>
947 class UndefinedSymbolProxyAtom : public WriterAtom<A>
950 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
951 virtual const char* getName() const { return fName; }
952 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
953 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
954 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
955 virtual uint64_t getSize() const { return 0; }
956 virtual const char* getSectionName() const { return "._imports"; }
958 using WriterAtom<A>::fWriter;
959 typedef typename A::P P;
963 template <typename A>
964 class BranchIslandAtom : public WriterAtom<A>
967 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
968 virtual const char* getName() const { return fName; }
969 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
970 virtual uint64_t getSize() const;
971 virtual const char* getSectionName() const { return "__text"; }
972 virtual void copyRawContent(uint8_t buffer[]) const;
974 using WriterAtom<A>::fWriter;
976 ObjectFile::Atom& fTarget;
977 uint32_t fTargetOffset;
980 template <typename A>
981 class StubAtom : public WriterAtom<A>
984 StubAtom(Writer<A>& writer, ObjectFile::Atom& target);
985 virtual const char* getName() const { return fName; }
986 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
987 virtual uint64_t getSize() const;
988 virtual ObjectFile::Alignment getAlignment() const;
989 virtual const char* getSectionName() const { return "__symbol_stub1"; }
990 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
991 virtual void copyRawContent(uint8_t buffer[]) const;
992 ObjectFile::Atom* getTarget() { return &fTarget; }
994 static const char* stubName(const char* importName);
996 using WriterAtom<A>::fWriter;
998 ObjectFile::Atom& fTarget;
999 std::vector<ObjectFile::Reference*> fReferences;
1002 template <typename A>
1003 class StubHelperAtom : public WriterAtom<A>
1006 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer);
1007 virtual const char* getName() const { return fName; }
1008 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1009 virtual uint64_t getSize() const;
1010 virtual const char* getSectionName() const { return "__stub_helper"; }
1011 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1012 virtual void copyRawContent(uint8_t buffer[]) const;
1013 ObjectFile::Atom* getTarget() { return &fTarget; }
1015 static const char* stubName(const char* importName);
1016 using WriterAtom<A>::fWriter;
1018 ObjectFile::Atom& fTarget;
1019 std::vector<ObjectFile::Reference*> fReferences;
1022 template <typename A>
1023 class LazyPointerAtom : public WriterAtom<A>
1026 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1027 virtual const char* getName() const { return fName; }
1028 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1029 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1030 virtual const char* getSectionName() const { return "__la_symbol_ptr"; }
1031 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1032 virtual void copyRawContent(uint8_t buffer[]) const;
1033 ObjectFile::Atom* getTarget() { return &fTarget; }
1035 using WriterAtom<A>::fWriter;
1036 static const char* lazyPointerName(const char* importName);
1038 ObjectFile::Atom& fTarget;
1039 std::vector<ObjectFile::Reference*> fReferences;
1043 template <typename A>
1044 class NonLazyPointerAtom : public WriterAtom<A>
1047 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1048 virtual const char* getName() const { return fName; }
1049 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1050 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1051 virtual const char* getSectionName() const { return "__nl_symbol_ptr"; }
1052 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1053 virtual void copyRawContent(uint8_t buffer[]) const;
1054 ObjectFile::Atom* getTarget() { return &fTarget; }
1056 using WriterAtom<A>::fWriter;
1057 static const char* nonlazyPointerName(const char* importName);
1059 ObjectFile::Atom& fTarget;
1060 std::vector<ObjectFile::Reference*> fReferences;
1064 template <typename A>
1065 class ObjCInfoAtom : public WriterAtom<A>
1068 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1069 bool objcReplacementClasses);
1070 virtual const char* getName() const { return "objc$info"; }
1071 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1072 virtual uint64_t getSize() const { return 8; }
1073 virtual const char* getSectionName() const;
1074 virtual void copyRawContent(uint8_t buffer[]) const;
1076 Segment& getInfoSegment() const;
1077 uint32_t fContent[2];
1081 template <typename A>
1082 class WriterReference : public ObjectFile::Reference
1085 typedef typename A::ReferenceKinds Kinds;
1087 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1088 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1089 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target),
1090 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1092 virtual ~WriterReference() {}
1094 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return ObjectFile::Reference::kBoundDirectly; }
1095 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1096 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1097 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1098 virtual const char* getTargetName() const { return fTarget->getName(); }
1099 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1100 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1101 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1102 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1103 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = ⌖ fTargetOffset = offset; }
1104 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = ⌖ }
1105 virtual void setFromTargetName(const char* name) { }
1106 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1107 virtual const char* getDescription() const { return "writer reference"; }
1108 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1112 uint32_t fFixUpOffsetInSrc;
1113 ObjectFile::Atom* fTarget;
1114 uint32_t fTargetOffset;
1115 ObjectFile::Atom* fFromTarget;
1116 uint32_t fFromTargetOffset;
1122 StubHelperAtom<x86_64>::StubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer)
1123 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1125 writer.fAllSynthesizedStubHelpers.push_back(this);
1127 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &lazyPointer));
1128 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldHelper));
1129 if ( writer.fDyldHelper == NULL )
1130 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1134 uint64_t StubHelperAtom<x86_64>::getSize() const
1140 void StubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1142 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1149 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1156 template <typename A>
1157 const char* StubHelperAtom<A>::stubName(const char* name)
1160 asprintf(&buf, "%s$stubHelper", name);
1165 // specialize lazy pointer for x86_64 to initially pointer to stub helper
1167 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
1168 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
1170 writer.fAllSynthesizedLazyPointers.push_back(this);
1172 StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this);
1173 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
1177 template <typename A>
1178 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
1179 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
1181 writer.fAllSynthesizedLazyPointers.push_back(this);
1183 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
1188 template <typename A>
1189 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
1192 asprintf(&buf, "%s$lazy_pointer", name);
1196 template <typename A>
1197 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
1199 bzero(buffer, getSize());
1203 template <typename A>
1204 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
1205 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
1207 writer.fAllSynthesizedNonLazyPointers.push_back(this);
1209 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
1212 template <typename A>
1213 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
1216 asprintf(&buf, "%s$non_lazy_pointer", name);
1220 template <typename A>
1221 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
1223 bzero(buffer, getSize());
1229 bool StubAtom<ppc64>::pic() const
1231 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
1232 // Usually that only happens if page zero is very large
1233 return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
1237 bool StubAtom<ppc>::pic() const
1239 return fWriter.fSlideable;
1243 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
1249 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
1255 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
1256 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1258 writer.fAllSynthesizedStubs.push_back(this);
1260 LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
1262 // picbase is 8 bytes into atom
1263 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
1264 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
1267 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
1268 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
1273 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
1274 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1276 writer.fAllSynthesizedStubs.push_back(this);
1278 LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
1280 // picbase is 8 bytes into atom
1281 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
1282 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
1285 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
1286 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
1290 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
1292 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
1293 : WriterAtom<x86>(writer, writer.fOptions.readOnlyx86Stubs() ? Segment::fgROImportSegment : Segment::fgImportSegment),
1296 if ( &target == NULL )
1297 fName = "cache-line-crossing-stub";
1299 fName = stubName(target.getName());
1300 writer.fAllSynthesizedStubs.push_back(this);
1305 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
1306 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1308 writer.fAllSynthesizedStubs.push_back(this);
1310 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target);
1311 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
1314 template <typename A>
1315 const char* StubAtom<A>::stubName(const char* name)
1318 asprintf(&buf, "%s$stub", name);
1323 uint64_t StubAtom<ppc>::getSize() const
1325 return ( pic() ? 32 : 16 );
1329 uint64_t StubAtom<ppc64>::getSize() const
1331 return ( pic() ? 32 : 16 );
1335 uint64_t StubAtom<x86>::getSize() const
1341 uint64_t StubAtom<x86_64>::getSize() const
1347 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
1349 // special case x86 fast stubs to be byte aligned
1354 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
1357 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
1358 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
1359 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
1360 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
1361 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
1362 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
1363 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
1364 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
1367 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
1368 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
1369 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
1370 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
1375 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
1378 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
1379 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
1380 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
1381 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
1382 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
1383 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
1384 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
1385 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
1388 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
1389 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
1390 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
1391 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
1396 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
1398 if ( fWriter.fOptions.prebind() ) {
1399 uint32_t address = this->getAddress();
1400 int32_t rel32 = 0 - (address+5);
1402 buffer[1] = rel32 & 0xFF;
1403 buffer[2] = (rel32 >> 8) & 0xFF;
1404 buffer[3] = (rel32 >> 16) & 0xFF;
1405 buffer[4] = (rel32 >> 24) & 0xFF;
1417 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1419 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
1427 // x86_64 stubs are 7 bytes and need no alignment
1429 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
1435 const char* StubAtom<ppc>::getSectionName() const
1437 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
1441 const char* StubAtom<ppc64>::getSectionName() const
1443 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
1447 const char* StubAtom<x86>::getSectionName() const
1449 return "__jump_table";
1455 struct AtomByNameSorter
1457 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
1459 return (strcmp(left->getName(), right->getName()) < 0);
1463 template <typename P>
1464 struct ExternalRelocSorter
1466 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
1468 // sort first by symbol number
1469 if ( left.r_symbolnum() != right.r_symbolnum() )
1470 return (left.r_symbolnum() < right.r_symbolnum());
1471 // then sort all uses of the same symbol by address
1472 return (left.r_address() < right.r_address());
1477 template <typename A>
1478 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
1479 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
1480 fLoadCommandsSegment(NULL), fPadSegmentInfo(NULL), fSplitCodeToDataContentAtom(NULL), fModuleInfoAtom(NULL),
1481 fPageZeroAtom(NULL), fSymbolTableCount(0), fLargestAtomSize(1),
1482 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
1483 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false), fSlideable(false),
1484 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
1486 // for UNIX conformance, error if file exists and is not writable
1487 if ( (access(path, F_OK) == 0) && (access(path, W_OK) == -1) )
1488 throwf("can't write output file: %s", path);
1490 int permissions = 0777;
1491 if ( fOptions.outputKind() == Options::kObjectFile )
1493 // Calling unlink first assures the file is gone so that open creates it with correct permissions
1494 // It also handles the case where fFilePath file is not writable but its directory is
1495 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
1496 (void)unlink(fFilePath);
1497 fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
1498 if ( fFileDescriptor == -1 ) {
1499 throwf("can't open output file for writing: %s", path);
1502 switch ( fOptions.outputKind() ) {
1503 case Options::kDynamicExecutable:
1504 case Options::kStaticExecutable:
1505 if ( fOptions.zeroPageSize() != 0 )
1506 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
1507 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1508 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1509 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1510 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1511 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1512 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1513 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1514 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1515 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1516 if ( fOptions.hasCustomStack() )
1517 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
1518 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1519 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1520 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1521 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1522 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1523 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1524 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1526 case Options::kDynamicLibrary:
1527 case Options::kDynamicBundle:
1528 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1530 case Options::kObjectFile:
1531 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1532 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1533 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
1534 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
1535 if ( fOptions.initFunctionName() != NULL )
1536 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
1538 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1539 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1540 if ( fOptions.sharedRegionEligible() )
1541 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
1542 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1543 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1544 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1545 if ( fOptions.sharedRegionEligible() ) {
1546 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
1548 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1549 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1550 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1551 if ( this->needsModuleTable() )
1552 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
1553 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1555 case Options::kDyld:
1556 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1557 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1558 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1559 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1560 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1561 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1562 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1563 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1564 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1565 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1566 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1567 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1568 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1572 // add extra commmands
1573 bool hasReExports = false;
1574 uint8_t ordinal = 1;
1575 switch ( fOptions.outputKind() ) {
1576 case Options::kDynamicExecutable:
1577 case Options::kDynamicLibrary:
1578 case Options::kDynamicBundle:
1580 // add dylib load command atoms for all dynamic libraries
1581 const unsigned int libCount = dynamicLibraries.size();
1582 for (unsigned int i=0; i < libCount; ++i) {
1583 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
1584 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
1586 if ( dylibInfo.options.fReExport ) {
1587 hasReExports = true;
1590 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
1591 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
1592 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
1593 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
1594 hasReExports = true;
1598 if ( dylibInfo.options.fBundleLoader ) {
1599 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
1602 // see if a DylibLoadCommandsAtom has already been created for this install path
1603 bool newDylib = true;
1604 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
1605 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
1606 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
1607 if ( !seenDylibInfo.options.fBundleLoader ) {
1608 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
1609 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
1610 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
1611 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
1612 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
1620 // assign new ordinal and check for other paired load commands
1621 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
1622 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
1623 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
1624 fWriterSynthesizedAtoms.push_back(dyliblc);
1625 if ( dylibInfo.options.fReExport
1626 && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
1627 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
1628 // see if child has sub-framework that is this
1629 bool isSubFramework = false;
1630 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
1631 if ( childInUmbrella != NULL ) {
1632 const char* myLeaf = strrchr(fOptions.installPath(), '/');
1633 if ( myLeaf != NULL ) {
1634 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
1635 isSubFramework = true;
1638 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
1639 if ( ! isSubFramework ) {
1640 // this dylib also needs a sub_x load command
1641 bool isFrameworkReExport = false;
1642 const char* lastSlash = strrchr(dylibInstallPath, '/');
1643 if ( lastSlash != NULL ) {
1644 char frameworkName[strlen(lastSlash)+20];
1645 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
1646 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
1648 if ( isFrameworkReExport ) {
1649 // needs a LC_SUB_UMBRELLA command
1650 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
1653 // needs a LC_SUB_LIBRARY command
1654 const char* nameStart = &lastSlash[1];
1655 if ( lastSlash == NULL )
1656 nameStart = dylibInstallPath;
1657 int len = strlen(nameStart);
1658 const char* dot = strchr(nameStart, '.');
1660 len = dot - nameStart;
1661 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
1668 // add umbrella command if needed
1669 if ( fOptions.umbrellaName() != NULL ) {
1670 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
1672 // add allowable client commands if used
1673 std::vector<const char*>& allowableClients = fOptions.allowableClients();
1674 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
1675 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
1678 case Options::kStaticExecutable:
1679 case Options::kObjectFile:
1680 case Options::kDyld:
1683 fNoReExportedDylibs = !hasReExports;
1685 // add any rpath load commands
1686 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
1687 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
1690 // set up fSlideable
1691 switch ( fOptions.outputKind() ) {
1692 case Options::kObjectFile:
1693 case Options::kStaticExecutable:
1696 case Options::kDynamicExecutable:
1697 fSlideable = fOptions.positionIndependentExecutable();
1699 case Options::kDyld:
1700 case Options::kDynamicLibrary:
1701 case Options::kDynamicBundle:
1706 //fprintf(stderr, "ordinals table:\n");
1707 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1708 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
1712 template <typename A>
1713 Writer<A>::~Writer()
1715 if ( fFilePath != NULL )
1716 free((void*)fFilePath);
1717 if ( fSymbolTable != NULL )
1718 delete [] fSymbolTable;
1722 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
1723 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
1724 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
1727 template <typename A>
1728 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
1730 if ( fOptions.outputKind() == Options::kObjectFile ) {
1731 // when doing -r -exported_symbols_list, don't creat proxy for a symbol
1732 // that is supposed to be exported. We want an error instead
1733 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
1734 if ( fOptions.hasExportRestrictList() && fOptions.shouldExport(name) )
1737 return new UndefinedSymbolProxyAtom<A>(*this, name);
1739 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
1740 return new UndefinedSymbolProxyAtom<A>(*this, name);
1745 template <typename A>
1746 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
1748 // flat namespace images use zero for all ordinals
1749 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
1752 // is an UndefinedSymbolProxyAtom
1754 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
1755 return DYNAMIC_LOOKUP_ORDINAL;
1757 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
1758 if ( pos != fLibraryToOrdinal.end() )
1761 throw "can't find ordinal for imported symbol";
1764 template <typename A>
1765 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
1767 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
1771 template <typename A>
1772 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
1773 std::vector<class ObjectFile::Reader::Stab>& stabs,
1774 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
1775 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
1776 bool biggerThanTwoGigs)
1780 fEntryPoint = entryPointAtom;
1781 fDyldHelper = dyldHelperAtom;
1782 fCanScatter = canScatter;
1783 fCpuConstraint = cpuConstraint;
1784 fBiggerThanTwoGigs = biggerThanTwoGigs;
1787 // Set for create UUID
1789 fUUIDAtom->generate();
1791 // remove uneeded dylib load commands
1792 optimizeDylibReferences();
1794 // check for mdynamic-no-pic codegen which force code into low 4GB
1795 scanForAbsoluteReferences();
1797 // create inter-library stubs
1800 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
1801 partitionIntoSections();
1803 // segment load command can now be sized and padding can be set
1804 adjustLoadCommandsAndPadding();
1806 // assign each section a file offset
1807 assignFileOffsets();
1809 // if need to add branch islands, reassign file offsets
1810 if ( addBranchIslands() )
1811 assignFileOffsets();
1813 // build symbol table and relocations
1816 // write map file if requested
1820 return writeAtoms();
1822 // clean up if any errors
1823 close(fFileDescriptor);
1824 (void)unlink(fFilePath);
1829 template <typename A>
1830 void Writer<A>::buildLinkEdit()
1832 this->collectExportedAndImportedAndLocalAtoms();
1833 this->buildSymbolTable();
1834 this->buildFixups();
1835 this->adjustLinkEditSections();
1840 template <typename A>
1841 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
1843 return atom->getAddress();
1844 // SectionInfo* info = (SectionInfo*)atom->getSection();
1845 // return info->getBaseAddress() + atom->getSectionOffset();
1850 const char* Writer<x86_64>::symbolTableName(const ObjectFile::Atom* atom)
1852 static unsigned int counter = 0;
1853 const char* name = atom->getName();
1854 if ( strncmp(name, "cstring=", 8) == 0 )
1855 asprintf((char**)&name, "LC%u", counter++);
1859 template <typename A>
1860 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
1862 return atom->getName();
1865 template <typename A>
1866 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1869 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
1872 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
1873 entry->set_n_type(N_EXT | N_ABS);
1876 entry->set_n_type(N_EXT | N_SECT);
1877 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
1878 if ( fOptions.keepPrivateExterns() )
1879 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
1883 // set n_sect (section number of implementation )
1884 uint8_t sectionIndex = atom->getSection()->getIndex();
1885 entry->set_n_sect(sectionIndex);
1887 // the __mh_execute_header is magic and must be an absolute symbol
1888 if ( (sectionIndex==0)
1889 && (fOptions.outputKind() == Options::kDynamicExecutable)
1890 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
1891 entry->set_n_type(N_EXT | N_ABS);
1895 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1896 desc |= REFERENCED_DYNAMICALLY;
1897 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
1899 fHasWeakExports = true;
1901 entry->set_n_desc(desc);
1903 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1904 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
1905 entry->set_n_value(atom->getSectionOffset());
1907 entry->set_n_value(this->getAtomLoadAddress(atom));
1910 template <typename A>
1911 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1914 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
1917 if ( (fOptions.outputKind() == Options::kObjectFile)
1918 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
1919 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
1920 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
1921 else if ( fOptions.prebind() )
1922 entry->set_n_type(N_PBUD | N_EXT);
1924 entry->set_n_type(N_UNDF | N_EXT);
1927 entry->set_n_sect(0);
1930 if ( fOptions.outputKind() != Options::kObjectFile ) {
1931 // set n_desc ( high byte is library ordinal, low byte is reference type )
1932 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
1933 if ( pos != fStubsMap.end() )
1934 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
1936 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
1938 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
1939 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
1940 SET_LIBRARY_ORDINAL(desc, ordinal);
1942 catch (const char* msg) {
1943 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
1946 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
1947 uint8_t align = atom->getAlignment().powerOf2;
1948 // if alignment does not match size, then record the custom alignment
1949 if ( align != __builtin_ctz(atom->getSize()) )
1950 SET_COMM_ALIGN(desc, align);
1952 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1953 desc |= REFERENCED_DYNAMICALLY;
1954 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1955 desc |= N_REF_TO_WEAK;
1956 fReferencesWeakImports = true;
1958 // set weak_import attribute
1959 if ( fWeakImportMap[atom] )
1961 entry->set_n_desc(desc);
1963 // set n_value, zero for import proxy and size for tentative definition
1964 entry->set_n_value(atom->getSize());
1968 template <typename A>
1969 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1972 const char* symbolName = this->symbolTableName(atom);
1974 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
1975 sprintf(anonName, "l%u", fAnonNameIndex++);
1976 symbolName = anonName;
1978 entry->set_n_strx(this->fStringsAtom->add(symbolName));
1981 uint8_t type = N_SECT;
1982 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
1984 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
1986 entry->set_n_type(type);
1988 // set n_sect (section number of implementation )
1989 uint8_t sectIndex = atom->getSection()->getIndex();
1990 if ( sectIndex == 0 ) {
1991 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
1992 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
1995 entry->set_n_sect(sectIndex);
1999 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2001 entry->set_n_desc(desc);
2003 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2004 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2005 entry->set_n_value(atom->getSectionOffset());
2007 entry->set_n_value(this->getAtomLoadAddress(atom));
2011 template <typename A>
2012 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
2014 macho_nlist<P> entry;
2017 entry.set_n_strx(fStringsAtom->add(name));
2020 entry.set_n_type(N_SECT);
2022 // set n_sect (section number of implementation )
2023 entry.set_n_sect(atom.getSection()->getIndex());
2026 entry.set_n_desc(0);
2028 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2029 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
2032 fLocalExtraLabels.push_back(entry);
2037 template <typename A>
2038 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
2040 macho_nlist<P> entry;
2043 entry.set_n_strx(fStringsAtom->add(name));
2046 entry.set_n_type(N_SECT|N_EXT);
2048 // set n_sect (section number of implementation )
2049 entry.set_n_sect(atom.getSection()->getIndex());
2052 entry.set_n_desc(0);
2054 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2055 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
2058 fGlobalExtraLabels.push_back(entry);
2061 template <typename A>
2062 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
2064 macho_nlist<P>* entry = &fSymbolTable[startIndex];
2065 for (uint32_t i=0; i < count; ++i, ++entry) {
2066 ObjectFile::Atom* atom = atoms[i];
2067 if ( &atoms == &fExportedAtoms ) {
2068 this->setExportNlist(atom, entry);
2070 else if ( &atoms == &fImportedAtoms ) {
2071 this->setImportNlist(atom, entry);
2074 this->setLocalNlist(atom, entry);
2079 template <typename A>
2080 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
2082 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
2083 fSymbolTable[startIndex++] = *it;
2087 template <typename A>
2088 struct NListNameSorter
2090 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
2092 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
2094 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
2097 StringsLinkEditAtom<A>* fStringPool;
2101 template <typename A>
2102 void Writer<A>::buildSymbolTable()
2104 fSymbolTableStabsStartIndex = 0;
2105 fSymbolTableStabsCount = fStabs->size();
2106 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
2107 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
2108 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
2109 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
2110 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
2111 fSymbolTableImportCount = fImportedAtoms.size();
2113 // allocate symbol table
2114 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
2115 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
2117 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
2118 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
2119 if ( fLocalExtraLabels.size() != 0 )
2120 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
2121 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
2122 if ( fGlobalExtraLabels.size() != 0 ) {
2123 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
2124 // re-sort combined range
2125 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
2126 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
2127 NListNameSorter<A>(fStringsAtom) );
2129 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
2130 addStabs(fSymbolTableStabsStartIndex);
2132 // set up module table
2133 if ( fModuleInfoAtom != NULL )
2134 fModuleInfoAtom->setName();
2139 template <typename A>
2140 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
2142 switch ( atom.getSymbolTableInclusion() ) {
2143 case ObjectFile::Atom::kSymbolTableNotIn:
2145 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
2147 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
2148 case ObjectFile::Atom::kSymbolTableIn:
2149 switch ( atom.getScope() ) {
2150 case ObjectFile::Atom::scopeGlobal:
2152 case ObjectFile::Atom::scopeLinkageUnit:
2153 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
2162 template <typename A>
2163 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
2165 const int atomCount = fAllAtoms->size();
2166 // guess at sizes of each bucket to minimize re-allocations
2167 fImportedAtoms.reserve(100);
2168 fExportedAtoms.reserve(atomCount/2);
2169 fLocalSymbolAtoms.reserve(atomCount);
2170 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2171 ObjectFile::Atom* atom = *it;
2172 // only named atoms go in symbol table
2173 if ( atom->getName() != NULL ) {
2174 // put atom into correct bucket: imports, exports, locals
2175 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
2176 switch ( atom->getDefinitionKind() ) {
2177 case ObjectFile::Atom::kExternalDefinition:
2178 case ObjectFile::Atom::kExternalWeakDefinition:
2179 fImportedAtoms.push_back(atom);
2181 case ObjectFile::Atom::kTentativeDefinition:
2182 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
2183 fImportedAtoms.push_back(atom);
2187 case ObjectFile::Atom::kRegularDefinition:
2188 case ObjectFile::Atom::kWeakDefinition:
2189 case ObjectFile::Atom::kAbsoluteSymbol:
2190 if ( this->shouldExport(*atom) )
2191 fExportedAtoms.push_back(atom);
2192 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
2193 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
2194 fLocalSymbolAtoms.push_back(atom);
2198 // when geneating a .o file, dtrace static probes become local labels
2199 if ( fOptions.outputKind() == Options::kObjectFile) {
2200 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2201 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2202 ObjectFile::Reference* ref = *rit;
2203 if ( ref->getKind() == A::kDtraceProbe ) {
2204 // dtrace probe points to be add back into generated .o file
2205 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
2209 // when linking kernel, old style dtrace static probes become global labels
2210 else if ( fOptions.outputKind() == Options::kStaticExecutable ) {
2211 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2212 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2213 ObjectFile::Reference* ref = *rit;
2214 if ( ref->getKind() == A::kDtraceProbe ) {
2215 // dtrace probe points to be add back into generated .o file
2216 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
2222 // sort exported atoms by name
2223 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
2224 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
2225 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
2229 template <typename A>
2230 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
2232 switch ( stab.type ) {
2234 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
2235 // end of function N_FUN has size
2236 return stab.atom->getSize();
2239 // start of function N_FUN has address
2240 return getAtomLoadAddress(stab.atom);
2245 if ( stab.atom == NULL )
2246 // some weird assembly files have slines not associated with a function
2249 // all these stab types need their value changed from an offset in the atom to an address
2250 return getAtomLoadAddress(stab.atom) + stab.value;
2254 // all these need address of atom
2255 return getAtomLoadAddress(stab.atom);;
2257 return stab.atom->getSize();
2259 if ( stab.atom == NULL ) {
2263 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
2264 // end of translation unit N_SO has address of end of last atom
2265 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
2268 // start of translation unit N_SO has address of end of first atom
2269 return getAtomLoadAddress(stab.atom);
2278 template <typename A>
2279 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
2281 switch (stab.type) {
2283 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
2284 return this->fStringsAtom->emptyString();
2287 // fall into uniquing case
2291 return this->fStringsAtom->addUnique(stab.string);
2294 if ( stab.string == NULL )
2296 else if ( stab.string[0] == '\0' )
2297 return this->fStringsAtom->emptyString();
2299 return this->fStringsAtom->add(stab.string);
2304 template <typename A>
2305 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
2307 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
2308 if ( stab.type == N_FUN )
2310 else if ( stab.atom != NULL )
2311 return stab.atom->getSection()->getIndex();
2316 template <typename A>
2317 void Writer<A>::addStabs(uint32_t startIndex)
2319 macho_nlist<P>* entry = &fSymbolTable[startIndex];
2320 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
2321 const ObjectFile::Reader::Stab& stab = *it;
2322 entry->set_n_type(stab.type);
2323 entry->set_n_sect(sectionIndexForStab(stab));
2324 entry->set_n_desc(stab.desc);
2325 entry->set_n_value(valueForStab(stab));
2326 entry->set_n_strx(stringOffsetForStab(stab));
2332 template <typename A>
2333 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
2337 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
2339 return i + fSymbolTableImportStartIndex;
2345 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
2347 return i + fSymbolTableLocalStartIndex;
2353 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
2355 return i + fSymbolTableExportStartIndex;
2359 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
2364 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
2366 switch ( target.getSymbolTableInclusion() ) {
2367 case ObjectFile::Atom::kSymbolTableNotIn:
2369 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
2370 case ObjectFile::Atom::kSymbolTableIn:
2371 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
2377 template <typename A>
2378 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
2380 switch ( target.getDefinitionKind() ) {
2381 case ObjectFile::Atom::kRegularDefinition:
2382 case ObjectFile::Atom::kWeakDefinition:
2383 case ObjectFile::Atom::kAbsoluteSymbol:
2385 case ObjectFile::Atom::kTentativeDefinition:
2386 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
2387 case ObjectFile::Atom::kExternalDefinition:
2388 case ObjectFile::Atom::kExternalWeakDefinition:
2389 return shouldExport(target);
2394 template <typename A>
2395 void Writer<A>::buildFixups()
2397 if ( fOptions.outputKind() == Options::kObjectFile ) {
2398 this->buildObjectFileFixups();
2401 if ( fOptions.keepRelocations() )
2402 this->buildObjectFileFixups();
2403 this->buildExecutableFixups();
2408 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2410 ObjectFile::Atom& target = ref->getTarget();
2411 bool external = this->makesExternalRelocatableReference(target);
2412 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
2413 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2414 macho_relocation_info<P> reloc1;
2415 macho_relocation_info<P> reloc2;
2416 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
2419 case x86_64::kNoFixUp:
2420 case x86_64::kFollowOn:
2423 case x86_64::kPointer:
2424 case x86_64::kPointerWeakImport:
2425 reloc1.set_r_address(address);
2426 reloc1.set_r_symbolnum(symbolIndex);
2427 reloc1.set_r_pcrel(false);
2428 reloc1.set_r_length(3);
2429 reloc1.set_r_extern(external);
2430 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2431 fSectionRelocs.push_back(reloc1);
2434 case x86_64::kPointerDiff32:
2435 case x86_64::kPointerDiff:
2437 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2438 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2439 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
2440 reloc1.set_r_address(address);
2441 reloc1.set_r_symbolnum(symbolIndex);
2442 reloc1.set_r_pcrel(false);
2443 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2444 reloc1.set_r_extern(external);
2445 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2446 reloc2.set_r_address(address);
2447 reloc2.set_r_symbolnum(fromSymbolIndex);
2448 reloc2.set_r_pcrel(false);
2449 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2450 reloc2.set_r_extern(fromExternal);
2451 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
2452 fSectionRelocs.push_back(reloc1);
2453 fSectionRelocs.push_back(reloc2);
2457 case x86_64::kBranchPCRel32:
2458 case x86_64::kBranchPCRel32WeakImport:
2459 case x86_64::kDtraceProbeSite:
2460 case x86_64::kDtraceIsEnabledSite:
2461 reloc1.set_r_address(address);
2462 reloc1.set_r_symbolnum(symbolIndex);
2463 reloc1.set_r_pcrel(true);
2464 reloc1.set_r_length(2);
2465 reloc1.set_r_extern(external);
2466 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2467 fSectionRelocs.push_back(reloc1);
2470 case x86_64::kPCRel32:
2471 reloc1.set_r_address(address);
2472 reloc1.set_r_symbolnum(symbolIndex);
2473 reloc1.set_r_pcrel(true);
2474 reloc1.set_r_length(2);
2475 reloc1.set_r_extern(external);
2476 reloc1.set_r_type(X86_64_RELOC_SIGNED);
2477 fSectionRelocs.push_back(reloc1);
2480 case x86_64::kPCRel32_1:
2481 reloc1.set_r_address(address);
2482 reloc1.set_r_symbolnum(symbolIndex);
2483 reloc1.set_r_pcrel(true);
2484 reloc1.set_r_length(2);
2485 reloc1.set_r_extern(external);
2486 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
2487 fSectionRelocs.push_back(reloc1);
2490 case x86_64::kPCRel32_2:
2491 reloc1.set_r_address(address);
2492 reloc1.set_r_symbolnum(symbolIndex);
2493 reloc1.set_r_pcrel(true);
2494 reloc1.set_r_length(2);
2495 reloc1.set_r_extern(external);
2496 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
2497 fSectionRelocs.push_back(reloc1);
2500 case x86_64::kPCRel32_4:
2501 reloc1.set_r_address(address);
2502 reloc1.set_r_symbolnum(symbolIndex);
2503 reloc1.set_r_pcrel(true);
2504 reloc1.set_r_length(2);
2505 reloc1.set_r_extern(external);
2506 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
2507 fSectionRelocs.push_back(reloc1);
2510 case x86_64::kPCRel32GOT:
2511 case x86_64::kPCRel32GOTWeakImport:
2512 reloc1.set_r_address(address);
2513 reloc1.set_r_symbolnum(symbolIndex);
2514 reloc1.set_r_pcrel(true);
2515 reloc1.set_r_length(2);
2516 reloc1.set_r_extern(external);
2517 reloc1.set_r_type(X86_64_RELOC_GOT);
2518 fSectionRelocs.push_back(reloc1);
2521 case x86_64::kPCRel32GOTLoad:
2522 case x86_64::kPCRel32GOTLoadWeakImport:
2523 reloc1.set_r_address(address);
2524 reloc1.set_r_symbolnum(symbolIndex);
2525 reloc1.set_r_pcrel(true);
2526 reloc1.set_r_length(2);
2527 reloc1.set_r_extern(external);
2528 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
2529 fSectionRelocs.push_back(reloc1);
2532 case x86_64::kDtraceTypeReference:
2533 case x86_64::kDtraceProbe:
2534 // generates no relocs
2542 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2544 ObjectFile::Atom& target = ref->getTarget();
2545 bool isExtern = this->makesExternalRelocatableReference(target);
2546 uint32_t symbolIndex = 0;
2548 symbolIndex = this->symbolIndex(target);
2549 uint32_t sectionNum = target.getSection()->getIndex();
2550 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2551 macho_relocation_info<P> reloc1;
2552 macho_relocation_info<P> reloc2;
2553 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2554 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2555 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
2557 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2558 fprintf(stderr, "ld: warning section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s\n",
2559 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2564 case x86::kFollowOn:
2568 case x86::kPointerWeakImport:
2569 case x86::kAbsolute32:
2570 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2571 // use scattered reloc is target offset is non-zero
2572 sreloc1->set_r_scattered(true);
2573 sreloc1->set_r_pcrel(false);
2574 sreloc1->set_r_length(2);
2575 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2576 sreloc1->set_r_address(address);
2577 sreloc1->set_r_value(target.getAddress());
2580 reloc1.set_r_address(address);
2581 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2582 reloc1.set_r_pcrel(false);
2583 reloc1.set_r_length(2);
2584 reloc1.set_r_extern(isExtern);
2585 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2587 fSectionRelocs.push_back(reloc1);
2590 case x86::kPointerDiff16:
2591 case x86::kPointerDiff:
2593 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2594 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
2595 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
2596 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
2597 sreloc1->set_r_scattered(true);
2598 sreloc1->set_r_pcrel(false);
2599 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2600 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2601 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
2603 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
2604 sreloc1->set_r_address(address);
2605 sreloc1->set_r_value(target.getAddress());
2606 sreloc2->set_r_scattered(true);
2607 sreloc2->set_r_pcrel(false);
2608 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2609 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
2610 sreloc2->set_r_address(0);
2611 //if ( &ref->getFromTarget() == &ref->getTarget() )
2612 sreloc2->set_r_value(ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
2614 // sreloc2->set_r_value(ref->getFromTarget().getAddress());
2615 fSectionRelocs.push_back(reloc2);
2616 fSectionRelocs.push_back(reloc1);
2620 case x86::kPCRel32WeakImport:
2623 case x86::kDtraceProbeSite:
2624 case x86::kDtraceIsEnabledSite:
2625 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2626 // use scattered reloc is target offset is non-zero
2627 sreloc1->set_r_scattered(true);
2628 sreloc1->set_r_pcrel(true);
2629 sreloc1->set_r_length( (kind==x86::kPCRel16) ? 1 : 2);
2630 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2631 sreloc1->set_r_address(address);
2632 sreloc1->set_r_value(target.getAddress());
2635 reloc1.set_r_address(address);
2636 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2637 reloc1.set_r_pcrel(true);
2638 reloc1.set_r_length( (kind==x86::kPCRel16) ? 1 : 2);
2639 reloc1.set_r_extern(isExtern);
2640 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2642 fSectionRelocs.push_back(reloc1);
2645 case x86::kDtraceTypeReference:
2646 case x86::kDtraceProbe:
2647 // generates no relocs
2657 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
2658 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
2659 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
2660 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
2664 uint8_t Writer<ppc>::getRelocPointerSize()
2670 uint8_t Writer<ppc64>::getRelocPointerSize()
2676 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2678 return addObjectRelocs_powerpc(atom, ref);
2682 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2684 return addObjectRelocs_powerpc(atom, ref);
2688 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
2689 // they use a common addObjectRelocs_powerpc() method.
2691 template <typename A>
2692 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2694 ObjectFile::Atom& target = ref->getTarget();
2695 bool isExtern = this->makesExternalRelocatableReference(target);
2696 uint32_t symbolIndex = 0;
2698 symbolIndex = this->symbolIndex(target);
2699 uint32_t sectionNum = target.getSection()->getIndex();
2700 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2701 macho_relocation_info<P> reloc1;
2702 macho_relocation_info<P> reloc2;
2703 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2704 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2705 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
2713 case A::kPointerWeakImport:
2714 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
2715 // use scattered reloc is target offset is outside target
2716 sreloc1->set_r_scattered(true);
2717 sreloc1->set_r_pcrel(false);
2718 sreloc1->set_r_length(getRelocPointerSize());
2719 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2720 sreloc1->set_r_address(address);
2721 sreloc1->set_r_value(target.getAddress());
2724 reloc1.set_r_address(address);
2726 reloc1.set_r_symbolnum(symbolIndex);
2728 reloc1.set_r_symbolnum(sectionNum);
2729 reloc1.set_r_pcrel(false);
2730 reloc1.set_r_length(getRelocPointerSize());
2731 reloc1.set_r_extern(isExtern);
2732 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2734 fSectionRelocs.push_back(reloc1);
2737 case A::kPointerDiff16:
2738 case A::kPointerDiff32:
2739 case A::kPointerDiff64:
2741 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2742 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2743 sreloc1->set_r_scattered(true);
2744 sreloc1->set_r_pcrel(false);
2745 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
2746 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
2747 sreloc1->set_r_address(address);
2748 sreloc1->set_r_value(toAddr);
2749 sreloc2->set_r_scattered(true);
2750 sreloc2->set_r_pcrel(false);
2751 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
2752 sreloc2->set_r_type(PPC_RELOC_PAIR);
2753 sreloc2->set_r_address(0);
2754 sreloc2->set_r_value(fromAddr);
2755 fSectionRelocs.push_back(reloc2);
2756 fSectionRelocs.push_back(reloc1);
2760 case A::kBranch24WeakImport:
2762 case A::kDtraceProbeSite:
2763 case A::kDtraceIsEnabledSite:
2764 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2765 reloc1.set_r_address(address);
2767 reloc1.set_r_symbolnum(symbolIndex);
2769 reloc1.set_r_symbolnum(sectionNum);
2770 reloc1.set_r_pcrel(true);
2771 reloc1.set_r_length(2);
2772 reloc1.set_r_type(PPC_RELOC_BR24);
2773 reloc1.set_r_extern(isExtern);
2776 sreloc1->set_r_scattered(true);
2777 sreloc1->set_r_pcrel(true);
2778 sreloc1->set_r_length(2);
2779 sreloc1->set_r_type(PPC_RELOC_BR24);
2780 sreloc1->set_r_address(address);
2781 sreloc1->set_r_value(target.getAddress());
2783 fSectionRelocs.push_back(reloc1);
2787 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2788 reloc1.set_r_address(address);
2790 reloc1.set_r_symbolnum(symbolIndex);
2792 reloc1.set_r_symbolnum(sectionNum);
2793 reloc1.set_r_pcrel(true);
2794 reloc1.set_r_length(2);
2795 reloc1.set_r_type(PPC_RELOC_BR14);
2796 reloc1.set_r_extern(isExtern);
2799 sreloc1->set_r_scattered(true);
2800 sreloc1->set_r_pcrel(true);
2801 sreloc1->set_r_length(2);
2802 sreloc1->set_r_type(PPC_RELOC_BR14);
2803 sreloc1->set_r_address(address);
2804 sreloc1->set_r_value(target.getAddress());
2806 fSectionRelocs.push_back(reloc1);
2809 case A::kPICBaseLow16:
2810 case A::kPICBaseLow14:
2812 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2813 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2814 sreloc1->set_r_scattered(true);
2815 sreloc1->set_r_pcrel(false);
2816 sreloc1->set_r_length(2);
2817 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
2818 sreloc1->set_r_address(address);
2819 sreloc1->set_r_value(target.getAddress());
2820 sreloc2->set_r_scattered(true);
2821 sreloc2->set_r_pcrel(false);
2822 sreloc2->set_r_length(2);
2823 sreloc2->set_r_type(PPC_RELOC_PAIR);
2824 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
2825 sreloc2->set_r_value(fromAddr);
2826 fSectionRelocs.push_back(reloc2);
2827 fSectionRelocs.push_back(reloc1);
2831 case A::kPICBaseHigh16:
2833 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2834 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2835 sreloc1->set_r_scattered(true);
2836 sreloc1->set_r_pcrel(false);
2837 sreloc1->set_r_length(2);
2838 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
2839 sreloc1->set_r_address(address);
2840 sreloc1->set_r_value(target.getAddress());
2841 sreloc2->set_r_scattered(true);
2842 sreloc2->set_r_pcrel(false);
2843 sreloc2->set_r_length(2);
2844 sreloc2->set_r_type(PPC_RELOC_PAIR);
2845 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
2846 sreloc2->set_r_value(fromAddr);
2847 fSectionRelocs.push_back(reloc2);
2848 fSectionRelocs.push_back(reloc1);
2855 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2856 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2857 reloc1.set_r_address(address);
2859 reloc1.set_r_symbolnum(symbolIndex);
2861 reloc1.set_r_symbolnum(sectionNum);
2862 reloc1.set_r_pcrel(false);
2863 reloc1.set_r_length(2);
2864 reloc1.set_r_extern(isExtern);
2865 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2868 sreloc1->set_r_scattered(true);
2869 sreloc1->set_r_pcrel(false);
2870 sreloc1->set_r_length(2);
2871 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2872 sreloc1->set_r_address(address);
2873 sreloc1->set_r_value(target.getAddress());
2876 reloc2.set_r_address(ref->getTargetOffset() >> 16);
2878 reloc2.set_r_address(toAddr >> 16);
2879 reloc2.set_r_symbolnum(0);
2880 reloc2.set_r_pcrel(false);
2881 reloc2.set_r_length(2);
2882 reloc2.set_r_extern(false);
2883 reloc2.set_r_type(PPC_RELOC_PAIR);
2884 fSectionRelocs.push_back(reloc2);
2885 fSectionRelocs.push_back(reloc1);
2891 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2892 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2893 reloc1.set_r_address(address);
2895 reloc1.set_r_symbolnum(symbolIndex);
2897 reloc1.set_r_symbolnum(sectionNum);
2898 reloc1.set_r_pcrel(false);
2899 reloc1.set_r_length(2);
2900 reloc1.set_r_extern(isExtern);
2901 reloc1.set_r_type(PPC_RELOC_HI16);
2904 sreloc1->set_r_scattered(true);
2905 sreloc1->set_r_pcrel(false);
2906 sreloc1->set_r_length(2);
2907 sreloc1->set_r_type(PPC_RELOC_HI16);
2908 sreloc1->set_r_address(address);
2909 sreloc1->set_r_value(target.getAddress());
2912 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2914 reloc2.set_r_address(toAddr & 0xFFFF);
2915 reloc2.set_r_symbolnum(0);
2916 reloc2.set_r_pcrel(false);
2917 reloc2.set_r_length(2);
2918 reloc2.set_r_extern(false);
2919 reloc2.set_r_type(PPC_RELOC_PAIR);
2920 fSectionRelocs.push_back(reloc2);
2921 fSectionRelocs.push_back(reloc1);
2925 case A::kAbsHigh16AddLow:
2927 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2928 uint32_t overflow = 0;
2929 if ( (toAddr & 0x00008000) != 0 )
2931 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2932 reloc1.set_r_address(address);
2934 reloc1.set_r_symbolnum(symbolIndex);
2936 reloc1.set_r_symbolnum(sectionNum);
2937 reloc1.set_r_pcrel(false);
2938 reloc1.set_r_length(2);
2939 reloc1.set_r_extern(isExtern);
2940 reloc1.set_r_type(PPC_RELOC_HA16);
2943 sreloc1->set_r_scattered(true);
2944 sreloc1->set_r_pcrel(false);
2945 sreloc1->set_r_length(2);
2946 sreloc1->set_r_type(PPC_RELOC_HA16);
2947 sreloc1->set_r_address(address);
2948 sreloc1->set_r_value(target.getAddress());
2951 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2953 reloc2.set_r_address(toAddr & 0xFFFF);
2954 reloc2.set_r_symbolnum(0);
2955 reloc2.set_r_pcrel(false);
2956 reloc2.set_r_length(2);
2957 reloc2.set_r_extern(false);
2958 reloc2.set_r_type(PPC_RELOC_PAIR);
2959 fSectionRelocs.push_back(reloc2);
2960 fSectionRelocs.push_back(reloc1);
2964 case A::kDtraceTypeReference:
2965 case A::kDtraceProbe:
2966 // generates no relocs
2975 // There are cases when an entry in the indirect symbol table is the magic value
2976 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
2977 // the content of the corresponding part of the __nl_symbol_pointer section
2978 // must also change.
2980 template <typename A>
2981 bool Writer<A>::indirectSymbolIsLocal(const ObjectFile::Reference* ref) const
2983 // use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
2984 return ( !this->shouldExport(ref->getTarget()) || (ref->getTargetOffset() != 0) );
2988 template <typename A>
2989 void Writer<A>::buildObjectFileFixups()
2991 uint32_t relocIndex = 0;
2992 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2993 const int segCount = segmentInfos.size();
2994 for(int i=0; i < segCount; ++i) {
2995 SegmentInfo* curSegment = segmentInfos[i];
2996 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2997 const int sectionCount = sectionInfos.size();
2998 for(int j=0; j < sectionCount; ++j) {
2999 SectionInfo* curSection = sectionInfos[j];
3000 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
3001 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3002 if ( ! curSection->fAllZeroFill ) {
3003 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
3004 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3005 curSection->fRelocOffset = relocIndex;
3006 const int atomCount = sectionAtoms.size();
3007 for (int k=0; k < atomCount; ++k) {
3008 ObjectFile::Atom* atom = sectionAtoms[k];
3009 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
3010 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3011 const int refCount = refs.size();
3012 for (int l=0; l < refCount; ++l) {
3013 ObjectFile::Reference* ref = refs[l];
3014 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
3015 uint32_t offsetInSection = atom->getSectionOffset();
3016 uint32_t indexInSection = offsetInSection / atom->getSize();
3017 uint32_t undefinedSymbolIndex;
3018 if ( curSection->fAllStubs ) {
3019 ObjectFile::Atom& stubTarget =ref->getTarget();
3020 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
3021 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
3022 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
3024 else if ( curSection->fAllNonLazyPointers) {
3025 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3026 if ( this->indirectSymbolIsLocal(ref) )
3027 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3029 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
3032 // should never get here, fAllLazyPointers not used in generated .o files
3033 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3035 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3036 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3037 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
3038 fIndirectTableAtom->fTable.push_back(entry);
3039 if ( curSection->fAllLazyPointers ) {
3040 ObjectFile::Atom& target = ref->getTarget();
3041 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3042 if ( &fromTarget == NULL ) {
3043 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
3046 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3047 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
3048 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
3049 macho_relocation_info<P> reloc1;
3050 reloc1.set_r_address(atom->getSectionOffset());
3051 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
3052 reloc1.set_r_pcrel(false);
3053 reloc1.set_r_length();
3054 reloc1.set_r_extern(isExtern);
3055 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3056 fSectionRelocs.push_back(reloc1);
3060 else if ( curSection->fAllStubs ) {
3061 relocIndex += this->addObjectRelocs(atom, ref);
3064 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
3065 relocIndex += this->addObjectRelocs(atom, ref);
3069 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
3074 // reverse the relocs
3075 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
3077 // now reverse section reloc offsets
3078 for(int i=0; i < segCount; ++i) {
3079 SegmentInfo* curSegment = segmentInfos[i];
3080 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3081 const int sectionCount = sectionInfos.size();
3082 for(int j=0; j < sectionCount; ++j) {
3083 SectionInfo* curSection = sectionInfos[j];
3084 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
3091 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3093 switch ( ref.getKind() ) {
3094 case ppc::kAbsLow16:
3095 case ppc::kAbsLow14:
3096 case ppc::kAbsHigh16:
3097 case ppc::kAbsHigh16AddLow:
3106 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3108 switch ( ref.getKind() ) {
3109 case ppc::kAbsLow16:
3110 case ppc::kAbsLow14:
3111 case ppc::kAbsHigh16:
3112 case ppc::kAbsHigh16AddLow:
3120 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3122 if ( ref.getKind() == x86::kAbsolute32 ) {
3123 switch ( ref.getTarget().getDefinitionKind() ) {
3124 case ObjectFile::Atom::kTentativeDefinition:
3125 case ObjectFile::Atom::kRegularDefinition:
3126 case ObjectFile::Atom::kWeakDefinition:
3127 // illegal in dylibs/bundles, until we support TEXT relocs
3129 case ObjectFile::Atom::kExternalDefinition:
3130 case ObjectFile::Atom::kExternalWeakDefinition:
3131 // illegal until we support TEXT relocs
3133 case ObjectFile::Atom::kAbsoluteSymbol:
3134 // absolute symbbols only allowed in static executables
3135 return ( fOptions.outputKind() != Options::kStaticExecutable);
3142 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3148 template <typename A>
3149 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
3151 switch ( target.getDefinitionKind() ) {
3152 case ObjectFile::Atom::kTentativeDefinition:
3153 case ObjectFile::Atom::kRegularDefinition:
3154 // in main executables, the only way regular symbols are indirected is if -interposable is used
3155 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
3156 if ( this->shouldExport(target) && fOptions.interposable() )
3157 return kRelocExternal;
3158 else if ( fSlideable )
3159 return kRelocInternal;
3163 // for flat-namespace or interposable two-level-namespace
3164 // all references to exported symbols get indirected
3165 else if ( this->shouldExport(target) &&
3166 ((fOptions.nameSpace() == Options::kFlatNameSpace)
3167 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
3168 || fOptions.interposable())
3169 && (target.getName() != NULL)
3170 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
3171 return kRelocExternal;
3172 else if ( fSlideable )
3173 return kRelocInternal;
3176 case ObjectFile::Atom::kWeakDefinition:
3177 // all calls to global weak definitions get indirected
3178 if ( this->shouldExport(target) )
3179 return kRelocExternal;
3180 else if ( fSlideable )
3181 return kRelocInternal;
3184 case ObjectFile::Atom::kExternalDefinition:
3185 case ObjectFile::Atom::kExternalWeakDefinition:
3186 return kRelocExternal;
3187 case ObjectFile::Atom::kAbsoluteSymbol:
3193 template <typename A>
3194 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3196 // for 32-bit architectures, the r_address field in relocs
3197 // for final linked images is the offset from the first segment
3198 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
3199 // or the offset from the first writable segment if built split-seg
3200 if ( fOptions.splitSeg() )
3201 result = address - fFirstWritableSegment->fBaseAddress;
3202 if ( result > 0x7FFFFFFF ) {
3203 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
3204 atom->getDisplayName(), atom->getFile()->getPath());
3210 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3212 // for x86_64, the r_address field in relocs for final linked images
3213 // is the offset from the start address of the first writable segment
3214 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
3215 if ( result > 0xFFFFFFFF ) {
3216 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3217 atom->getDisplayName(), atom->getFile()->getPath());
3223 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3225 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
3226 // the 10.5 dyld, iterprets the r_address as:
3227 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
3228 // 2) an offset from the base address of the first writable segment
3229 // For dyld, r_address is always the offset from the base address
3231 bool badFor10_4 = false;
3232 if ( fWritableSegmentPastFirst4GB ) {
3233 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
3235 result = address - fFirstWritableSegment->fBaseAddress;
3236 if ( result > 0xFFFFFFFF ) {
3237 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3238 atom->getDisplayName(), atom->getFile()->getPath());
3242 result = address - fSegmentInfos[0]->fBaseAddress;
3243 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
3247 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",
3248 atom->getDisplayName(), atom->getFile()->getPath());
3254 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
3255 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3256 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
3257 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3260 template <typename A>
3261 void Writer<A>::buildExecutableFixups()
3263 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
3264 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3265 const int segCount = segmentInfos.size();
3266 for(int i=0; i < segCount; ++i) {
3267 SegmentInfo* curSegment = segmentInfos[i];
3268 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3269 const int sectionCount = sectionInfos.size();
3270 for(int j=0; j < sectionCount; ++j) {
3271 SectionInfo* curSection = sectionInfos[j];
3272 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
3273 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3274 if ( ! curSection->fAllZeroFill ) {
3275 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
3276 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3277 const int atomCount = sectionAtoms.size();
3278 for (int k=0; k < atomCount; ++k) {
3279 ObjectFile::Atom* atom = sectionAtoms[k];
3280 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3281 const int refCount = refs.size();
3282 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
3283 for (int l=0; l < refCount; ++l) {
3284 ObjectFile::Reference* ref = refs[l];
3285 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
3286 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
3287 if ( atom->getSize() != sizeof(pint_t) ) {
3288 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
3290 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
3291 if ( curSection->fAllLazyPointers ) {
3292 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
3294 uint32_t offsetInSection = atom->getSectionOffset();
3295 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
3296 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3297 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
3298 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
3299 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3300 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3301 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
3302 fIndirectTableAtom->fTable.push_back(entry);
3303 if ( curSection->fAllLazyPointers ) {
3304 uint8_t preboundLazyType;
3305 if ( fOptions.prebind() && (fDyldHelper != NULL) && preboundLazyPointerType(&preboundLazyType) ) {
3306 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
3307 macho_scattered_relocation_info<P> pblaReloc;
3308 pblaReloc.set_r_scattered(true);
3309 pblaReloc.set_r_pcrel(false);
3310 pblaReloc.set_r_length();
3311 pblaReloc.set_r_type(preboundLazyType);
3312 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3313 pblaReloc.set_r_value(fDyldHelper->getAddress());
3314 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
3316 else if ( fSlideable ) {
3317 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
3318 macho_relocation_info<P> dyldHelperReloc;
3319 uint32_t sectionNum = 1;
3320 if ( fDyldHelper != NULL )
3321 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
3322 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
3323 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3324 dyldHelperReloc.set_r_symbolnum(sectionNum);
3325 dyldHelperReloc.set_r_pcrel(false);
3326 dyldHelperReloc.set_r_length();
3327 dyldHelperReloc.set_r_extern(false);
3328 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
3329 fInternalRelocs.push_back(dyldHelperReloc);
3333 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
3334 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
3335 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
3336 atom->getDisplayName(), atom->getFile()->getPath());
3338 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
3342 case kRelocInternal:
3344 macho_relocation_info<P> internalReloc;
3345 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
3346 uint32_t sectionNum = sectInfo->getIndex();
3347 // special case _mh_dylib_header and friends which are not in any real section
3348 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
3350 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3351 internalReloc.set_r_symbolnum(sectionNum);
3352 internalReloc.set_r_pcrel(false);
3353 internalReloc.set_r_length();
3354 internalReloc.set_r_extern(false);
3355 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3356 fInternalRelocs.push_back(internalReloc);
3359 case kRelocExternal:
3361 macho_relocation_info<P> externalReloc;
3362 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3363 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
3364 externalReloc.set_r_pcrel(false);
3365 externalReloc.set_r_length();
3366 externalReloc.set_r_extern(true);
3367 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3368 fExternalRelocs.push_back(externalReloc);
3373 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
3374 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
3377 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
3378 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
3379 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
3380 uint32_t offsetInSection = atom->getSectionOffset();
3381 uint32_t indexInSection = offsetInSection / atom->getSize();
3382 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3383 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3384 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
3385 fIndirectTableAtom->fTable.push_back(entry);
3391 if ( fSplitCodeToDataContentAtom != NULL )
3392 fSplitCodeToDataContentAtom->encode();
3397 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3399 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
3400 case ppc::kPICBaseHigh16:
3401 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
3403 case ppc::kPointerDiff32:
3404 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3406 case ppc::kPointerDiff64:
3407 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3411 case ppc::kPointerWeakImport:
3412 case ppc::kPICBaseLow16:
3413 case ppc::kPICBaseLow14:
3417 fprintf(stderr, "ld: warning codegen with reference kind %d in %s prevents image from loading in dyld shared cache\n", ref->getKind(), atom->getDisplayName());
3418 fSplitCodeToDataContentAtom->setCantEncode();
3423 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3425 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
3426 case ppc64::kPICBaseHigh16:
3427 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
3429 case ppc64::kPointerDiff32:
3430 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3432 case ppc64::kPointerDiff64:
3433 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3435 case ppc64::kNoFixUp:
3436 case ppc64::kPointer:
3437 case ppc64::kPointerWeakImport:
3438 case ppc64::kPICBaseLow16:
3439 case ppc64::kPICBaseLow14:
3443 fprintf(stderr, "ld: warning codegen with reference kind %d in %s prevents image from loading in dyld shared cache\n", ref->getKind(), atom->getDisplayName());
3444 fSplitCodeToDataContentAtom->setCantEncode();
3449 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3451 switch ( (x86::ReferenceKinds)ref->getKind() ) {
3452 case x86::kPointerDiff:
3453 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
3454 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
3456 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3460 case x86::kPointerWeakImport:
3464 case x86::kPCRel32WeakImport:
3465 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
3466 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
3467 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
3470 // fall into warning case
3472 fprintf(stderr, "ld: warning codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache\n", atom->getDisplayName(), ref->getFixUpOffset());
3473 fSplitCodeToDataContentAtom->setCantEncode();
3478 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3480 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
3481 case x86_64::kPCRel32:
3482 case x86_64::kPCRel32_1:
3483 case x86_64::kPCRel32_2:
3484 case x86_64::kPCRel32_4:
3485 case x86_64::kPCRel32GOTLoad:
3486 case x86_64::kPCRel32GOTLoadWeakImport:
3487 case x86_64::kPCRel32GOT:
3488 case x86_64::kPCRel32GOTWeakImport:
3489 case x86_64::kPointerDiff32:
3490 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3492 case x86_64::kPointerDiff:
3493 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3495 case x86_64::kNoFixUp:
3496 case x86_64::kPointer:
3500 fprintf(stderr, "ld: warning codegen in %s with kind %d prevents image from loading in dyld shared cache\n", atom->getDisplayName(), ref->getKind());
3501 fSplitCodeToDataContentAtom->setCantEncode();
3506 template <typename A>
3507 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
3509 switch ( to.getDefinitionKind() ) {
3510 case ObjectFile::Atom::kExternalDefinition:
3511 case ObjectFile::Atom::kExternalWeakDefinition:
3512 case ObjectFile::Atom::kAbsoluteSymbol:
3514 case ObjectFile::Atom::kRegularDefinition:
3515 case ObjectFile::Atom::kWeakDefinition:
3516 case ObjectFile::Atom::kTentativeDefinition:
3517 // segments with same permissions slide together
3518 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
3519 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
3521 throw "ld64 internal error";
3526 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
3529 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
3530 for (uint32_t p=from; p < to; p += 4)
3531 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
3535 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
3538 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
3539 for (uint32_t p=from; p < to; p += 4)
3540 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
3544 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
3546 uint8_t x86Nop = 0x90;
3547 for (uint32_t p=from; p < to; ++p)
3548 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
3552 void Writer<x86_64>::writeNoOps(uint32_t from, uint32_t to)
3554 uint8_t x86Nop = 0x90;
3555 for (uint32_t p=from; p < to; ++p)
3556 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
3561 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
3563 for (uint8_t* p=from; p < to; p += 4)
3564 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
3568 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
3570 for (uint8_t* p=from; p < to; p += 4)
3571 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
3575 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
3577 for (uint8_t* p=from; p < to; ++p)
3582 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
3584 for (uint8_t* p=from; p < to; ++p)
3589 static const char* stringName(const char* str)
3591 if ( strncmp(str, "cstring=", 8) == 0) {
3592 static char buffer[1024];
3595 for(const char*s = &str[8]; *s != '\0'; ++s) {
3609 if ( t > &buffer[1020] ) {
3628 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
3629 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
3630 template <> const char* Writer<x86>::getArchString() { return "i386"; }
3631 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
3633 template <typename A>
3634 void Writer<A>::writeMap()
3636 if ( fOptions.generatedMapPath() != NULL ) {
3637 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
3638 if ( mapFile != NULL ) {
3639 // write output path
3640 fprintf(mapFile, "# Path: %s\n", fFilePath);
3641 // write output architecure
3642 fprintf(mapFile, "# Arch: %s\n", getArchString());
3644 if ( fUUIDAtom != NULL ) {
3645 const uint8_t* uuid = fUUIDAtom->getUUID();
3646 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
3647 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
3648 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
3650 // write table of object files
3651 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
3652 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
3653 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
3654 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3655 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3656 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3657 if ( ! (*secit)->fVirtualSection ) {
3658 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3659 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3660 ObjectFile::Reader* reader = (*ait)->getFile();
3661 uint32_t readerOrdinal = (*ait)->getOrdinal();
3662 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
3663 if ( pos == readerToOrdinal.end() ) {
3664 readerToOrdinal[reader] = readerOrdinal;
3665 ordinalToReader[readerOrdinal] = reader;
3671 fprintf(mapFile, "# Object files:\n");
3672 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
3673 uint32_t fileIndex = 0;
3674 readerToFileOrdinal[this] = fileIndex++;
3675 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
3676 if ( it->first != 0 ) {
3677 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
3678 readerToFileOrdinal[it->second] = fileIndex++;
3681 // write table of sections
3682 fprintf(mapFile, "# Sections:\n");
3683 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
3684 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3685 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3686 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3687 if ( ! (*secit)->fVirtualSection ) {
3688 SectionInfo* sect = *secit;
3689 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
3690 (*segit)->fName, sect->fSectionName);
3694 // write table of symbols
3695 fprintf(mapFile, "# Symbols:\n");
3696 fprintf(mapFile, "# Address\tSize \tFile Name\n");
3697 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3698 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3699 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3700 if ( ! (*secit)->fVirtualSection ) {
3701 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3702 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
3703 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3704 ObjectFile::Atom* atom = *ait;
3705 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
3706 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
3714 fprintf(stderr, "ld: warning could not write map file: %s\n", fOptions.generatedMapPath());
3719 template <typename A>
3720 uint64_t Writer<A>::writeAtoms()
3722 // try to allocate buffer for entire output file content
3723 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
3724 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
3725 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
3726 uint8_t* atomBuffer = NULL;
3727 bool streaming = false;
3728 if ( wholeBuffer == NULL ) {
3729 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
3734 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3735 SegmentInfo* curSegment = *segit;
3736 bool isTextSeg = (strcmp(curSegment->fName, "__TEXT") == 0);
3737 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3738 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3739 SectionInfo* curSection = *secit;
3740 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3741 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
3742 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
3743 if ( ! curSection->fAllZeroFill ) {
3744 end = curSection->fFileOffset;
3745 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
3746 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3747 ObjectFile::Atom* atom = *ait;
3748 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
3749 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
3750 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
3751 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
3752 if ( fileOffset != end ) {
3754 // fill gaps with no-ops
3756 writeNoOps(end, fileOffset);
3758 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
3760 else if ( streaming ) {
3762 if ( (fileOffset-end) == 4 ) {
3764 ::pwrite(fFileDescriptor, &zero, 4, end);
3767 uint8_t zero = 0x00;
3768 for (uint32_t p=end; p < fileOffset; ++p)
3769 ::pwrite(fFileDescriptor, &zero, 1, p);
3773 uint64_t atomSize = atom->getSize();
3775 if ( atomSize > fLargestAtomSize )
3776 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
3777 atom->getDisplayName(), atomSize, fLargestAtomSize);
3780 if ( fileOffset > fileBufferSize )
3781 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
3782 atom->getDisplayName(), fileOffset, fileBufferSize);
3784 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
3785 end = fileOffset+atomSize;
3787 atom->copyRawContent(buffer);
3788 // apply any fix-ups
3790 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3791 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
3792 ObjectFile::Reference* ref = *it;
3793 if ( fOptions.outputKind() == Options::kObjectFile ) {
3795 // skip fix-ups for undefined targets
3796 if ( &(ref->getTarget()) != NULL )
3797 this->fixUpReferenceRelocatable(ref, atom, buffer);
3800 // producing final linked image
3801 this->fixUpReferenceFinal(ref, atom, buffer);
3805 catch (const char* msg) {
3806 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3808 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
3809 // fileOffset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
3812 ::pwrite(fFileDescriptor, buffer, atomSize, fileOffset);
3815 if ( (fileOffset + atomSize) > size )
3816 size = fileOffset + atomSize;
3824 // update content based UUID
3825 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
3826 uint8_t digest[CC_MD5_DIGEST_LENGTH];
3828 // if output file file did not fit in memory, re-read file to generate md5 hash
3829 uint32_t kMD5BufferSize = 16*1024;
3830 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
3831 if ( md5Buffer != NULL ) {
3832 CC_MD5_CTX md5State;
3833 CC_MD5_Init(&md5State);
3834 ::lseek(fFileDescriptor, 0, SEEK_SET);
3836 while ( (len = ::read(fFileDescriptor, md5Buffer, kMD5BufferSize)) > 0 )
3837 CC_MD5_Update(&md5State, md5Buffer, len);
3838 CC_MD5_Final(digest, &md5State);
3842 // if malloc fails, fall back to random uuid
3843 ::uuid_generate_random(digest);
3845 fUUIDAtom->setContent(digest);
3846 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
3847 fUUIDAtom->copyRawContent(atomBuffer);
3848 ::pwrite(fFileDescriptor, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
3851 // if output file fit in memory, just genrate an md5 hash in memory
3852 CC_MD5(wholeBuffer, size, digest);
3853 fUUIDAtom->setContent(digest);
3854 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
3855 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
3861 delete [] atomBuffer;
3864 // write whole output file in one chunk
3865 ::pwrite(fFileDescriptor, wholeBuffer, size, 0);
3866 delete [] wholeBuffer;
3869 close(fFileDescriptor);
3875 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
3877 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
3878 uint8_t* dtraceProbeSite;
3879 const int64_t kTwoGigLimit = 0x7FFFFFFF;
3880 const int64_t kSixtyFourKiloLimit = 0x7FFF;
3881 int64_t displacement;
3882 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
3885 case x86::kFollowOn:
3888 case x86::kPointerWeakImport:
3891 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
3892 if ( fOptions.prebind() ) {
3893 switch (ref->getTarget().getDefinitionKind()) {
3894 case ObjectFile::Atom::kExternalDefinition:
3895 case ObjectFile::Atom::kExternalWeakDefinition:
3896 // prebound external relocation ==> pointer contains addend
3897 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3899 case ObjectFile::Atom::kTentativeDefinition:
3900 case ObjectFile::Atom::kRegularDefinition:
3901 case ObjectFile::Atom::kWeakDefinition:
3902 // prebound external relocation to internal atom ==> pointer contains target address + addend
3903 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3905 case ObjectFile::Atom::kAbsoluteSymbol:
3910 // external realocation ==> pointer contains addend
3911 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3915 // pointer contains target address
3916 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
3917 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3921 case x86::kPointerDiff:
3922 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
3923 LittleEndian::set32(*fixUp, (uint32_t)displacement);
3925 case x86::kPointerDiff16:
3926 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
3927 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
3928 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
3929 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
3931 case x86::kDtraceProbeSite:
3932 // change call site to a NOP
3933 dtraceProbeSite = (uint8_t*)fixUp;
3934 dtraceProbeSite[-1] = 0x90; // 1-byte nop
3935 dtraceProbeSite[0] = 0x0F; // 4-byte nop
3936 dtraceProbeSite[1] = 0x1F;
3937 dtraceProbeSite[2] = 0x40;
3938 dtraceProbeSite[3] = 0x00;
3940 case x86::kDtraceIsEnabledSite:
3941 // change call site to a clear eax
3942 dtraceProbeSite = (uint8_t*)fixUp;
3943 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
3944 dtraceProbeSite[0] = 0xC0;
3945 dtraceProbeSite[1] = 0x90; // 1-byte nop
3946 dtraceProbeSite[2] = 0x90; // 1-byte nop
3947 dtraceProbeSite[3] = 0x90; // 1-byte nop
3949 case x86::kPCRel32WeakImport:
3953 switch ( ref->getTarget().getDefinitionKind() ) {
3954 case ObjectFile::Atom::kRegularDefinition:
3955 case ObjectFile::Atom::kWeakDefinition:
3956 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
3958 case ObjectFile::Atom::kExternalDefinition:
3959 case ObjectFile::Atom::kExternalWeakDefinition:
3960 throw "codegen problem, can't use rel32 to external symbol";
3961 case ObjectFile::Atom::kTentativeDefinition:
3964 case ObjectFile::Atom::kAbsoluteSymbol:
3965 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
3968 if ( kind == x86::kPCRel16 ) {
3969 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
3970 //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());
3971 throwf("rel16 out of range in %s", inAtom->getDisplayName());
3973 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
3976 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
3977 //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());
3978 throwf("rel32 out of range in %s", inAtom->getDisplayName());
3980 LittleEndian::set32(*fixUp, (int32_t)displacement);
3983 case x86::kAbsolute32:
3984 switch ( ref->getTarget().getDefinitionKind() ) {
3985 case ObjectFile::Atom::kRegularDefinition:
3986 case ObjectFile::Atom::kWeakDefinition:
3987 case ObjectFile::Atom::kTentativeDefinition:
3988 // pointer contains target address
3989 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3991 case ObjectFile::Atom::kExternalDefinition:
3992 case ObjectFile::Atom::kExternalWeakDefinition:
3993 // external realocation ==> pointer contains addend
3994 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3996 case ObjectFile::Atom::kAbsoluteSymbol:
3997 // pointer contains target address
3998 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
4002 case x86::kDtraceTypeReference:
4003 case x86::kDtraceProbe:
4004 // nothing to fix up
4012 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4014 const int64_t kTwoGigLimit = 0x7FFFFFFF;
4015 const int64_t kSixtyFourKiloLimit = 0x7FFF;
4016 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4017 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
4018 int64_t displacement;
4019 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
4022 case x86::kFollowOn:
4026 case x86::kPointerWeakImport:
4027 case x86::kAbsolute32:
4030 // external realocation ==> pointer contains addend
4031 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4033 else if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4034 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
4035 if ( this->indirectSymbolIsLocal(ref) )
4036 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4038 LittleEndian::set32(*fixUp, 0);
4040 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
4041 // internal relocation => pointer contains target address
4042 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4045 // internal relocation to tentative ==> pointer contains addend
4046 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4050 case x86::kPointerDiff:
4051 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4052 LittleEndian::set32(*fixUp, (uint32_t)displacement);
4054 case x86::kPointerDiff16:
4055 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4056 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
4057 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
4058 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
4062 case x86::kPCRel32WeakImport:
4063 case x86::kDtraceProbeSite:
4064 case x86::kDtraceIsEnabledSite:
4067 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4069 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4070 if ( kind == x86::kPCRel16 ) {
4072 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
4073 //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());
4074 throwf("rel16 out of range in %s", inAtom->getDisplayName());
4076 int16_t word = (int16_t)displacement;
4077 LittleEndian::set16(*((uint16_t*)fixUp), word);
4080 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
4081 //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());
4082 throwf("rel32 out of range in %s", inAtom->getDisplayName());
4084 LittleEndian::set32(*fixUp, (int32_t)displacement);
4088 case x86::kDtraceProbe:
4089 case x86::kDtraceTypeReference:
4090 // nothing to fix up
4096 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4098 const int64_t twoGigLimit = 0x7FFFFFFF;
4099 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
4100 uint8_t* dtraceProbeSite;
4101 int64_t displacement = 0;
4102 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
4103 case x86_64::kNoFixUp:
4104 case x86_64::kFollowOn:
4107 case x86_64::kPointerWeakImport:
4108 case x86_64::kPointer:
4110 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
4111 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
4112 // external realocation ==> pointer contains addend
4113 LittleEndian::set64(*fixUp, ref->getTargetOffset());
4116 // internal relocation
4117 // pointer contains target address
4118 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
4119 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4123 case x86_64::kPointerDiff32:
4124 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4125 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
4126 throw "32-bit pointer difference out of range";
4127 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
4129 case x86_64::kPointerDiff:
4130 LittleEndian::set64(*fixUp,
4131 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4133 case x86_64::kPCRel32GOTLoad:
4134 case x86_64::kPCRel32GOTLoadWeakImport:
4135 // if GOT entry was optimized away, change movq instruction to a leaq
4136 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
4137 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
4138 uint8_t* opcodes = (uint8_t*)fixUp;
4139 if ( opcodes[-2] != 0x8B )
4140 throw "GOT load reloc does not point to a movq instruction";
4143 // fall into general rel32 case
4144 case x86_64::kBranchPCRel32WeakImport:
4145 case x86_64::kBranchPCRel32:
4146 case x86_64::kPCRel32:
4147 case x86_64::kPCRel32_1:
4148 case x86_64::kPCRel32_2:
4149 case x86_64::kPCRel32_4:
4150 case x86_64::kPCRel32GOT:
4151 case x86_64::kPCRel32GOTWeakImport:
4152 switch ( ref->getTarget().getDefinitionKind() ) {
4153 case ObjectFile::Atom::kRegularDefinition:
4154 case ObjectFile::Atom::kWeakDefinition:
4155 case ObjectFile::Atom::kTentativeDefinition:
4156 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4158 case ObjectFile::Atom::kAbsoluteSymbol:
4159 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4161 case ObjectFile::Atom::kExternalDefinition:
4162 case ObjectFile::Atom::kExternalWeakDefinition:
4163 throw "codegen problem, can't use rel32 to external symbol";
4166 switch ( ref->getKind() ) {
4167 case x86_64::kPCRel32_1:
4170 case x86_64::kPCRel32_2:
4173 case x86_64::kPCRel32_4:
4177 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
4178 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
4179 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
4180 throw "rel32 out of range";
4182 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
4184 case x86_64::kDtraceProbeSite:
4185 // change call site to a NOP
4186 dtraceProbeSite = (uint8_t*)fixUp;
4187 dtraceProbeSite[-1] = 0x90; // 1-byte nop
4188 dtraceProbeSite[0] = 0x0F; // 4-byte nop
4189 dtraceProbeSite[1] = 0x1F;
4190 dtraceProbeSite[2] = 0x40;
4191 dtraceProbeSite[3] = 0x00;
4193 case x86_64::kDtraceIsEnabledSite:
4194 // change call site to a clear eax
4195 dtraceProbeSite = (uint8_t*)fixUp;
4196 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
4197 dtraceProbeSite[0] = 0x33;
4198 dtraceProbeSite[1] = 0xC0;
4199 dtraceProbeSite[2] = 0x90; // 1-byte nop
4200 dtraceProbeSite[3] = 0x90; // 1-byte nop
4202 case x86_64::kDtraceTypeReference:
4203 case x86_64::kDtraceProbe:
4204 // nothing to fix up
4210 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4212 const int64_t twoGigLimit = 0x7FFFFFFF;
4213 bool external = this->makesExternalRelocatableReference(ref->getTarget());
4214 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
4215 int64_t displacement = 0;
4217 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
4218 case x86_64::kNoFixUp:
4219 case x86_64::kFollowOn:
4222 case x86_64::kPointer:
4223 case x86_64::kPointerWeakImport:
4226 // external realocation ==> pointer contains addend
4227 LittleEndian::set64(*fixUp, ref->getTargetOffset());
4230 // internal relocation ==> pointer contains target address
4231 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4235 case x86_64::kPointerDiff32:
4236 // addend in content
4237 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
4239 case x86_64::kPointerDiff:
4240 // addend in content
4241 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
4243 case x86_64::kBranchPCRel32:
4244 case x86_64::kBranchPCRel32WeakImport:
4245 case x86_64::kDtraceProbeSite:
4246 case x86_64::kDtraceIsEnabledSite:
4247 case x86_64::kPCRel32:
4248 case x86_64::kPCRel32_1:
4249 case x86_64::kPCRel32_2:
4250 case x86_64::kPCRel32_4:
4251 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
4252 temp32 = ref->getTargetOffset();
4254 // extern relocation contains addend
4255 displacement = temp32;
4258 // internal relocations contain delta to target address
4259 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4261 switch ( ref->getKind() ) {
4262 case x86_64::kPCRel32_1:
4265 case x86_64::kPCRel32_2:
4268 case x86_64::kPCRel32_4:
4272 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
4273 //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());
4274 throw "rel32 out of range";
4276 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
4278 case x86_64::kPCRel32GOT:
4279 case x86_64::kPCRel32GOTLoad:
4280 case x86_64::kPCRel32GOTWeakImport:
4281 case x86_64::kPCRel32GOTLoadWeakImport:
4282 // contains addend (usually zero)
4283 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
4285 case x86_64::kDtraceTypeReference:
4286 case x86_64::kDtraceProbe:
4287 // nothing to fix up
4293 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4295 fixUpReference_powerpc(ref, inAtom, buffer, true);
4299 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4301 fixUpReference_powerpc(ref, inAtom, buffer, true);
4305 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4307 fixUpReference_powerpc(ref, inAtom, buffer, false);
4311 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4313 fixUpReference_powerpc(ref, inAtom, buffer, false);
4317 // ppc and ppc64 are mostly the same, so they share a template specialzation
4319 template <typename A>
4320 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
4322 uint32_t instruction;
4323 uint32_t newInstruction;
4324 int64_t displacement;
4325 uint64_t targetAddr = 0;
4326 uint64_t picBaseAddr;
4327 uint16_t instructionLowHalf;
4328 uint16_t instructionHighHalf;
4329 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4330 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
4331 bool relocateableExternal = false;
4332 const int64_t picbase_twoGigLimit = 0x80000000;
4334 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4335 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4336 if ( finalLinkedImage )
4337 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
4339 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
4342 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
4347 case A::kPointerWeakImport:
4350 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
4351 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
4352 if ( fOptions.prebind() ) {
4353 switch (ref->getTarget().getDefinitionKind()) {
4354 case ObjectFile::Atom::kExternalDefinition:
4355 case ObjectFile::Atom::kExternalWeakDefinition:
4356 // prebound lazy pointer to another dylib ==> pointer contains zero
4357 P::setP(*fixUpPointer, 0);
4359 case ObjectFile::Atom::kTentativeDefinition:
4360 case ObjectFile::Atom::kRegularDefinition:
4361 case ObjectFile::Atom::kWeakDefinition:
4362 // prebound lazy pointer to withing this dylib ==> pointer contains address
4363 P::setP(*fixUpPointer, targetAddr);
4365 case ObjectFile::Atom::kAbsoluteSymbol:
4370 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
4371 if ( fDyldHelper == NULL )
4372 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
4373 P::setP(*fixUpPointer, fDyldHelper->getAddress());
4376 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4377 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
4378 if ( this->indirectSymbolIsLocal(ref) )
4379 P::setP(*fixUpPointer, targetAddr);
4381 P::setP(*fixUpPointer, 0);
4383 else if ( relocateableExternal ) {
4384 if ( fOptions.prebind() ) {
4385 switch (ref->getTarget().getDefinitionKind()) {
4386 case ObjectFile::Atom::kExternalDefinition:
4387 case ObjectFile::Atom::kExternalWeakDefinition:
4388 // prebound external relocation ==> pointer contains addend
4389 P::setP(*fixUpPointer, ref->getTargetOffset());
4391 case ObjectFile::Atom::kTentativeDefinition:
4392 case ObjectFile::Atom::kRegularDefinition:
4393 case ObjectFile::Atom::kWeakDefinition:
4394 // prebound external relocation to internal atom ==> pointer contains target address + addend
4395 P::setP(*fixUpPointer, targetAddr);
4397 case ObjectFile::Atom::kAbsoluteSymbol:
4402 // external realocation ==> pointer contains addend
4403 P::setP(*fixUpPointer, ref->getTargetOffset());
4407 // internal relocation
4408 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
4409 // pointer contains target address
4410 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
4411 P::setP(*fixUpPointer, targetAddr);
4414 // pointer contains addend
4415 P::setP(*fixUpPointer, ref->getTargetOffset());
4420 case A::kPointerDiff64:
4421 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4423 case A::kPointerDiff32:
4424 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4426 case A::kPointerDiff16:
4427 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4429 case A::kDtraceProbeSite:
4430 if ( finalLinkedImage ) {
4431 // change call site to a NOP
4432 BigEndian::set32(*fixUp, 0x60000000);
4435 // set bl instuction to branch to address zero in .o file
4436 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
4437 instruction = BigEndian::get32(*fixUp);
4438 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4439 BigEndian::set32(*fixUp, newInstruction);
4442 case A::kDtraceIsEnabledSite:
4443 if ( finalLinkedImage ) {
4444 // change call site to a li r3,0
4445 BigEndian::set32(*fixUp, 0x38600000);
4448 // set bl instuction to branch to address zero in .o file
4449 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
4450 instruction = BigEndian::get32(*fixUp);
4451 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4452 BigEndian::set32(*fixUp, newInstruction);
4455 case A::kBranch24WeakImport:
4458 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
4459 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4460 if ( relocateableExternal ) {
4461 // doing "ld -r" to an external symbol
4462 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4463 displacement -= ref->getTarget().getAddress();
4466 const int64_t bl_eightMegLimit = 0x00FFFFFF;
4467 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
4468 //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());
4469 throwf("bl out of range (%lld max is +/-16M) from %s at 0x%08llX in %s of %s to %s at 0x%08llX in %s of %s",
4470 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
4471 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
4474 instruction = BigEndian::get32(*fixUp);
4475 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4476 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
4477 BigEndian::set32(*fixUp, newInstruction);
4482 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
4483 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4484 if ( relocateableExternal ) {
4485 // doing "ld -r" to an external symbol
4486 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4487 displacement -= ref->getTarget().getAddress();
4490 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
4491 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
4492 //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());
4493 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
4494 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4495 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4498 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
4499 instruction = BigEndian::get32(*fixUp);
4500 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
4501 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
4502 BigEndian::set32(*fixUp, newInstruction);
4505 case A::kPICBaseLow16:
4506 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4507 displacement = targetAddr - picBaseAddr;
4508 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4509 throw "32-bit pic-base out of range";
4510 instructionLowHalf = (displacement & 0xFFFF);
4511 instruction = BigEndian::get32(*fixUp);
4512 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4513 BigEndian::set32(*fixUp, newInstruction);
4515 case A::kPICBaseLow14:
4516 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4517 displacement = targetAddr - picBaseAddr;
4518 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4519 throw "32-bit pic-base out of range";
4520 if ( (displacement & 0x3) != 0 )
4521 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
4522 instructionLowHalf = (displacement & 0xFFFC);
4523 instruction = BigEndian::get32(*fixUp);
4524 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
4525 BigEndian::set32(*fixUp, newInstruction);
4527 case A::kPICBaseHigh16:
4528 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4529 displacement = targetAddr - picBaseAddr;
4530 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4531 throw "32-bit pic-base out of range";
4532 instructionLowHalf = displacement >> 16;
4533 if ( (displacement & 0x00008000) != 0 )
4534 ++instructionLowHalf;
4535 instruction = BigEndian::get32(*fixUp);
4536 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4537 BigEndian::set32(*fixUp, newInstruction);
4540 if ( relocateableExternal && !finalLinkedImage )
4541 targetAddr -= ref->getTarget().getAddress();
4542 instructionLowHalf = (targetAddr & 0xFFFF);
4543 instruction = BigEndian::get32(*fixUp);
4544 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4545 BigEndian::set32(*fixUp, newInstruction);
4548 if ( relocateableExternal && !finalLinkedImage )
4549 targetAddr -= ref->getTarget().getAddress();
4550 if ( (targetAddr & 0x3) != 0 )
4551 throw "bad address for absolute lo14 instruction fix-up";
4552 instructionLowHalf = (targetAddr & 0xFFFF);
4553 instruction = BigEndian::get32(*fixUp);
4554 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
4555 BigEndian::set32(*fixUp, newInstruction);
4558 if ( relocateableExternal ) {
4559 if ( finalLinkedImage ) {
4560 switch (ref->getTarget().getDefinitionKind()) {
4561 case ObjectFile::Atom::kExternalDefinition:
4562 case ObjectFile::Atom::kExternalWeakDefinition:
4563 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
4565 case ObjectFile::Atom::kTentativeDefinition:
4566 case ObjectFile::Atom::kRegularDefinition:
4567 case ObjectFile::Atom::kWeakDefinition:
4568 // use target address
4570 case ObjectFile::Atom::kAbsoluteSymbol:
4571 targetAddr = ref->getTarget().getSectionOffset();
4576 targetAddr -= ref->getTarget().getAddress();
4579 instructionHighHalf = (targetAddr >> 16);
4580 instruction = BigEndian::get32(*fixUp);
4581 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
4582 BigEndian::set32(*fixUp, newInstruction);
4584 case A::kAbsHigh16AddLow:
4585 if ( relocateableExternal ) {
4586 if ( finalLinkedImage ) {
4587 switch (ref->getTarget().getDefinitionKind()) {
4588 case ObjectFile::Atom::kExternalDefinition:
4589 case ObjectFile::Atom::kExternalWeakDefinition:
4590 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
4592 case ObjectFile::Atom::kTentativeDefinition:
4593 case ObjectFile::Atom::kRegularDefinition:
4594 case ObjectFile::Atom::kWeakDefinition:
4595 // use target address
4597 case ObjectFile::Atom::kAbsoluteSymbol:
4598 targetAddr = ref->getTarget().getSectionOffset();
4603 targetAddr -= ref->getTarget().getAddress();
4606 if ( targetAddr & 0x00008000 )
4607 targetAddr += 0x00010000;
4608 instruction = BigEndian::get32(*fixUp);
4609 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
4610 BigEndian::set32(*fixUp, newInstruction);
4612 case A::kDtraceTypeReference:
4613 case A::kDtraceProbe:
4614 // nothing to fix up
4620 bool Writer<ppc>::stubableReference(const ObjectFile::Reference* ref)
4622 uint8_t kind = ref->getKind();
4623 switch ( (ppc::ReferenceKinds)kind ) {
4625 case ppc::kFollowOn:
4627 case ppc::kPointerWeakImport:
4628 case ppc::kPointerDiff16:
4629 case ppc::kPointerDiff32:
4630 case ppc::kPointerDiff64:
4631 case ppc::kDtraceProbe:
4632 case ppc::kDtraceProbeSite:
4633 case ppc::kDtraceIsEnabledSite:
4634 case ppc::kDtraceTypeReference:
4635 // these are never used to call external functions
4637 case ppc::kBranch24:
4638 case ppc::kBranch24WeakImport:
4639 case ppc::kBranch14:
4640 // these are used to call external functions
4642 case ppc::kPICBaseLow16:
4643 case ppc::kPICBaseLow14:
4644 case ppc::kPICBaseHigh16:
4645 case ppc::kAbsLow16:
4646 case ppc::kAbsLow14:
4647 case ppc::kAbsHigh16:
4648 case ppc::kAbsHigh16AddLow:
4649 // these are only used to call external functions
4650 // in -mlong-branch stubs
4651 switch ( ref->getTarget().getDefinitionKind() ) {
4652 case ObjectFile::Atom::kExternalDefinition:
4653 case ObjectFile::Atom::kExternalWeakDefinition:
4655 case ObjectFile::Atom::kTentativeDefinition:
4656 case ObjectFile::Atom::kRegularDefinition:
4657 case ObjectFile::Atom::kWeakDefinition:
4658 case ObjectFile::Atom::kAbsoluteSymbol:
4668 bool Writer<ppc64>::stubableReference(const ObjectFile::Reference* ref)
4670 uint8_t kind = ref->getKind();
4671 switch ( (ppc64::ReferenceKinds)kind ) {
4673 case ppc::kFollowOn:
4675 case ppc::kPointerWeakImport:
4676 case ppc::kPointerDiff16:
4677 case ppc::kPointerDiff32:
4678 case ppc::kPointerDiff64:
4679 case ppc::kPICBaseLow16:
4680 case ppc::kPICBaseLow14:
4681 case ppc::kPICBaseHigh16:
4682 case ppc::kAbsLow16:
4683 case ppc::kAbsLow14:
4684 case ppc::kAbsHigh16:
4685 case ppc::kAbsHigh16AddLow:
4686 case ppc::kDtraceProbe:
4687 case ppc::kDtraceProbeSite:
4688 case ppc::kDtraceIsEnabledSite:
4689 case ppc::kDtraceTypeReference:
4690 // these are never used to call external functions
4692 case ppc::kBranch24:
4693 case ppc::kBranch24WeakImport:
4694 case ppc::kBranch14:
4695 // these are used to call external functions
4702 bool Writer<x86>::stubableReference(const ObjectFile::Reference* ref)
4704 uint8_t kind = ref->getKind();
4705 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
4709 bool Writer<x86_64>::stubableReference(const ObjectFile::Reference* ref)
4711 uint8_t kind = ref->getKind();
4712 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
4717 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
4719 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
4723 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
4725 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
4729 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
4731 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
4735 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
4738 case x86_64::kPointerWeakImport:
4739 case x86_64::kBranchPCRel32WeakImport:
4740 case x86_64::kPCRel32GOTWeakImport:
4741 case x86_64::kPCRel32GOTLoadWeakImport:
4750 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
4756 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
4762 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
4768 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
4771 case x86_64::kPCRel32GOT:
4772 case x86_64::kPCRel32GOTWeakImport:
4773 case x86_64::kPCRel32GOTLoad:
4774 case x86_64::kPCRel32GOTLoadWeakImport:
4781 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
4787 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
4793 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
4799 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
4802 case x86_64::kPCRel32GOTLoad:
4803 case x86_64::kPCRel32GOTLoadWeakImport:
4811 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
4812 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
4813 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
4814 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
4817 template <typename A>
4818 void Writer<A>::optimizeDylibReferences()
4820 //fprintf(stderr, "original ordinals table:\n");
4821 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4822 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
4824 // find unused dylibs that can be removed
4825 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
4826 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
4827 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4828 ObjectFile::Reader* reader = it->first;
4829 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
4830 if ( aliasPos != fLibraryAliases.end() ) {
4831 // already noticed that this reader has same install name as another reader
4832 readerAliases[reader] = aliasPos->second;
4834 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || fOptions.deadStripDylibs()) ) {
4835 // this reader can be optimized away
4836 it->second = 0xFFFFFFFF;
4837 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
4838 if ( pos != fLibraryToLoadCommand.end() )
4839 pos->second->optimizeAway();
4842 // mark this reader as using it ordinal
4843 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
4844 if ( pos == ordinalToReader.end() )
4845 ordinalToReader[it->second] = reader;
4847 readerAliases[reader] = pos->second;
4850 // renumber ordinals (depends on iterator walking in ordinal order)
4851 uint32_t newOrdinal = 0;
4852 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
4853 if ( it->first <= fLibraryToOrdinal.size() )
4854 fLibraryToOrdinal[it->second] = ++newOrdinal;
4857 // add aliases (e.g. -lm points to libSystem.dylib)
4858 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
4859 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
4862 // fprintf(stderr, "new ordinals table:\n");
4863 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4864 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
4870 void Writer<x86_64>::scanForAbsoluteReferences()
4872 // x86_64 codegen never has absolute references
4876 void Writer<x86>::scanForAbsoluteReferences()
4878 // when linking -pie verify there are no absolute addressing
4879 if ( fOptions.positionIndependentExecutable() ) {
4880 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4881 ObjectFile::Atom* atom = *it;
4882 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4883 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4884 ObjectFile::Reference* ref = *rit;
4885 switch (ref->getKind()) {
4886 case x86::kAbsolute32:
4887 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4896 void Writer<ppc>::scanForAbsoluteReferences()
4898 // when linking -pie verify there are no absolute addressing
4899 if ( fOptions.positionIndependentExecutable() ) {
4900 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4901 ObjectFile::Atom* atom = *it;
4902 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4903 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4904 ObjectFile::Reference* ref = *rit;
4905 switch (ref->getKind()) {
4906 case ppc::kAbsLow16:
4907 case ppc::kAbsLow14:
4908 case ppc::kAbsHigh16:
4909 case ppc::kAbsHigh16AddLow:
4910 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4919 // for ppc64 look for any -mdynamic-no-pic codegen
4921 void Writer<ppc64>::scanForAbsoluteReferences()
4923 // only do this for main executable
4924 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
4925 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4926 ObjectFile::Atom* atom = *it;
4927 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4928 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4929 ObjectFile::Reference* ref = *rit;
4930 switch (ref->getKind()) {
4931 case ppc64::kAbsLow16:
4932 case ppc64::kAbsLow14:
4933 case ppc64::kAbsHigh16:
4934 case ppc64::kAbsHigh16AddLow:
4935 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4936 // shrink page-zero and add pad segment to compensate
4937 fPadSegmentInfo = new SegmentInfo();
4938 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
4939 fPageZeroAtom->setSize(0x1000);
4948 template <typename A>
4949 void Writer<A>::insertDummyStubs()
4951 // only needed for x86
4955 void Writer<x86>::insertDummyStubs()
4957 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
4958 std::vector<class StubAtom<x86>*> betterStubs;
4959 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
4960 switch (betterStubs.size() % 64 ) {
4961 case 12:// stub would occupy 0x3C->0x41
4962 case 25:// stub would occupy 0x7D->0x82
4963 case 38:// stub would occupy 0xBE->0xC3
4964 case 51:// stub would occupy 0xFF->0x04
4965 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL))); //pad with dummy stub
4968 betterStubs.push_back(*it);
4971 fAllSynthesizedStubs.clear();
4972 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
4975 template <typename A>
4976 void Writer<A>::synthesizeStubs()
4978 switch ( fOptions.outputKind() ) {
4979 case Options::kObjectFile:
4980 // these output kinds never have stubs
4982 case Options::kStaticExecutable:
4983 case Options::kDyld:
4984 case Options::kDynamicLibrary:
4985 case Options::kDynamicBundle:
4986 case Options::kDynamicExecutable:
4987 // try to synthesize stubs for these
4991 // walk every atom and reference
4992 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4993 ObjectFile::Atom* atom = *it;
4994 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4995 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4996 ObjectFile::Reference* ref = *rit;
4997 switch ( ref->getTargetBinding()) {
4998 case ObjectFile::Reference::kUnboundByName:
4999 case ObjectFile::Reference::kDontBind:
5001 case ObjectFile::Reference::kBoundByName:
5002 case ObjectFile::Reference::kBoundDirectly:
5003 ObjectFile::Atom& target = ref->getTarget();
5004 // build map of which symbols need weak importing
5005 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
5006 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
5007 bool weakImport = this->weakImportReferenceKind(ref->getKind());
5008 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
5009 if ( pos == fWeakImportMap.end() ) {
5010 // target not in fWeakImportMap, so add
5011 fWeakImportMap[&target] = weakImport;
5014 // target in fWeakImportMap, check for weakness mismatch
5015 if ( pos->second != weakImport ) {
5017 switch ( fOptions.weakReferenceMismatchTreatment() ) {
5018 case Options::kWeakReferenceMismatchError:
5019 throwf("mismatching weak references for symbol: %s", target.getName());
5020 case Options::kWeakReferenceMismatchWeak:
5023 case Options::kWeakReferenceMismatchNonWeak:
5024 pos->second = false;
5030 // create stubs as needed
5031 if ( this->stubableReference(ref)
5032 && (ref->getTargetOffset() == 0)
5033 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
5034 ObjectFile::Atom* stub = NULL;
5035 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
5036 if ( pos == fStubsMap.end() ) {
5037 stub = new StubAtom<A>(*this, target);
5038 fStubsMap[&target] = stub;
5043 // alter reference to use stub instead
5044 ref->setTarget(*stub, 0);
5046 // create GOT slots (non-lazy pointers) as needed
5047 else if ( this->GOTReferenceKind(ref->getKind()) ) {
5049 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
5051 if ( fBiggerThanTwoGigs ) {
5052 // in big images use GOT for all zero fill atoms
5053 // this is just a heuristic and may need to be re-examined
5054 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
5057 // < 2GB image so remove all GOT entries that we can
5058 useGOT = mustUseGOT;
5060 // if this GOT usage cannot be optimized away then make a GOT enry
5061 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
5064 ObjectFile::Atom* nlp = NULL;
5065 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
5066 if ( pos == fGOTMap.end() ) {
5067 nlp = new NonLazyPointerAtom<A>(*this, target);
5068 fGOTMap[&target] = nlp;
5073 // alter reference to use non lazy pointer instead
5074 ref->setTarget(*nlp, ref->getTargetOffset());
5082 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
5084 // add dummy stubs (x86 only)
5085 this->insertDummyStubs();
5087 // sort lazy pointers
5088 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
5090 // add stubs to fAllAtoms
5091 if ( fAllSynthesizedStubs.size() != 0 ) {
5092 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
5093 std::vector<ObjectFile::Atom*> mergedStubs;
5094 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
5095 // when we have stubs and helpers, insert both into fAllAtoms
5096 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
5097 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
5098 stubs = &mergedStubs;
5100 ObjectFile::Section* curSection = NULL;
5101 ObjectFile::Atom* prevAtom = NULL;
5102 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5103 ObjectFile::Atom* atom = *it;
5104 ObjectFile::Section* nextSection = atom->getSection();
5105 if ( nextSection != curSection ) {
5106 // HACK HACK for i386 where stubs are not in _TEXT segment
5107 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
5108 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
5109 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
5110 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
5111 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
5116 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
5117 // found end of __text section, insert stubs here
5118 fAllAtoms->insert(it, stubs->begin(), stubs->end());
5122 curSection = nextSection;
5129 // add lazy pointers to fAllAtoms
5130 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
5131 ObjectFile::Section* curSection = NULL;
5132 ObjectFile::Atom* prevAtom = NULL;
5133 bool inserted = false;
5134 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5135 ObjectFile::Atom* atom = *it;
5136 ObjectFile::Section* nextSection = atom->getSection();
5137 if ( nextSection != curSection ) {
5138 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
5139 // found end of __dyld section, insert lazy pointers here
5140 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
5144 curSection = nextSection;
5149 throw "can't insert lazy pointers, __dyld section not found";
5153 // add non-lazy pointers to fAllAtoms
5154 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
5155 ObjectFile::Section* curSection = NULL;
5156 ObjectFile::Atom* prevAtom = NULL;
5157 bool inserted = false;
5158 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5159 ObjectFile::Atom* atom = *it;
5160 ObjectFile::Section* nextSection = atom->getSection();
5161 if ( nextSection != curSection ) {
5162 if ( (prevAtom != NULL)
5163 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
5164 || ((strcmp(prevAtom->getSectionName(), "__data") == 0) &&
5165 ((fOptions.outputKind() == Options::kDyld) || (fOptions.outputKind() == Options::kStaticExecutable))) ) ) {
5166 // found end of __dyld section, insert lazy pointers here
5167 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
5171 curSection = nextSection;
5176 throw "can't insert non-lazy pointers, __dyld section not found";
5180 // build LC_SEGMENT_SPLIT_INFO content now that all atoms exist
5181 if ( fSplitCodeToDataContentAtom != NULL ) {
5182 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5183 ObjectFile::Atom* atom = *it;
5184 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5185 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
5186 ObjectFile::Reference* ref = *rit;
5187 switch ( ref->getTargetBinding()) {
5188 case ObjectFile::Reference::kUnboundByName:
5189 case ObjectFile::Reference::kDontBind:
5191 case ObjectFile::Reference::kBoundByName:
5192 case ObjectFile::Reference::kBoundDirectly:
5193 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
5194 this->addCrossSegmentRef(atom, ref);
5205 template <typename A>
5206 void Writer<A>::partitionIntoSections()
5208 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
5210 // for every atom, set its sectionInfo object and section offset
5211 // build up fSegmentInfos along the way
5212 ObjectFile::Section* curSection = NULL;
5213 SectionInfo* currentSectionInfo = NULL;
5214 SegmentInfo* currentSegmentInfo = NULL;
5215 SectionInfo* cstringSectionInfo = NULL;
5216 unsigned int sectionIndex = 1;
5217 fSegmentInfos.reserve(8);
5218 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
5219 ObjectFile::Atom* atom = (*fAllAtoms)[i];
5220 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
5221 if ( oneSegmentCommand ) {
5222 if ( currentSegmentInfo == NULL ) {
5223 currentSegmentInfo = new SegmentInfo();
5224 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5225 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5226 this->fSegmentInfos.push_back(currentSegmentInfo);
5228 currentSectionInfo = new SectionInfo();
5229 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
5230 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
5231 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
5232 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
5233 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
5234 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
5235 currentSectionInfo->setIndex(sectionIndex++);
5236 currentSegmentInfo->fSections.push_back(currentSectionInfo);
5237 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
5238 cstringSectionInfo = currentSectionInfo;
5241 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
5242 currentSegmentInfo = new SegmentInfo();
5243 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
5244 uint32_t initprot = 0;
5245 if ( atom->getSegment().isContentReadable() )
5246 initprot |= VM_PROT_READ;
5247 if ( atom->getSegment().isContentWritable() )
5248 initprot |= VM_PROT_WRITE;
5249 if ( atom->getSegment().isContentExecutable() )
5250 initprot |= VM_PROT_EXECUTE;
5251 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
5252 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
5253 currentSegmentInfo->fInitProtection = initprot;
5254 if ( initprot == 0 )
5255 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
5257 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5258 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
5259 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
5260 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
5261 currentSegmentInfo->fInitProtection = it->init;
5262 currentSegmentInfo->fMaxProtection = it->max;
5265 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
5266 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
5267 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
5268 currentSegmentInfo->fIndependentAddress = true;
5269 this->fSegmentInfos.push_back(currentSegmentInfo);
5271 currentSectionInfo = new SectionInfo();
5272 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
5273 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
5274 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
5275 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
5276 // check for -sectalign override
5277 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
5278 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
5279 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
5280 currentSectionInfo->fAlignment = it->alignment;
5282 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
5283 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
5284 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
5285 currentSectionInfo->setIndex(sectionIndex++);
5286 currentSegmentInfo->fSections.push_back(currentSectionInfo);
5288 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
5289 fLoadCommandsSection = currentSectionInfo;
5290 fLoadCommandsSegment = currentSegmentInfo;
5292 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
5293 currentSectionInfo->fAllLazyPointers = true;
5294 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
5295 currentSectionInfo->fAllLazyPointers = true;
5296 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
5297 currentSectionInfo->fAllNonLazyPointers = true;
5298 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
5299 currentSectionInfo->fAllNonLazyPointers = true;
5300 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
5301 currentSectionInfo->fAllNonLazyPointers = true;
5302 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
5303 currentSectionInfo->fAllStubs = true;
5304 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
5305 currentSectionInfo->fAllStubs = true;
5306 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
5307 currentSectionInfo->fAllStubs = true;
5308 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
5309 currentSectionInfo->fAllStubs = true;
5310 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
5311 currentSectionInfo->fAllSelfModifyingStubs = true;
5312 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
5314 curSection = atom->getSection();
5315 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers
5316 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllStubs ) {
5317 fSymbolTableCommands->needDynamicTable();
5320 // any non-zero fill atoms make whole section marked not-zero-fill
5321 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
5322 currentSectionInfo->fAllZeroFill = false;
5323 // change section object to be Writer's SectionInfo object
5324 atom->setSection(currentSectionInfo);
5325 // section alignment is that of a contained atom with the greatest alignment
5326 uint8_t atomAlign = atom->getAlignment().powerOf2;
5327 if ( currentSectionInfo->fAlignment < atomAlign )
5328 currentSectionInfo->fAlignment = atomAlign;
5329 // calculate section offset for this atom
5330 uint64_t offset = currentSectionInfo->fSize;
5331 uint64_t alignment = 1 << atomAlign;
5332 uint64_t currentModulus = (offset % alignment);
5333 uint64_t requiredModulus = atom->getAlignment().modulus;
5334 if ( currentModulus != requiredModulus ) {
5335 if ( requiredModulus > currentModulus )
5336 offset += requiredModulus-currentModulus;
5338 offset += requiredModulus+alignment-currentModulus;
5340 atom->setSectionOffset(offset);
5341 uint64_t curAtomSize = atom->getSize();
5342 currentSectionInfo->fSize = offset + curAtomSize;
5343 // add atom to section vector
5344 currentSectionInfo->fAtoms.push_back(atom);
5345 // update largest size
5346 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
5347 fLargestAtomSize = curAtomSize;
5349 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
5350 // when merging cstring sections in .o files, all strings need to use the max alignment
5351 uint64_t offset = 0;
5352 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
5353 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
5354 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
5355 ObjectFile::Atom* atom = *it;
5356 atom->setSectionOffset(offset);
5357 offset += atom->getSize();
5359 cstringSectionInfo->fSize = offset;
5364 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
5365 class TargetAndOffsetComparor
5368 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
5370 if ( left.atom != right.atom )
5371 return ( left.atom < right.atom );
5372 return ( left.offset < right.offset );
5377 bool Writer<ppc>::addBranchIslands()
5379 return this->addPPCBranchIslands();
5383 bool Writer<ppc64>::addBranchIslands()
5385 return this->addPPCBranchIslands();
5389 bool Writer<x86>::addBranchIslands()
5391 // x86 branches can reach entire 4G address space, so no need for branch islands
5396 bool Writer<x86_64>::addBranchIslands()
5398 // x86 branches can reach entire 4G size of largest image
5404 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
5407 case ppc::kBranch24:
5408 case ppc::kBranch24WeakImport:
5415 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
5418 case ppc64::kBranch24:
5419 case ppc64::kBranch24WeakImport:
5426 // PowerPC can do PC relative branches as far as +/-16MB.
5427 // If a branch target is >16MB then we insert one or more
5428 // "branch islands" between the branch and its target that
5429 // allows island hoping to the target.
5431 // Branch Island Algorithm
5433 // If the __TEXT segment < 16MB, then no branch islands needed
5434 // Otherwise, every 15MB into the __TEXT segment is region is
5435 // added which can contain branch islands. Every out of range
5436 // bl instruction is checked. If it crosses a region, an island
5437 // is added to that region with the same target and the bl is
5438 // adjusted to target the island instead.
5440 // In theory, if too many islands are added to one region, it
5441 // could grow the __TEXT enough that other previously in-range
5442 // bl branches could be pushed out of range. We reduce the
5443 // probability this could happen by placing the ranges every
5444 // 15MB which means the region would have to be 1MB (256K islands)
5445 // before any branches could be pushed out of range.
5447 template <typename A>
5448 bool Writer<A>::addPPCBranchIslands()
5451 bool result = false;
5452 // Can only possibly need branch islands if __TEXT segment > 16M
5453 if ( fLoadCommandsSegment->fSize > 16000000 ) {
5454 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
5455 const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section
5456 SectionInfo* textSection = NULL;
5457 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
5458 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
5460 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
5464 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
5465 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
5466 AtomToIsland regionsMap[kIslandRegionsCount];
5467 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
5468 unsigned int islandCount = 0;
5470 // create islands for branch references that are out of range
5471 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5472 ObjectFile::Atom* atom = *it;
5473 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5474 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
5475 ObjectFile::Reference* ref = *rit;
5476 if ( this->isBranch24Reference(ref->getKind()) ) {
5477 ObjectFile::Atom& target = ref->getTarget();
5478 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
5479 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
5480 int64_t displacement = dstAddr - srcAddr;
5481 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
5482 const int64_t kFifteenMegLimit = kBetweenRegions;
5483 if ( displacement > kFifteenMegLimit ) {
5484 // create forward branch chain
5485 ObjectFile::Atom* nextTarget = ⌖
5486 uint64_t nextTargetOffset = ref->getTargetOffset();
5487 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
5488 AtomToIsland* region = ®ionsMap[i];
5489 int64_t islandRegionAddr = kBetweenRegions * (i+1);
5490 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
5491 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
5492 if ( pos == region->end() ) {
5493 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
5494 island->setSection(textSection);
5495 (*region)[finalTargetAndOffset] = island;
5496 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
5497 regionsIslands[i].push_back(island);
5499 nextTarget = island;
5500 nextTargetOffset = 0;
5503 nextTarget = pos->second;
5504 nextTargetOffset = 0;
5508 if (log) fprintf(stderr, "using island %s for %s\n", nextTarget->getDisplayName(), atom->getDisplayName());
5509 ref->setTarget(*nextTarget, nextTargetOffset);
5511 else if ( displacement < (-kFifteenMegLimit) ) {
5512 // create back branching chain
5513 ObjectFile::Atom* prevTarget = ⌖
5514 uint64_t prevTargetOffset = ref->getTargetOffset();
5515 for (int i=0; i < kIslandRegionsCount ; ++i) {
5516 AtomToIsland* region = ®ionsMap[i];
5517 int64_t islandRegionAddr = kBetweenRegions * (i+1);
5518 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
5519 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
5520 if ( pos == region->end() ) {
5521 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
5522 island->setSection(textSection);
5523 (*region)[finalTargetAndOffset] = island;
5524 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
5525 regionsIslands[i].push_back(island);
5527 prevTarget = island;
5528 prevTargetOffset = 0;
5531 prevTarget = pos->second;
5532 prevTargetOffset = 0;
5536 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
5537 ref->setTarget(*prevTarget, prevTargetOffset);
5543 // insert islands into __text section and adjust section offsets
5544 if ( islandCount > 0 ) {
5545 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
5546 std::vector<ObjectFile::Atom*> newAtomList;
5547 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
5548 uint64_t islandRegionAddr = kBetweenRegions;
5549 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
5550 int regionIndex = 0;
5551 uint64_t atomSlide = 0;
5552 uint64_t sectionOffset = 0;
5553 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
5554 ObjectFile::Atom* atom = *it;
5555 newAtomList.push_back(atom);
5556 if ( atom->getAddress() > islandRegionAddr ) {
5557 uint64_t islandStartOffset = atom->getSectionOffset();
5558 sectionOffset = islandStartOffset + atomSlide;
5559 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
5560 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
5561 ObjectFile::Atom* islandAtom = *rit;
5562 newAtomList.push_back(islandAtom);
5563 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
5564 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5565 islandAtom->setSectionOffset(sectionOffset);
5566 sectionOffset += islandAtom->getSize();
5569 islandRegionAddr += kBetweenRegions;
5570 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
5571 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
5573 if ( atomSlide != 0 )
5574 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
5576 sectionOffset = textSection->fSize+atomSlide;
5577 // put any remaining islands at end of __text section
5578 if ( regionIndex < kIslandRegionsCount ) {
5579 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
5580 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
5581 ObjectFile::Atom* islandAtom = *rit;
5582 newAtomList.push_back(islandAtom);
5583 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
5584 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5585 islandAtom->setSectionOffset(sectionOffset);
5586 sectionOffset += islandAtom->getSize();
5590 textSection->fAtoms = newAtomList;
5591 textSection->fSize = sectionOffset;
5600 template <typename A>
5601 void Writer<A>::adjustLoadCommandsAndPadding()
5603 fSegmentCommands->computeSize();
5605 // recompute load command section offsets
5606 uint64_t offset = 0;
5607 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
5608 const unsigned int atomCount = loadCommandAtoms.size();
5609 for (unsigned int i=0; i < atomCount; ++i) {
5610 ObjectFile::Atom* atom = loadCommandAtoms[i];
5611 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
5612 offset = ( (offset+alignment-1) & (-alignment) );
5613 atom->setSectionOffset(offset);
5614 uint32_t atomSize = atom->getSize();
5615 if ( atomSize > fLargestAtomSize )
5616 fLargestAtomSize = atomSize;
5618 fLoadCommandsSection->fSize = offset;
5621 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
5622 const int sectionCount = sectionInfos.size();
5623 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
5624 for(int j=0; j < sectionCount; ++j) {
5625 SectionInfo* curSection = sectionInfos[j];
5626 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
5627 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
5630 uint64_t paddingSize = 0;
5631 if ( fOptions.outputKind() == Options::kDyld ) {
5632 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
5633 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
5635 else if ( fOptions.outputKind() == Options::kObjectFile ) {
5636 // mach-o .o files need no padding between load commands and first section
5640 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
5642 for(int j=sectionCount-1; j >=0; --j) {
5643 SectionInfo* curSection = sectionInfos[j];
5644 addr -= curSection->fSize;
5645 addr = addr & (0 - (1 << curSection->fAlignment));
5646 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
5647 addr -= totalSizeOfHeaderAndLoadCommands;
5648 paddingSize = addr % 4096;
5653 // if command line requires more padding than this
5654 uint32_t minPad = fOptions.minimumHeaderPad();
5655 if ( fOptions.maxMminimumHeaderPad() ) {
5656 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
5657 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
5658 if ( fOptions.outputKind() == Options::kDynamicLibrary )
5659 altMin += MAXPATHLEN;
5660 if ( altMin > minPad )
5663 if ( paddingSize < minPad ) {
5664 int extraPages = (minPad - paddingSize + 4095)/4096;
5665 paddingSize += extraPages * 4096;
5669 // adjust atom size and update section size
5670 fHeaderPadding->setSize(paddingSize);
5671 for(int j=0; j < sectionCount; ++j) {
5672 SectionInfo* curSection = sectionInfos[j];
5673 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
5674 curSection->fSize = paddingSize;
5678 // assign file offsets and logical address to all segments
5679 template <typename A>
5680 void Writer<A>::assignFileOffsets()
5682 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
5683 bool haveFixedSegments = false;
5684 uint64_t fileOffset = 0;
5685 uint64_t nextContiguousAddress = fOptions.baseAddress();
5686 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
5687 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
5689 // process segments with fixed addresses (-segaddr)
5690 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
5691 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5692 SegmentInfo* curSegment = *segit;
5693 if ( strcmp(curSegment->fName, it->name) == 0 ) {
5694 curSegment->fBaseAddress = it->address;
5695 curSegment->fFixedAddress = true;
5701 // Run through the segments and each segment's sections to assign addresses
5702 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5703 SegmentInfo* curSegment = *segit;
5705 if ( fOptions.splitSeg() ) {
5706 if ( curSegment->fInitProtection & VM_PROT_WRITE )
5707 nextContiguousAddress = nextWritableAddress;
5709 nextContiguousAddress = nextReadOnlyAddress;
5712 fileOffset = (fileOffset+4095) & (-4096);
5713 curSegment->fFileOffset = fileOffset;
5715 // Set the segment base address
5716 if ( curSegment->fFixedAddress )
5717 haveFixedSegments = true;
5719 curSegment->fBaseAddress = nextContiguousAddress;
5721 // We've set the segment address, now run through each section.
5722 uint64_t address = curSegment->fBaseAddress;
5723 SectionInfo* firstZeroFillSection = NULL;
5724 SectionInfo* prevSection = NULL;
5726 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5728 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
5729 SectionInfo* curSection = *it;
5731 // adjust section address based on alignment
5732 uint64_t alignment = 1 << curSection->fAlignment;
5733 address = ( (address+alignment-1) & (-alignment) );
5735 // adjust file offset to match address
5736 if ( prevSection != NULL ) {
5737 if ( finalLinkedImage || !prevSection->fVirtualSection )
5738 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
5740 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
5743 // update section info
5744 curSection->fFileOffset = fileOffset;
5745 curSection->setBaseAddress(address);
5747 // keep track of trailing zero fill sections
5748 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
5749 firstZeroFillSection = curSection;
5750 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
5751 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
5753 // update running pointers
5754 if ( finalLinkedImage || !curSection->fVirtualSection )
5755 address += curSection->fSize;
5756 fileOffset += curSection->fSize;
5758 // sanity check size of 32-bit binaries
5759 if ( address > maxAddress() )
5760 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
5762 // update segment info
5763 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
5764 curSegment->fSize = curSegment->fFileSize;
5765 prevSection = curSection;
5768 if ( fOptions.outputKind() == Options::kObjectFile ) {
5769 // don't page align .o files
5772 // optimize trailing zero-fill sections to not occupy disk space
5773 if ( firstZeroFillSection != NULL ) {
5774 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
5775 fileOffset = firstZeroFillSection->fFileOffset;
5777 // page align segment size
5778 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
5779 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
5780 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
5781 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
5782 if ( curSegment->fInitProtection & VM_PROT_WRITE )
5783 nextWritableAddress = nextContiguousAddress;
5785 nextReadOnlyAddress = nextContiguousAddress;
5790 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
5791 if ( haveFixedSegments ) {
5792 int segCount = fSegmentInfos.size();
5793 for(int i=0; i < segCount; ++i) {
5794 SegmentInfo* segment1 = fSegmentInfos[i];
5796 for(int j=0; j < segCount; ++j) {
5798 SegmentInfo* segment2 = fSegmentInfos[j];
5800 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
5801 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
5802 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5803 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5805 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
5806 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
5807 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5808 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5810 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
5811 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5812 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5819 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
5820 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5821 SegmentInfo* curSegment = *segit;
5822 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
5823 if ( fFirstWritableSegment == NULL )
5824 fFirstWritableSegment = curSegment;
5825 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
5826 fWritableSegmentPastFirst4GB = true;
5832 template <typename A>
5833 void Writer<A>::adjustLinkEditSections()
5835 // link edit content is always in last segment
5836 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
5837 unsigned int firstLinkEditSectionIndex = 0;
5838 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
5839 ++firstLinkEditSectionIndex;
5841 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
5842 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
5843 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
5844 if ( fPadSegmentInfo != NULL ) {
5845 // insert __4GBFILL segment into segments vector before LINKEDIT
5846 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
5847 if ( *it == lastSeg ) {
5848 fSegmentInfos.insert(it, fPadSegmentInfo);
5852 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
5853 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
5854 fPadSegmentInfo->fBaseAddress = address;
5855 // adjust LINKEDIT to start at zeroPageSize
5856 address = fOptions.zeroPageSize();
5857 lastSeg->fBaseAddress = fOptions.zeroPageSize();
5859 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
5860 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
5861 // adjust section address based on alignment
5862 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
5863 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
5865 fileOffset += pad; // adjust file offset to match address
5866 lastSeg->fSections[i]->setBaseAddress(address);
5867 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
5868 lastSeg->fSections[i]->setBaseAddress(0);
5869 lastSeg->fSections[i]->fFileOffset = fileOffset;
5870 uint64_t sectionOffset = 0;
5871 for (unsigned int j=0; j < atoms.size(); ++j) {
5872 ObjectFile::Atom* atom = atoms[j];
5873 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
5874 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5875 atom->setSectionOffset(sectionOffset);
5876 uint64_t size = atom->getSize();
5877 sectionOffset += size;
5878 if ( size > fLargestAtomSize )
5879 fLargestAtomSize = size;
5881 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
5882 lastSeg->fSections[i]->fSize = sectionOffset;
5883 fileOffset += sectionOffset;
5884 address += sectionOffset;
5886 if ( fOptions.outputKind() == Options::kObjectFile ) {
5887 //lastSeg->fBaseAddress = 0;
5888 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
5889 //lastSeg->fFileOffset = 0;
5890 //lastSeg->fFileSize =
5893 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
5894 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
5899 template <typename A>
5900 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
5902 switch ( fWriter.fOptions.outputKind() ) {
5903 case Options::kDynamicExecutable:
5904 case Options::kStaticExecutable:
5905 return ObjectFile::Atom::scopeGlobal;
5906 case Options::kDynamicLibrary:
5907 case Options::kDynamicBundle:
5908 case Options::kDyld:
5909 case Options::kObjectFile:
5910 return ObjectFile::Atom::scopeLinkageUnit;
5912 throw "unknown header type";
5915 template <typename A>
5916 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
5918 switch ( fWriter.fOptions.outputKind() ) {
5919 case Options::kDynamicExecutable:
5920 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
5921 case Options::kStaticExecutable:
5922 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
5923 case Options::kDynamicLibrary:
5924 case Options::kDynamicBundle:
5925 case Options::kDyld:
5926 return ObjectFile::Atom::kSymbolTableIn;
5927 case Options::kObjectFile:
5928 return ObjectFile::Atom::kSymbolTableNotIn;
5930 throw "unknown header type";
5933 template <typename A>
5934 const char* MachHeaderAtom<A>::getName() const
5936 switch ( fWriter.fOptions.outputKind() ) {
5937 case Options::kDynamicExecutable:
5938 case Options::kStaticExecutable:
5939 return "__mh_execute_header";
5940 case Options::kDynamicLibrary:
5941 return "__mh_dylib_header";
5942 case Options::kDynamicBundle:
5943 return "__mh_bundle_header";
5944 case Options::kObjectFile:
5946 case Options::kDyld:
5947 return "__mh_dylinker_header";
5949 throw "unknown header type";
5952 template <typename A>
5953 const char* MachHeaderAtom<A>::getDisplayName() const
5955 switch ( fWriter.fOptions.outputKind() ) {
5956 case Options::kDynamicExecutable:
5957 case Options::kStaticExecutable:
5958 case Options::kDynamicLibrary:
5959 case Options::kDynamicBundle:
5960 case Options::kDyld:
5961 return this->getName();
5962 case Options::kObjectFile:
5963 return "mach header";
5965 throw "unknown header type";
5968 template <typename A>
5969 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
5972 uint32_t fileType = 0;
5973 switch ( fWriter.fOptions.outputKind() ) {
5974 case Options::kDynamicExecutable:
5975 case Options::kStaticExecutable:
5976 fileType = MH_EXECUTE;
5978 case Options::kDynamicLibrary:
5979 fileType = MH_DYLIB;
5981 case Options::kDynamicBundle:
5982 fileType = MH_BUNDLE;
5984 case Options::kObjectFile:
5985 fileType = MH_OBJECT;
5987 case Options::kDyld:
5988 fileType = MH_DYLINKER;
5994 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
5995 if ( fWriter.fCanScatter )
5996 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
5999 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
6000 flags |= MH_NOUNDEFS;
6003 flags = MH_DYLDLINK;
6004 if ( fWriter.fOptions.bindAtLoad() )
6005 flags |= MH_BINDATLOAD;
6006 switch ( fWriter.fOptions.nameSpace() ) {
6007 case Options::kTwoLevelNameSpace:
6008 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
6010 case Options::kFlatNameSpace:
6012 case Options::kForceFlatNameSpace:
6013 flags |= MH_FORCE_FLAT;
6016 if ( fWriter.fHasWeakExports )
6017 flags |= MH_WEAK_DEFINES;
6018 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
6019 flags |= MH_BINDS_TO_WEAK;
6020 if ( fWriter.fOptions.prebind() )
6021 flags |= MH_PREBOUND;
6022 if ( fWriter.fOptions.splitSeg() )
6023 flags |= MH_SPLIT_SEGS;
6024 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
6025 flags |= MH_NO_REEXPORTED_DYLIBS;
6026 if ( fWriter.fOptions.positionIndependentExecutable() )
6029 if ( fWriter.fOptions.hasExecutableStack() )
6030 flags |= MH_ALLOW_STACK_EXECUTION;
6031 if ( fWriter.fOptions.readerOptions().fRootSafe )
6032 flags |= MH_ROOT_SAFE;
6033 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
6034 flags |= MH_SETUID_SAFE;
6037 // get commands info
6038 uint32_t commandsSize = 0;
6039 uint32_t commandsCount = 0;
6041 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
6042 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
6043 ObjectFile::Atom* atom = *it;
6044 commandsSize += atom->getSize();
6045 // segment and symbol table atoms can contain more than one load command
6046 if ( atom == fWriter.fSegmentCommands )
6047 commandsCount += fWriter.fSegmentCommands->commandCount();
6048 else if ( atom == fWriter.fSymbolTableCommands )
6049 commandsCount += fWriter.fSymbolTableCommands->commandCount();
6050 else if ( atom->getSize() != 0 )
6054 // fill out mach_header
6055 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
6057 mh->set_filetype(fileType);
6058 mh->set_ncmds(commandsCount);
6059 mh->set_sizeofcmds(commandsSize);
6060 mh->set_flags(flags);
6064 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
6066 header.set_magic(MH_MAGIC);
6067 header.set_cputype(CPU_TYPE_POWERPC);
6068 switch ( fWriter.fCpuConstraint ) {
6069 case ObjectFile::Reader::kCpuAny:
6070 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
6072 case ObjectFile::Reader::kCpuG3:
6073 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_750);
6075 case ObjectFile::Reader::kCpuG4:
6076 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_7400);
6078 case ObjectFile::Reader::kCpuG5:
6079 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_970);
6085 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
6087 header.set_magic(MH_MAGIC_64);
6088 header.set_cputype(CPU_TYPE_POWERPC64);
6089 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6090 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
6092 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
6093 header.set_reserved(0);
6097 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
6099 header.set_magic(MH_MAGIC);
6100 header.set_cputype(CPU_TYPE_I386);
6101 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
6105 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
6107 header.set_magic(MH_MAGIC_64);
6108 header.set_cputype(CPU_TYPE_X86_64);
6109 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6110 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
6112 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
6113 header.set_reserved(0);
6117 template <typename A>
6118 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
6119 : WriterAtom<A>(writer, Segment::fgStackSegment)
6121 if ( stackGrowsDown() )
6122 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
6124 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
6129 bool CustomStackAtom<ppc>::stackGrowsDown()
6135 bool CustomStackAtom<ppc64>::stackGrowsDown()
6141 bool CustomStackAtom<x86>::stackGrowsDown()
6147 bool CustomStackAtom<x86_64>::stackGrowsDown()
6153 template <typename A>
6154 void SegmentLoadCommandsAtom<A>::computeSize()
6157 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6158 const int segCount = segmentInfos.size();
6159 for(int i=0; i < segCount; ++i) {
6160 size += sizeof(macho_segment_command<P>);
6161 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
6162 const int sectionCount = sectionInfos.size();
6163 for(int j=0; j < sectionCount; ++j) {
6164 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
6165 size += sizeof(macho_section<P>);
6169 fCommandCount = segCount;
6170 if ( fWriter.fPadSegmentInfo != NULL ) {
6172 fSize += sizeof(macho_segment_command<P>);
6177 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
6179 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
6183 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
6185 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
6189 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
6191 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
6195 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
6197 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
6200 template <typename A>
6201 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6203 uint64_t size = this->getSize();
6204 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
6205 bzero(buffer, size);
6206 uint8_t* p = buffer;
6207 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6208 const int segCount = segmentInfos.size();
6209 for(int i=0; i < segCount; ++i) {
6210 SegmentInfo* segInfo = segmentInfos[i];
6211 const int sectionCount = segInfo->fSections.size();
6212 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
6213 cmd->set_cmd(macho_segment_command<P>::CMD);
6214 cmd->set_segname(segInfo->fName);
6215 cmd->set_vmaddr(segInfo->fBaseAddress);
6216 cmd->set_vmsize(segInfo->fSize);
6217 cmd->set_fileoff(segInfo->fFileOffset);
6218 cmd->set_filesize(segInfo->fFileSize);
6219 cmd->set_maxprot(segInfo->fMaxProtection);
6220 cmd->set_initprot(segInfo->fInitProtection);
6221 // add sections array
6222 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
6223 unsigned int sectionsEmitted = 0;
6224 for (int j=0; j < sectionCount; ++j) {
6225 SectionInfo* sectInfo = segInfo->fSections[j];
6226 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
6227 macho_section<P>* sect = §ions[sectionsEmitted++];
6229 // .o file segment does not cover load commands, so recalc at first real section
6230 if ( sectionsEmitted == 1 ) {
6231 cmd->set_vmaddr(sectInfo->getBaseAddress());
6232 cmd->set_fileoff(sectInfo->fFileOffset);
6234 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
6235 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
6237 sect->set_sectname(sectInfo->fSectionName);
6238 sect->set_segname(sectInfo->fSegmentName);
6239 sect->set_addr(sectInfo->getBaseAddress());
6240 sect->set_size(sectInfo->fSize);
6241 sect->set_offset(sectInfo->fFileOffset);
6242 sect->set_align(sectInfo->fAlignment);
6243 if ( sectInfo->fRelocCount != 0 ) {
6244 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
6245 sect->set_nreloc(sectInfo->fRelocCount);
6247 if ( sectInfo->fAllZeroFill ) {
6248 sect->set_flags(S_ZEROFILL);
6249 sect->set_offset(0);
6251 else if ( sectInfo->fAllLazyPointers ) {
6252 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
6253 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6255 else if ( sectInfo->fAllNonLazyPointers ) {
6256 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
6257 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6259 else if ( sectInfo->fAllStubs ) {
6260 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
6261 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6262 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
6264 else if ( sectInfo->fAllSelfModifyingStubs ) {
6265 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
6266 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6267 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
6269 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6270 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
6272 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6273 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
6275 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6276 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
6278 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6279 sect->set_flags(S_COALESCED);
6281 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6282 sect->set_flags(S_COALESCED);
6284 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6285 sect->set_flags(S_INTERPOSING);
6287 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6288 sect->set_flags(S_CSTRING_LITERALS);
6290 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6291 sect->set_flags(S_4BYTE_LITERALS);
6293 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6294 sect->set_flags(S_8BYTE_LITERALS);
6296 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6297 sect->set_flags(S_16BYTE_LITERALS);
6299 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
6300 sect->set_flags(S_LITERAL_POINTERS);
6302 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6303 sect->set_flags(S_DTRACE_DOF);
6305 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6306 sect->set_flags(S_DTRACE_DOF);
6308 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6309 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
6313 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
6314 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
6315 cmd->set_nsects(sectionsEmitted);
6320 template <typename A>
6321 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
6322 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
6324 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
6325 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
6326 switch ( fWriter.fOptions.outputKind() ) {
6327 case Options::kDynamicExecutable:
6328 case Options::kDynamicLibrary:
6329 case Options::kDynamicBundle:
6330 case Options::kDyld:
6331 fNeedsDynamicSymbolTable = true;
6333 case Options::kObjectFile:
6334 case Options::kStaticExecutable:
6335 fNeedsDynamicSymbolTable = false;
6338 writer.fSymbolTableCommands = this;
6343 template <typename A>
6344 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
6346 fNeedsDynamicSymbolTable = true;
6350 template <typename A>
6351 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
6353 if ( fNeedsDynamicSymbolTable )
6354 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
6356 return this->alignedSize(sizeof(macho_symtab_command<P>));
6359 template <typename A>
6360 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6362 // build LC_DYSYMTAB command
6363 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
6364 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
6365 symbolTableCmd->set_cmd(LC_SYMTAB);
6366 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
6367 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
6368 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
6369 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
6370 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
6372 // build LC_DYSYMTAB command
6373 if ( fNeedsDynamicSymbolTable ) {
6374 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
6375 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
6376 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
6377 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
6378 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
6379 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
6380 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
6381 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
6382 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
6383 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
6384 if ( fWriter.fModuleInfoAtom != NULL ) {
6385 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
6386 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
6387 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
6388 dynamicSymbolTableCmd->set_nmodtab(1);
6389 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
6390 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
6392 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
6393 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
6394 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
6395 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
6396 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
6397 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
6398 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
6404 template <typename A>
6405 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
6407 return fNeedsDynamicSymbolTable ? 2 : 1;
6410 template <typename A>
6411 uint64_t DyldLoadCommandsAtom<A>::getSize() const
6413 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
6416 template <typename A>
6417 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6419 uint64_t size = this->getSize();
6420 bzero(buffer, size);
6421 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
6422 if ( fWriter.fOptions.outputKind() == Options::kDyld )
6423 cmd->set_cmd(LC_ID_DYLINKER);
6425 cmd->set_cmd(LC_LOAD_DYLINKER);
6426 cmd->set_cmdsize(this->getSize());
6427 cmd->set_name_offset();
6428 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
6431 template <typename A>
6432 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
6434 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
6437 template <typename A>
6438 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6440 uint64_t size = this->getSize();
6442 bzero(buffer, size);
6443 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
6444 cmd->set_cmd(LC_SUB_CLIENT);
6445 cmd->set_cmdsize(size);
6446 cmd->set_client_offset();
6447 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
6451 template <typename A>
6452 uint64_t DylibLoadCommandsAtom<A>::getSize() const
6454 if ( fOptimizedAway ) {
6458 const char* path = fInfo.reader->getInstallPath();
6459 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
6463 template <typename A>
6464 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6466 if ( fOptimizedAway )
6468 uint64_t size = this->getSize();
6469 bzero(buffer, size);
6470 const char* path = fInfo.reader->getInstallPath();
6471 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
6472 if ( fInfo.options.fWeakImport )
6473 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
6474 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6475 cmd->set_cmd(LC_REEXPORT_DYLIB);
6477 cmd->set_cmd(LC_LOAD_DYLIB);
6478 cmd->set_cmdsize(this->getSize());
6479 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
6480 cmd->set_current_version(fInfo.reader->getCurrentVersion());
6481 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
6482 cmd->set_name_offset();
6483 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
6488 template <typename A>
6489 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
6491 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
6494 template <typename A>
6495 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6497 uint64_t size = this->getSize();
6498 bzero(buffer, size);
6499 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
6500 cmd->set_cmd(LC_ID_DYLIB);
6501 cmd->set_cmdsize(this->getSize());
6502 cmd->set_name_offset();
6503 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
6504 cmd->set_current_version(fWriter.fOptions.currentVersion());
6505 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
6506 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
6510 template <typename A>
6511 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6513 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6514 bzero(buffer, sizeof(macho_routines_command<P>));
6515 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
6516 cmd->set_cmd(macho_routines_command<P>::CMD);
6517 cmd->set_cmdsize(this->getSize());
6518 cmd->set_init_address(initAddr);
6522 template <typename A>
6523 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
6525 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
6528 template <typename A>
6529 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6531 uint64_t size = this->getSize();
6532 bzero(buffer, size);
6533 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
6534 cmd->set_cmd(LC_SUB_UMBRELLA);
6535 cmd->set_cmdsize(this->getSize());
6536 cmd->set_sub_umbrella_offset();
6537 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
6540 template <typename A>
6541 void UUIDLoadCommandAtom<A>::generate()
6543 switch ( fWriter.fOptions.getUUIDMode() ) {
6544 case Options::kUUIDNone:
6547 case Options::kUUIDRandom:
6548 ::uuid_generate_random(fUUID);
6551 case Options::kUUIDContent:
6558 template <typename A>
6559 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
6561 memcpy(fUUID, uuid, 16);
6564 template <typename A>
6565 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
6568 uint64_t size = this->getSize();
6569 bzero(buffer, size);
6570 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
6571 cmd->set_cmd(LC_UUID);
6572 cmd->set_cmdsize(this->getSize());
6573 cmd->set_uuid((uint8_t*)fUUID);
6578 template <typename A>
6579 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
6581 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
6584 template <typename A>
6585 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6587 uint64_t size = this->getSize();
6588 bzero(buffer, size);
6589 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
6590 cmd->set_cmd(LC_SUB_LIBRARY);
6591 cmd->set_cmdsize(this->getSize());
6592 cmd->set_sub_library_offset();
6593 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
6594 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
6597 template <typename A>
6598 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
6600 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
6603 template <typename A>
6604 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6606 uint64_t size = this->getSize();
6607 bzero(buffer, size);
6608 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
6609 cmd->set_cmd(LC_SUB_FRAMEWORK);
6610 cmd->set_cmdsize(this->getSize());
6611 cmd->set_umbrella_offset();
6612 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
6616 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
6618 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
6622 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
6624 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
6628 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
6630 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
6634 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
6636 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
6640 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
6642 uint64_t size = this->getSize();
6643 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6644 bzero(buffer, size);
6645 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
6646 cmd->set_cmd(LC_UNIXTHREAD);
6647 cmd->set_cmdsize(size);
6648 cmd->set_flavor(1); // PPC_THREAD_STATE
6649 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
6650 cmd->set_thread_register(0, start);
6651 if ( fWriter.fOptions.hasCustomStack() )
6652 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
6657 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
6659 uint64_t size = this->getSize();
6660 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6661 bzero(buffer, size);
6662 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
6663 cmd->set_cmd(LC_UNIXTHREAD);
6664 cmd->set_cmdsize(size);
6665 cmd->set_flavor(5); // PPC_THREAD_STATE64
6666 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
6667 cmd->set_thread_register(0, start);
6668 if ( fWriter.fOptions.hasCustomStack() )
6669 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
6673 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
6675 uint64_t size = this->getSize();
6676 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6677 bzero(buffer, size);
6678 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
6679 cmd->set_cmd(LC_UNIXTHREAD);
6680 cmd->set_cmdsize(size);
6681 cmd->set_flavor(1); // i386_THREAD_STATE
6682 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
6683 cmd->set_thread_register(10, start);
6684 if ( fWriter.fOptions.hasCustomStack() )
6685 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
6690 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
6692 uint64_t size = this->getSize();
6693 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6694 bzero(buffer, size);
6695 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
6696 cmd->set_cmd(LC_UNIXTHREAD);
6697 cmd->set_cmdsize(size);
6698 cmd->set_flavor(x86_THREAD_STATE64);
6699 cmd->set_count(x86_THREAD_STATE64_COUNT);
6700 cmd->set_thread_register(16, start); // rip
6701 if ( fWriter.fOptions.hasCustomStack() )
6702 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
6706 template <typename A>
6707 uint64_t RPathLoadCommandsAtom<A>::getSize() const
6709 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
6712 template <typename A>
6713 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6715 uint64_t size = this->getSize();
6716 bzero(buffer, size);
6717 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
6718 cmd->set_cmd(LC_RPATH);
6719 cmd->set_cmdsize(this->getSize());
6720 cmd->set_path_offset();
6721 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
6725 template <typename A>
6726 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
6728 bzero(buffer, fSize);
6731 template <typename A>
6732 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
6735 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
6736 if ( fWriter.fLargestAtomSize < newSize )
6737 fWriter.fLargestAtomSize = newSize;
6740 template <typename A>
6741 uint64_t LinkEditAtom<A>::getFileOffset() const
6743 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
6747 template <typename A>
6748 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
6750 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
6753 template <typename A>
6754 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6756 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
6760 template <typename A>
6761 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
6763 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
6766 template <typename A>
6767 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6769 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
6774 template <typename A>
6775 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
6777 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
6780 template <typename A>
6781 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6783 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
6786 template <typename A>
6787 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
6789 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
6792 template <typename A>
6793 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6795 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
6796 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
6801 template <typename A>
6802 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
6804 return fTable.size() * sizeof(uint32_t);
6807 template <typename A>
6808 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6810 uint64_t size = this->getSize();
6811 bzero(buffer, size);
6812 const uint32_t indirectTableSize = fTable.size();
6813 uint32_t* indirectTable = (uint32_t*)buffer;
6814 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
6815 if ( it->indirectIndex < indirectTableSize ) {
6816 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
6819 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
6826 template <typename A>
6827 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
6829 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
6830 + sizeof(macho_dylib_module<P>)
6831 + this->getReferencesCount()*sizeof(uint32_t);
6834 template <typename A>
6835 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
6837 return this->getFileOffset();
6840 template <typename A>
6841 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
6843 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
6846 template <typename A>
6847 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
6849 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
6852 template <typename A>
6853 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
6855 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
6858 template <typename A>
6859 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6861 uint64_t size = this->getSize();
6862 bzero(buffer, size);
6863 // create toc. The symbols are already sorted, they are all in the smae module
6864 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
6865 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
6866 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
6867 p->set_module_index(0);
6869 // create module table (one entry)
6870 uint16_t numInits = 0;
6871 uint16_t numTerms = 0;
6872 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6873 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
6874 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
6875 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
6876 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
6877 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
6878 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
6879 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
6880 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
6884 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
6885 module->set_module_name(fModuleNameOffset);
6886 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
6887 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
6888 module->set_irefsym(0);
6889 module->set_nrefsym(this->getReferencesCount());
6890 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
6891 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
6892 module->set_iextrel(0);
6893 module->set_nextrel(fWriter.fExternalRelocs.size());
6894 module->set_iinit_iterm(0,0);
6895 module->set_ninit_nterm(numInits,numTerms);
6896 module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years
6897 module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years
6898 // create reference table
6899 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
6900 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
6901 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
6902 ref->set_flags(REFERENCE_FLAG_DEFINED);
6904 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
6905 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
6906 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
6907 if ( pos != fWriter.fStubsMap.end() )
6908 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
6910 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
6916 template <typename A>
6917 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
6918 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
6920 fCurrentBuffer = new char[kBufferSize];
6921 // burn first byte of string pool (so zero is never a valid string offset)
6922 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
6923 // make offset 1 always point to an empty string
6924 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
6927 template <typename A>
6928 uint64_t StringsLinkEditAtom<A>::getSize() const
6931 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
6934 template <typename A>
6935 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6937 uint64_t offset = 0;
6938 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
6939 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
6940 offset += kBufferSize;
6942 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
6943 // zero fill end to align
6944 offset += fCurrentBufferUsed;
6945 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
6946 buffer[offset++] = 0;
6949 template <typename A>
6950 int32_t StringsLinkEditAtom<A>::add(const char* name)
6952 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
6953 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
6954 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
6955 fCurrentBufferUsed += lenNeeded;
6958 int copied = kBufferSize-fCurrentBufferUsed-1;
6959 // change trailing '\0' that strlcpy added to real char
6960 fCurrentBuffer[kBufferSize-1] = name[copied];
6961 // alloc next buffer
6962 fFullBuffers.push_back(fCurrentBuffer);
6963 fCurrentBuffer = new char[kBufferSize];
6964 fCurrentBufferUsed = 0;
6965 // append rest of string
6966 this->add(&name[copied+1]);
6972 template <typename A>
6973 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
6975 StringToOffset::iterator pos = fUniqueStrings.find(name);
6976 if ( pos != fUniqueStrings.end() ) {
6980 int32_t offset = this->add(name);
6981 fUniqueStrings[name] = offset;
6987 template <typename A>
6988 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
6990 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
6991 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
6992 // check for out of bounds
6993 if ( index > maxIndex )
6995 // check for index in fCurrentBuffer
6996 if ( index > currentBufferStartIndex )
6997 return &fCurrentBuffer[index-currentBufferStartIndex];
6998 // otherwise index is in a full buffer
6999 uint32_t fullBufferIndex = index/kBufferSize;
7000 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
7005 template <typename A>
7006 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
7007 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
7009 char* buf = new char[strlen(name)+32];
7010 if ( targetOffset == 0 ) {
7011 if ( islandRegion == 0 )
7012 sprintf(buf, "%s$island", name);
7014 sprintf(buf, "%s$island_%d", name, islandRegion);
7017 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
7024 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
7026 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
7027 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
7028 OSWriteBigInt32(buffer, 0, branchInstruction);
7032 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
7034 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
7035 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
7036 OSWriteBigInt32(buffer, 0, branchInstruction);
7040 uint64_t BranchIslandAtom<ppc>::getSize() const
7046 uint64_t BranchIslandAtom<ppc64>::getSize() const
7053 template <typename A>
7054 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
7056 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
7057 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
7059 return 0; // a zero size causes the load command to be suppressed
7062 template <typename A>
7063 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7065 uint64_t size = this->getSize();
7066 bzero(buffer, size);
7067 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
7068 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
7069 cmd->set_cmdsize(size);
7070 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
7071 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
7075 template <typename A>
7076 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
7078 return fEncodedData.size();
7081 template <typename A>
7082 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
7084 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
7088 template <typename A>
7089 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
7091 pint_t addr = fWriter.fOptions.baseAddress();
7092 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
7093 pint_t nextAddr = it->atom->getAddress() + it->offset;
7094 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
7095 uint64_t delta = nextAddr - addr;
7097 throw "double split seg info for same address";
7101 byte = delta & 0x7F;
7105 fEncodedData.push_back(byte);
7108 while( byte >= 0x80 );
7113 template <typename A>
7114 void SegmentSplitInfoContentAtom<A>::encode()
7116 if ( ! fCantEncode ) {
7117 fEncodedData.reserve(8192);
7119 if ( fKind1Locations.size() != 0 ) {
7120 fEncodedData.push_back(1);
7121 //fprintf(stderr, "type 1:\n");
7122 this->uleb128EncodeAddresses(fKind1Locations);
7123 fEncodedData.push_back(0);
7126 if ( fKind2Locations.size() != 0 ) {
7127 fEncodedData.push_back(2);
7128 //fprintf(stderr, "type 2:\n");
7129 this->uleb128EncodeAddresses(fKind2Locations);
7130 fEncodedData.push_back(0);
7133 if ( fKind3Locations.size() != 0 ) {
7134 fEncodedData.push_back(3);
7135 //fprintf(stderr, "type 3:\n");
7136 this->uleb128EncodeAddresses(fKind3Locations);
7137 fEncodedData.push_back(0);
7140 if ( fKind4Locations.size() != 0 ) {
7141 fEncodedData.push_back(4);
7142 //fprintf(stderr, "type 4:\n");
7143 this->uleb128EncodeAddresses(fKind4Locations);
7144 fEncodedData.push_back(0);
7147 // always add zero byte to mark end
7148 fEncodedData.push_back(0);
7150 // add zeros to end to align size
7151 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
7152 fEncodedData.push_back(0);
7157 template <typename A>
7158 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
7159 : WriterAtom<A>(writer, getInfoSegment())
7163 // struct objc_image_info {
7164 // uint32_t version; // initially 0
7167 // #define OBJC_IMAGE_SUPPORTS_GC 2
7168 // #define OBJC_IMAGE_GC_ONLY 4
7170 if ( objcReplacementClasses )
7172 switch ( objcConstraint ) {
7173 case ObjectFile::Reader::kObjcNone:
7174 case ObjectFile::Reader::kObjcRetainRelease:
7176 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
7179 case ObjectFile::Reader::kObjcGC:
7183 A::P::E::set32(fContent[1], value);
7186 template <typename A>
7187 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
7189 memcpy(buffer, &fContent[0], 8);
7193 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
7194 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
7195 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
7196 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
7197 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
7199 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
7200 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
7201 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
7202 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
7206 }; // namespace executable
7207 }; // namespace mach_o
7210 #endif // __EXECUTABLE_MACH_O__