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 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
2389 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
2390 case ObjectFile::Atom::kExternalDefinition:
2391 case ObjectFile::Atom::kExternalWeakDefinition:
2392 return shouldExport(target);
2397 template <typename A>
2398 void Writer<A>::buildFixups()
2400 if ( fOptions.outputKind() == Options::kObjectFile ) {
2401 this->buildObjectFileFixups();
2404 if ( fOptions.keepRelocations() )
2405 this->buildObjectFileFixups();
2406 this->buildExecutableFixups();
2411 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2413 ObjectFile::Atom& target = ref->getTarget();
2414 bool external = this->makesExternalRelocatableReference(target);
2415 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
2416 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2417 macho_relocation_info<P> reloc1;
2418 macho_relocation_info<P> reloc2;
2419 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
2422 case x86_64::kNoFixUp:
2423 case x86_64::kFollowOn:
2426 case x86_64::kPointer:
2427 case x86_64::kPointerWeakImport:
2428 reloc1.set_r_address(address);
2429 reloc1.set_r_symbolnum(symbolIndex);
2430 reloc1.set_r_pcrel(false);
2431 reloc1.set_r_length(3);
2432 reloc1.set_r_extern(external);
2433 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2434 fSectionRelocs.push_back(reloc1);
2437 case x86_64::kPointerDiff32:
2438 case x86_64::kPointerDiff:
2440 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2441 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2442 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
2443 reloc1.set_r_address(address);
2444 reloc1.set_r_symbolnum(symbolIndex);
2445 reloc1.set_r_pcrel(false);
2446 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2447 reloc1.set_r_extern(external);
2448 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2449 reloc2.set_r_address(address);
2450 reloc2.set_r_symbolnum(fromSymbolIndex);
2451 reloc2.set_r_pcrel(false);
2452 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2453 reloc2.set_r_extern(fromExternal);
2454 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
2455 fSectionRelocs.push_back(reloc1);
2456 fSectionRelocs.push_back(reloc2);
2460 case x86_64::kBranchPCRel32:
2461 case x86_64::kBranchPCRel32WeakImport:
2462 case x86_64::kDtraceProbeSite:
2463 case x86_64::kDtraceIsEnabledSite:
2464 reloc1.set_r_address(address);
2465 reloc1.set_r_symbolnum(symbolIndex);
2466 reloc1.set_r_pcrel(true);
2467 reloc1.set_r_length(2);
2468 reloc1.set_r_extern(external);
2469 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2470 fSectionRelocs.push_back(reloc1);
2473 case x86_64::kPCRel32:
2474 reloc1.set_r_address(address);
2475 reloc1.set_r_symbolnum(symbolIndex);
2476 reloc1.set_r_pcrel(true);
2477 reloc1.set_r_length(2);
2478 reloc1.set_r_extern(external);
2479 reloc1.set_r_type(X86_64_RELOC_SIGNED);
2480 fSectionRelocs.push_back(reloc1);
2483 case x86_64::kPCRel32_1:
2484 reloc1.set_r_address(address);
2485 reloc1.set_r_symbolnum(symbolIndex);
2486 reloc1.set_r_pcrel(true);
2487 reloc1.set_r_length(2);
2488 reloc1.set_r_extern(external);
2489 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
2490 fSectionRelocs.push_back(reloc1);
2493 case x86_64::kPCRel32_2:
2494 reloc1.set_r_address(address);
2495 reloc1.set_r_symbolnum(symbolIndex);
2496 reloc1.set_r_pcrel(true);
2497 reloc1.set_r_length(2);
2498 reloc1.set_r_extern(external);
2499 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
2500 fSectionRelocs.push_back(reloc1);
2503 case x86_64::kPCRel32_4:
2504 reloc1.set_r_address(address);
2505 reloc1.set_r_symbolnum(symbolIndex);
2506 reloc1.set_r_pcrel(true);
2507 reloc1.set_r_length(2);
2508 reloc1.set_r_extern(external);
2509 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
2510 fSectionRelocs.push_back(reloc1);
2513 case x86_64::kPCRel32GOT:
2514 case x86_64::kPCRel32GOTWeakImport:
2515 reloc1.set_r_address(address);
2516 reloc1.set_r_symbolnum(symbolIndex);
2517 reloc1.set_r_pcrel(true);
2518 reloc1.set_r_length(2);
2519 reloc1.set_r_extern(external);
2520 reloc1.set_r_type(X86_64_RELOC_GOT);
2521 fSectionRelocs.push_back(reloc1);
2524 case x86_64::kPCRel32GOTLoad:
2525 case x86_64::kPCRel32GOTLoadWeakImport:
2526 reloc1.set_r_address(address);
2527 reloc1.set_r_symbolnum(symbolIndex);
2528 reloc1.set_r_pcrel(true);
2529 reloc1.set_r_length(2);
2530 reloc1.set_r_extern(external);
2531 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
2532 fSectionRelocs.push_back(reloc1);
2535 case x86_64::kDtraceTypeReference:
2536 case x86_64::kDtraceProbe:
2537 // generates no relocs
2545 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2547 ObjectFile::Atom& target = ref->getTarget();
2548 bool isExtern = this->makesExternalRelocatableReference(target);
2549 uint32_t symbolIndex = 0;
2551 symbolIndex = this->symbolIndex(target);
2552 uint32_t sectionNum = target.getSection()->getIndex();
2553 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2554 macho_relocation_info<P> reloc1;
2555 macho_relocation_info<P> reloc2;
2556 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2557 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2558 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
2560 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2561 fprintf(stderr, "ld: warning section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s\n",
2562 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2567 case x86::kFollowOn:
2571 case x86::kPointerWeakImport:
2572 case x86::kAbsolute32:
2573 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2574 // use scattered reloc is target offset is non-zero
2575 sreloc1->set_r_scattered(true);
2576 sreloc1->set_r_pcrel(false);
2577 sreloc1->set_r_length(2);
2578 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2579 sreloc1->set_r_address(address);
2580 sreloc1->set_r_value(target.getAddress());
2583 reloc1.set_r_address(address);
2584 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2585 reloc1.set_r_pcrel(false);
2586 reloc1.set_r_length(2);
2587 reloc1.set_r_extern(isExtern);
2588 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2590 fSectionRelocs.push_back(reloc1);
2593 case x86::kPointerDiff16:
2594 case x86::kPointerDiff:
2596 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2597 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
2598 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
2599 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
2600 sreloc1->set_r_scattered(true);
2601 sreloc1->set_r_pcrel(false);
2602 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2603 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2604 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
2606 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
2607 sreloc1->set_r_address(address);
2608 sreloc1->set_r_value(target.getAddress());
2609 sreloc2->set_r_scattered(true);
2610 sreloc2->set_r_pcrel(false);
2611 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2612 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
2613 sreloc2->set_r_address(0);
2614 //if ( &ref->getFromTarget() == &ref->getTarget() )
2615 sreloc2->set_r_value(ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
2617 // sreloc2->set_r_value(ref->getFromTarget().getAddress());
2618 fSectionRelocs.push_back(reloc2);
2619 fSectionRelocs.push_back(reloc1);
2623 case x86::kPCRel32WeakImport:
2626 case x86::kDtraceProbeSite:
2627 case x86::kDtraceIsEnabledSite:
2628 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2629 // use scattered reloc is target offset is non-zero
2630 sreloc1->set_r_scattered(true);
2631 sreloc1->set_r_pcrel(true);
2632 sreloc1->set_r_length( (kind==x86::kPCRel16) ? 1 : 2);
2633 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2634 sreloc1->set_r_address(address);
2635 sreloc1->set_r_value(target.getAddress());
2638 reloc1.set_r_address(address);
2639 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2640 reloc1.set_r_pcrel(true);
2641 reloc1.set_r_length( (kind==x86::kPCRel16) ? 1 : 2);
2642 reloc1.set_r_extern(isExtern);
2643 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2645 fSectionRelocs.push_back(reloc1);
2648 case x86::kDtraceTypeReference:
2649 case x86::kDtraceProbe:
2650 // generates no relocs
2660 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
2661 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
2662 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
2663 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
2667 uint8_t Writer<ppc>::getRelocPointerSize()
2673 uint8_t Writer<ppc64>::getRelocPointerSize()
2679 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2681 return addObjectRelocs_powerpc(atom, ref);
2685 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2687 return addObjectRelocs_powerpc(atom, ref);
2691 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
2692 // they use a common addObjectRelocs_powerpc() method.
2694 template <typename A>
2695 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2697 ObjectFile::Atom& target = ref->getTarget();
2698 bool isExtern = this->makesExternalRelocatableReference(target);
2699 uint32_t symbolIndex = 0;
2701 symbolIndex = this->symbolIndex(target);
2702 uint32_t sectionNum = target.getSection()->getIndex();
2703 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2704 macho_relocation_info<P> reloc1;
2705 macho_relocation_info<P> reloc2;
2706 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2707 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2708 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
2716 case A::kPointerWeakImport:
2717 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
2718 // use scattered reloc is target offset is outside target
2719 sreloc1->set_r_scattered(true);
2720 sreloc1->set_r_pcrel(false);
2721 sreloc1->set_r_length(getRelocPointerSize());
2722 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2723 sreloc1->set_r_address(address);
2724 sreloc1->set_r_value(target.getAddress());
2727 reloc1.set_r_address(address);
2729 reloc1.set_r_symbolnum(symbolIndex);
2731 reloc1.set_r_symbolnum(sectionNum);
2732 reloc1.set_r_pcrel(false);
2733 reloc1.set_r_length(getRelocPointerSize());
2734 reloc1.set_r_extern(isExtern);
2735 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2737 fSectionRelocs.push_back(reloc1);
2740 case A::kPointerDiff16:
2741 case A::kPointerDiff32:
2742 case A::kPointerDiff64:
2744 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2745 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2746 sreloc1->set_r_scattered(true);
2747 sreloc1->set_r_pcrel(false);
2748 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
2749 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
2750 sreloc1->set_r_address(address);
2751 sreloc1->set_r_value(toAddr);
2752 sreloc2->set_r_scattered(true);
2753 sreloc2->set_r_pcrel(false);
2754 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
2755 sreloc2->set_r_type(PPC_RELOC_PAIR);
2756 sreloc2->set_r_address(0);
2757 sreloc2->set_r_value(fromAddr);
2758 fSectionRelocs.push_back(reloc2);
2759 fSectionRelocs.push_back(reloc1);
2763 case A::kBranch24WeakImport:
2765 case A::kDtraceProbeSite:
2766 case A::kDtraceIsEnabledSite:
2767 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2768 reloc1.set_r_address(address);
2770 reloc1.set_r_symbolnum(symbolIndex);
2772 reloc1.set_r_symbolnum(sectionNum);
2773 reloc1.set_r_pcrel(true);
2774 reloc1.set_r_length(2);
2775 reloc1.set_r_type(PPC_RELOC_BR24);
2776 reloc1.set_r_extern(isExtern);
2779 sreloc1->set_r_scattered(true);
2780 sreloc1->set_r_pcrel(true);
2781 sreloc1->set_r_length(2);
2782 sreloc1->set_r_type(PPC_RELOC_BR24);
2783 sreloc1->set_r_address(address);
2784 sreloc1->set_r_value(target.getAddress());
2786 fSectionRelocs.push_back(reloc1);
2790 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2791 reloc1.set_r_address(address);
2793 reloc1.set_r_symbolnum(symbolIndex);
2795 reloc1.set_r_symbolnum(sectionNum);
2796 reloc1.set_r_pcrel(true);
2797 reloc1.set_r_length(2);
2798 reloc1.set_r_type(PPC_RELOC_BR14);
2799 reloc1.set_r_extern(isExtern);
2802 sreloc1->set_r_scattered(true);
2803 sreloc1->set_r_pcrel(true);
2804 sreloc1->set_r_length(2);
2805 sreloc1->set_r_type(PPC_RELOC_BR14);
2806 sreloc1->set_r_address(address);
2807 sreloc1->set_r_value(target.getAddress());
2809 fSectionRelocs.push_back(reloc1);
2812 case A::kPICBaseLow16:
2813 case A::kPICBaseLow14:
2815 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2816 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2817 sreloc1->set_r_scattered(true);
2818 sreloc1->set_r_pcrel(false);
2819 sreloc1->set_r_length(2);
2820 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
2821 sreloc1->set_r_address(address);
2822 sreloc1->set_r_value(target.getAddress());
2823 sreloc2->set_r_scattered(true);
2824 sreloc2->set_r_pcrel(false);
2825 sreloc2->set_r_length(2);
2826 sreloc2->set_r_type(PPC_RELOC_PAIR);
2827 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
2828 sreloc2->set_r_value(fromAddr);
2829 fSectionRelocs.push_back(reloc2);
2830 fSectionRelocs.push_back(reloc1);
2834 case A::kPICBaseHigh16:
2836 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2837 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2838 sreloc1->set_r_scattered(true);
2839 sreloc1->set_r_pcrel(false);
2840 sreloc1->set_r_length(2);
2841 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
2842 sreloc1->set_r_address(address);
2843 sreloc1->set_r_value(target.getAddress());
2844 sreloc2->set_r_scattered(true);
2845 sreloc2->set_r_pcrel(false);
2846 sreloc2->set_r_length(2);
2847 sreloc2->set_r_type(PPC_RELOC_PAIR);
2848 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
2849 sreloc2->set_r_value(fromAddr);
2850 fSectionRelocs.push_back(reloc2);
2851 fSectionRelocs.push_back(reloc1);
2858 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2859 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2860 reloc1.set_r_address(address);
2862 reloc1.set_r_symbolnum(symbolIndex);
2864 reloc1.set_r_symbolnum(sectionNum);
2865 reloc1.set_r_pcrel(false);
2866 reloc1.set_r_length(2);
2867 reloc1.set_r_extern(isExtern);
2868 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2871 sreloc1->set_r_scattered(true);
2872 sreloc1->set_r_pcrel(false);
2873 sreloc1->set_r_length(2);
2874 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2875 sreloc1->set_r_address(address);
2876 sreloc1->set_r_value(target.getAddress());
2879 reloc2.set_r_address(ref->getTargetOffset() >> 16);
2881 reloc2.set_r_address(toAddr >> 16);
2882 reloc2.set_r_symbolnum(0);
2883 reloc2.set_r_pcrel(false);
2884 reloc2.set_r_length(2);
2885 reloc2.set_r_extern(false);
2886 reloc2.set_r_type(PPC_RELOC_PAIR);
2887 fSectionRelocs.push_back(reloc2);
2888 fSectionRelocs.push_back(reloc1);
2894 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2895 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2896 reloc1.set_r_address(address);
2898 reloc1.set_r_symbolnum(symbolIndex);
2900 reloc1.set_r_symbolnum(sectionNum);
2901 reloc1.set_r_pcrel(false);
2902 reloc1.set_r_length(2);
2903 reloc1.set_r_extern(isExtern);
2904 reloc1.set_r_type(PPC_RELOC_HI16);
2907 sreloc1->set_r_scattered(true);
2908 sreloc1->set_r_pcrel(false);
2909 sreloc1->set_r_length(2);
2910 sreloc1->set_r_type(PPC_RELOC_HI16);
2911 sreloc1->set_r_address(address);
2912 sreloc1->set_r_value(target.getAddress());
2915 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2917 reloc2.set_r_address(toAddr & 0xFFFF);
2918 reloc2.set_r_symbolnum(0);
2919 reloc2.set_r_pcrel(false);
2920 reloc2.set_r_length(2);
2921 reloc2.set_r_extern(false);
2922 reloc2.set_r_type(PPC_RELOC_PAIR);
2923 fSectionRelocs.push_back(reloc2);
2924 fSectionRelocs.push_back(reloc1);
2928 case A::kAbsHigh16AddLow:
2930 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2931 uint32_t overflow = 0;
2932 if ( (toAddr & 0x00008000) != 0 )
2934 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2935 reloc1.set_r_address(address);
2937 reloc1.set_r_symbolnum(symbolIndex);
2939 reloc1.set_r_symbolnum(sectionNum);
2940 reloc1.set_r_pcrel(false);
2941 reloc1.set_r_length(2);
2942 reloc1.set_r_extern(isExtern);
2943 reloc1.set_r_type(PPC_RELOC_HA16);
2946 sreloc1->set_r_scattered(true);
2947 sreloc1->set_r_pcrel(false);
2948 sreloc1->set_r_length(2);
2949 sreloc1->set_r_type(PPC_RELOC_HA16);
2950 sreloc1->set_r_address(address);
2951 sreloc1->set_r_value(target.getAddress());
2954 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2956 reloc2.set_r_address(toAddr & 0xFFFF);
2957 reloc2.set_r_symbolnum(0);
2958 reloc2.set_r_pcrel(false);
2959 reloc2.set_r_length(2);
2960 reloc2.set_r_extern(false);
2961 reloc2.set_r_type(PPC_RELOC_PAIR);
2962 fSectionRelocs.push_back(reloc2);
2963 fSectionRelocs.push_back(reloc1);
2967 case A::kDtraceTypeReference:
2968 case A::kDtraceProbe:
2969 // generates no relocs
2978 // There are cases when an entry in the indirect symbol table is the magic value
2979 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
2980 // the content of the corresponding part of the __nl_symbol_pointer section
2981 // must also change.
2983 template <typename A>
2984 bool Writer<A>::indirectSymbolIsLocal(const ObjectFile::Reference* ref) const
2986 // use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
2987 return ( !this->shouldExport(ref->getTarget()) || (ref->getTargetOffset() != 0) );
2991 template <typename A>
2992 void Writer<A>::buildObjectFileFixups()
2994 uint32_t relocIndex = 0;
2995 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2996 const int segCount = segmentInfos.size();
2997 for(int i=0; i < segCount; ++i) {
2998 SegmentInfo* curSegment = segmentInfos[i];
2999 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3000 const int sectionCount = sectionInfos.size();
3001 for(int j=0; j < sectionCount; ++j) {
3002 SectionInfo* curSection = sectionInfos[j];
3003 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
3004 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3005 if ( ! curSection->fAllZeroFill ) {
3006 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
3007 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3008 curSection->fRelocOffset = relocIndex;
3009 const int atomCount = sectionAtoms.size();
3010 for (int k=0; k < atomCount; ++k) {
3011 ObjectFile::Atom* atom = sectionAtoms[k];
3012 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
3013 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3014 const int refCount = refs.size();
3015 for (int l=0; l < refCount; ++l) {
3016 ObjectFile::Reference* ref = refs[l];
3017 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
3018 uint32_t offsetInSection = atom->getSectionOffset();
3019 uint32_t indexInSection = offsetInSection / atom->getSize();
3020 uint32_t undefinedSymbolIndex;
3021 if ( curSection->fAllStubs ) {
3022 ObjectFile::Atom& stubTarget =ref->getTarget();
3023 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
3024 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
3025 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
3027 else if ( curSection->fAllNonLazyPointers) {
3028 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3029 if ( this->indirectSymbolIsLocal(ref) )
3030 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3032 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
3035 // should never get here, fAllLazyPointers not used in generated .o files
3036 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3038 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3039 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3040 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
3041 fIndirectTableAtom->fTable.push_back(entry);
3042 if ( curSection->fAllLazyPointers ) {
3043 ObjectFile::Atom& target = ref->getTarget();
3044 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3045 if ( &fromTarget == NULL ) {
3046 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
3049 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3050 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
3051 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
3052 macho_relocation_info<P> reloc1;
3053 reloc1.set_r_address(atom->getSectionOffset());
3054 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
3055 reloc1.set_r_pcrel(false);
3056 reloc1.set_r_length();
3057 reloc1.set_r_extern(isExtern);
3058 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3059 fSectionRelocs.push_back(reloc1);
3063 else if ( curSection->fAllStubs ) {
3064 relocIndex += this->addObjectRelocs(atom, ref);
3067 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
3068 relocIndex += this->addObjectRelocs(atom, ref);
3072 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
3077 // reverse the relocs
3078 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
3080 // now reverse section reloc offsets
3081 for(int i=0; i < segCount; ++i) {
3082 SegmentInfo* curSegment = segmentInfos[i];
3083 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3084 const int sectionCount = sectionInfos.size();
3085 for(int j=0; j < sectionCount; ++j) {
3086 SectionInfo* curSection = sectionInfos[j];
3087 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
3094 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3096 switch ( ref.getKind() ) {
3097 case ppc::kAbsLow16:
3098 case ppc::kAbsLow14:
3099 case ppc::kAbsHigh16:
3100 case ppc::kAbsHigh16AddLow:
3109 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3111 switch ( ref.getKind() ) {
3112 case ppc::kAbsLow16:
3113 case ppc::kAbsLow14:
3114 case ppc::kAbsHigh16:
3115 case ppc::kAbsHigh16AddLow:
3123 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3125 if ( ref.getKind() == x86::kAbsolute32 ) {
3126 switch ( ref.getTarget().getDefinitionKind() ) {
3127 case ObjectFile::Atom::kTentativeDefinition:
3128 case ObjectFile::Atom::kRegularDefinition:
3129 case ObjectFile::Atom::kWeakDefinition:
3130 // illegal in dylibs/bundles, until we support TEXT relocs
3132 case ObjectFile::Atom::kExternalDefinition:
3133 case ObjectFile::Atom::kExternalWeakDefinition:
3134 // illegal until we support TEXT relocs
3136 case ObjectFile::Atom::kAbsoluteSymbol:
3137 // absolute symbbols only allowed in static executables
3138 return ( fOptions.outputKind() != Options::kStaticExecutable);
3145 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3151 template <typename A>
3152 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
3154 switch ( target.getDefinitionKind() ) {
3155 case ObjectFile::Atom::kTentativeDefinition:
3156 case ObjectFile::Atom::kRegularDefinition:
3157 // in main executables, the only way regular symbols are indirected is if -interposable is used
3158 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
3159 if ( this->shouldExport(target) && fOptions.interposable() )
3160 return kRelocExternal;
3161 else if ( fSlideable )
3162 return kRelocInternal;
3166 // for flat-namespace or interposable two-level-namespace
3167 // all references to exported symbols get indirected
3168 else if ( this->shouldExport(target) &&
3169 ((fOptions.nameSpace() == Options::kFlatNameSpace)
3170 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
3171 || fOptions.interposable())
3172 && (target.getName() != NULL)
3173 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
3174 return kRelocExternal;
3175 else if ( fSlideable )
3176 return kRelocInternal;
3179 case ObjectFile::Atom::kWeakDefinition:
3180 // all calls to global weak definitions get indirected
3181 if ( this->shouldExport(target) )
3182 return kRelocExternal;
3183 else if ( fSlideable )
3184 return kRelocInternal;
3187 case ObjectFile::Atom::kExternalDefinition:
3188 case ObjectFile::Atom::kExternalWeakDefinition:
3189 return kRelocExternal;
3190 case ObjectFile::Atom::kAbsoluteSymbol:
3196 template <typename A>
3197 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3199 // for 32-bit architectures, the r_address field in relocs
3200 // for final linked images is the offset from the first segment
3201 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
3202 // or the offset from the first writable segment if built split-seg
3203 if ( fOptions.splitSeg() )
3204 result = address - fFirstWritableSegment->fBaseAddress;
3205 if ( result > 0x7FFFFFFF ) {
3206 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
3207 atom->getDisplayName(), atom->getFile()->getPath());
3213 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3215 // for x86_64, the r_address field in relocs for final linked images
3216 // is the offset from the start address of the first writable segment
3217 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
3218 if ( result > 0xFFFFFFFF ) {
3219 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3220 atom->getDisplayName(), atom->getFile()->getPath());
3226 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3228 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
3229 // the 10.5 dyld, iterprets the r_address as:
3230 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
3231 // 2) an offset from the base address of the first writable segment
3232 // For dyld, r_address is always the offset from the base address
3234 bool badFor10_4 = false;
3235 if ( fWritableSegmentPastFirst4GB ) {
3236 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
3238 result = address - fFirstWritableSegment->fBaseAddress;
3239 if ( result > 0xFFFFFFFF ) {
3240 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3241 atom->getDisplayName(), atom->getFile()->getPath());
3245 result = address - fSegmentInfos[0]->fBaseAddress;
3246 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
3250 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",
3251 atom->getDisplayName(), atom->getFile()->getPath());
3257 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
3258 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3259 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
3260 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3263 template <typename A>
3264 void Writer<A>::buildExecutableFixups()
3266 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
3267 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3268 const int segCount = segmentInfos.size();
3269 for(int i=0; i < segCount; ++i) {
3270 SegmentInfo* curSegment = segmentInfos[i];
3271 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3272 const int sectionCount = sectionInfos.size();
3273 for(int j=0; j < sectionCount; ++j) {
3274 SectionInfo* curSection = sectionInfos[j];
3275 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
3276 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3277 if ( ! curSection->fAllZeroFill ) {
3278 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
3279 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3280 const int atomCount = sectionAtoms.size();
3281 for (int k=0; k < atomCount; ++k) {
3282 ObjectFile::Atom* atom = sectionAtoms[k];
3283 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3284 const int refCount = refs.size();
3285 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
3286 for (int l=0; l < refCount; ++l) {
3287 ObjectFile::Reference* ref = refs[l];
3288 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
3289 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
3290 if ( atom->getSize() != sizeof(pint_t) ) {
3291 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
3293 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
3294 if ( curSection->fAllLazyPointers ) {
3295 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
3297 uint32_t offsetInSection = atom->getSectionOffset();
3298 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
3299 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3300 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
3301 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
3302 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3303 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3304 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
3305 fIndirectTableAtom->fTable.push_back(entry);
3306 if ( curSection->fAllLazyPointers ) {
3307 uint8_t preboundLazyType;
3308 if ( fOptions.prebind() && (fDyldHelper != NULL) && preboundLazyPointerType(&preboundLazyType) ) {
3309 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
3310 macho_scattered_relocation_info<P> pblaReloc;
3311 pblaReloc.set_r_scattered(true);
3312 pblaReloc.set_r_pcrel(false);
3313 pblaReloc.set_r_length();
3314 pblaReloc.set_r_type(preboundLazyType);
3315 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3316 pblaReloc.set_r_value(fDyldHelper->getAddress());
3317 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
3319 else if ( fSlideable ) {
3320 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
3321 macho_relocation_info<P> dyldHelperReloc;
3322 uint32_t sectionNum = 1;
3323 if ( fDyldHelper != NULL )
3324 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
3325 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
3326 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3327 dyldHelperReloc.set_r_symbolnum(sectionNum);
3328 dyldHelperReloc.set_r_pcrel(false);
3329 dyldHelperReloc.set_r_length();
3330 dyldHelperReloc.set_r_extern(false);
3331 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
3332 fInternalRelocs.push_back(dyldHelperReloc);
3336 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
3337 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
3338 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
3339 atom->getDisplayName(), atom->getFile()->getPath());
3341 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
3345 case kRelocInternal:
3347 macho_relocation_info<P> internalReloc;
3348 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
3349 uint32_t sectionNum = sectInfo->getIndex();
3350 // special case _mh_dylib_header and friends which are not in any real section
3351 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
3353 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3354 internalReloc.set_r_symbolnum(sectionNum);
3355 internalReloc.set_r_pcrel(false);
3356 internalReloc.set_r_length();
3357 internalReloc.set_r_extern(false);
3358 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3359 fInternalRelocs.push_back(internalReloc);
3362 case kRelocExternal:
3364 macho_relocation_info<P> externalReloc;
3365 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3366 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
3367 externalReloc.set_r_pcrel(false);
3368 externalReloc.set_r_length();
3369 externalReloc.set_r_extern(true);
3370 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3371 fExternalRelocs.push_back(externalReloc);
3376 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
3377 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
3380 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
3381 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
3382 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
3383 uint32_t offsetInSection = atom->getSectionOffset();
3384 uint32_t indexInSection = offsetInSection / atom->getSize();
3385 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3386 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3387 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
3388 fIndirectTableAtom->fTable.push_back(entry);
3394 if ( fSplitCodeToDataContentAtom != NULL )
3395 fSplitCodeToDataContentAtom->encode();
3400 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3402 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
3403 case ppc::kPICBaseHigh16:
3404 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
3406 case ppc::kPointerDiff32:
3407 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3409 case ppc::kPointerDiff64:
3410 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3414 case ppc::kPointerWeakImport:
3415 case ppc::kPICBaseLow16:
3416 case ppc::kPICBaseLow14:
3420 fprintf(stderr, "ld: warning codegen with reference kind %d in %s prevents image from loading in dyld shared cache\n", ref->getKind(), atom->getDisplayName());
3421 fSplitCodeToDataContentAtom->setCantEncode();
3426 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3428 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
3429 case ppc64::kPICBaseHigh16:
3430 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
3432 case ppc64::kPointerDiff32:
3433 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3435 case ppc64::kPointerDiff64:
3436 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3438 case ppc64::kNoFixUp:
3439 case ppc64::kPointer:
3440 case ppc64::kPointerWeakImport:
3441 case ppc64::kPICBaseLow16:
3442 case ppc64::kPICBaseLow14:
3446 fprintf(stderr, "ld: warning codegen with reference kind %d in %s prevents image from loading in dyld shared cache\n", ref->getKind(), atom->getDisplayName());
3447 fSplitCodeToDataContentAtom->setCantEncode();
3452 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3454 switch ( (x86::ReferenceKinds)ref->getKind() ) {
3455 case x86::kPointerDiff:
3456 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
3457 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
3459 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3463 case x86::kPointerWeakImport:
3467 case x86::kPCRel32WeakImport:
3468 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
3469 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
3470 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
3473 // fall into warning case
3475 fprintf(stderr, "ld: warning codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache\n", atom->getDisplayName(), ref->getFixUpOffset());
3476 fSplitCodeToDataContentAtom->setCantEncode();
3481 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3483 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
3484 case x86_64::kPCRel32:
3485 case x86_64::kPCRel32_1:
3486 case x86_64::kPCRel32_2:
3487 case x86_64::kPCRel32_4:
3488 case x86_64::kPCRel32GOTLoad:
3489 case x86_64::kPCRel32GOTLoadWeakImport:
3490 case x86_64::kPCRel32GOT:
3491 case x86_64::kPCRel32GOTWeakImport:
3492 case x86_64::kPointerDiff32:
3493 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3495 case x86_64::kPointerDiff:
3496 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3498 case x86_64::kNoFixUp:
3499 case x86_64::kPointer:
3503 fprintf(stderr, "ld: warning codegen in %s with kind %d prevents image from loading in dyld shared cache\n", atom->getDisplayName(), ref->getKind());
3504 fSplitCodeToDataContentAtom->setCantEncode();
3509 template <typename A>
3510 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
3512 switch ( to.getDefinitionKind() ) {
3513 case ObjectFile::Atom::kExternalDefinition:
3514 case ObjectFile::Atom::kExternalWeakDefinition:
3515 case ObjectFile::Atom::kAbsoluteSymbol:
3517 case ObjectFile::Atom::kRegularDefinition:
3518 case ObjectFile::Atom::kWeakDefinition:
3519 case ObjectFile::Atom::kTentativeDefinition:
3520 // segments with same permissions slide together
3521 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
3522 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
3524 throw "ld64 internal error";
3529 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
3532 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
3533 for (uint32_t p=from; p < to; p += 4)
3534 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
3538 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
3541 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
3542 for (uint32_t p=from; p < to; p += 4)
3543 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
3547 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
3549 uint8_t x86Nop = 0x90;
3550 for (uint32_t p=from; p < to; ++p)
3551 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
3555 void Writer<x86_64>::writeNoOps(uint32_t from, uint32_t to)
3557 uint8_t x86Nop = 0x90;
3558 for (uint32_t p=from; p < to; ++p)
3559 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
3564 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
3566 for (uint8_t* p=from; p < to; p += 4)
3567 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
3571 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
3573 for (uint8_t* p=from; p < to; p += 4)
3574 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
3578 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
3580 for (uint8_t* p=from; p < to; ++p)
3585 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
3587 for (uint8_t* p=from; p < to; ++p)
3592 static const char* stringName(const char* str)
3594 if ( strncmp(str, "cstring=", 8) == 0) {
3595 static char buffer[1024];
3598 for(const char*s = &str[8]; *s != '\0'; ++s) {
3612 if ( t > &buffer[1020] ) {
3631 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
3632 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
3633 template <> const char* Writer<x86>::getArchString() { return "i386"; }
3634 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
3636 template <typename A>
3637 void Writer<A>::writeMap()
3639 if ( fOptions.generatedMapPath() != NULL ) {
3640 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
3641 if ( mapFile != NULL ) {
3642 // write output path
3643 fprintf(mapFile, "# Path: %s\n", fFilePath);
3644 // write output architecure
3645 fprintf(mapFile, "# Arch: %s\n", getArchString());
3647 if ( fUUIDAtom != NULL ) {
3648 const uint8_t* uuid = fUUIDAtom->getUUID();
3649 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
3650 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
3651 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
3653 // write table of object files
3654 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
3655 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
3656 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
3657 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3658 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3659 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3660 if ( ! (*secit)->fVirtualSection ) {
3661 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3662 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3663 ObjectFile::Reader* reader = (*ait)->getFile();
3664 uint32_t readerOrdinal = (*ait)->getOrdinal();
3665 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
3666 if ( pos == readerToOrdinal.end() ) {
3667 readerToOrdinal[reader] = readerOrdinal;
3668 ordinalToReader[readerOrdinal] = reader;
3674 fprintf(mapFile, "# Object files:\n");
3675 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
3676 uint32_t fileIndex = 0;
3677 readerToFileOrdinal[this] = fileIndex++;
3678 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
3679 if ( it->first != 0 ) {
3680 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
3681 readerToFileOrdinal[it->second] = fileIndex++;
3684 // write table of sections
3685 fprintf(mapFile, "# Sections:\n");
3686 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
3687 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3688 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3689 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3690 if ( ! (*secit)->fVirtualSection ) {
3691 SectionInfo* sect = *secit;
3692 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
3693 (*segit)->fName, sect->fSectionName);
3697 // write table of symbols
3698 fprintf(mapFile, "# Symbols:\n");
3699 fprintf(mapFile, "# Address\tSize \tFile Name\n");
3700 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3701 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3702 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3703 if ( ! (*secit)->fVirtualSection ) {
3704 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3705 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
3706 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3707 ObjectFile::Atom* atom = *ait;
3708 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
3709 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
3717 fprintf(stderr, "ld: warning could not write map file: %s\n", fOptions.generatedMapPath());
3722 template <typename A>
3723 uint64_t Writer<A>::writeAtoms()
3725 // try to allocate buffer for entire output file content
3726 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
3727 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
3728 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
3729 uint8_t* atomBuffer = NULL;
3730 bool streaming = false;
3731 if ( wholeBuffer == NULL ) {
3732 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
3737 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3738 SegmentInfo* curSegment = *segit;
3739 bool isTextSeg = (strcmp(curSegment->fName, "__TEXT") == 0);
3740 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3741 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3742 SectionInfo* curSection = *secit;
3743 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3744 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
3745 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
3746 if ( ! curSection->fAllZeroFill ) {
3747 end = curSection->fFileOffset;
3748 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
3749 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3750 ObjectFile::Atom* atom = *ait;
3751 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
3752 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
3753 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
3754 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
3755 if ( fileOffset != end ) {
3757 // fill gaps with no-ops
3759 writeNoOps(end, fileOffset);
3761 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
3763 else if ( streaming ) {
3765 if ( (fileOffset-end) == 4 ) {
3767 ::pwrite(fFileDescriptor, &zero, 4, end);
3770 uint8_t zero = 0x00;
3771 for (uint32_t p=end; p < fileOffset; ++p)
3772 ::pwrite(fFileDescriptor, &zero, 1, p);
3776 uint64_t atomSize = atom->getSize();
3778 if ( atomSize > fLargestAtomSize )
3779 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
3780 atom->getDisplayName(), atomSize, fLargestAtomSize);
3783 if ( fileOffset > fileBufferSize )
3784 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
3785 atom->getDisplayName(), fileOffset, fileBufferSize);
3787 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
3788 end = fileOffset+atomSize;
3790 atom->copyRawContent(buffer);
3791 // apply any fix-ups
3793 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3794 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
3795 ObjectFile::Reference* ref = *it;
3796 if ( fOptions.outputKind() == Options::kObjectFile ) {
3798 // skip fix-ups for undefined targets
3799 if ( &(ref->getTarget()) != NULL )
3800 this->fixUpReferenceRelocatable(ref, atom, buffer);
3803 // producing final linked image
3804 this->fixUpReferenceFinal(ref, atom, buffer);
3808 catch (const char* msg) {
3809 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3811 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
3812 // fileOffset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
3815 ::pwrite(fFileDescriptor, buffer, atomSize, fileOffset);
3818 if ( (fileOffset + atomSize) > size )
3819 size = fileOffset + atomSize;
3827 // update content based UUID
3828 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
3829 uint8_t digest[CC_MD5_DIGEST_LENGTH];
3831 // if output file file did not fit in memory, re-read file to generate md5 hash
3832 uint32_t kMD5BufferSize = 16*1024;
3833 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
3834 if ( md5Buffer != NULL ) {
3835 CC_MD5_CTX md5State;
3836 CC_MD5_Init(&md5State);
3837 ::lseek(fFileDescriptor, 0, SEEK_SET);
3839 while ( (len = ::read(fFileDescriptor, md5Buffer, kMD5BufferSize)) > 0 )
3840 CC_MD5_Update(&md5State, md5Buffer, len);
3841 CC_MD5_Final(digest, &md5State);
3845 // if malloc fails, fall back to random uuid
3846 ::uuid_generate_random(digest);
3848 fUUIDAtom->setContent(digest);
3849 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
3850 fUUIDAtom->copyRawContent(atomBuffer);
3851 ::pwrite(fFileDescriptor, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
3854 // if output file fit in memory, just genrate an md5 hash in memory
3855 CC_MD5(wholeBuffer, size, digest);
3856 fUUIDAtom->setContent(digest);
3857 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
3858 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
3864 delete [] atomBuffer;
3867 // write whole output file in one chunk
3868 ::pwrite(fFileDescriptor, wholeBuffer, size, 0);
3869 delete [] wholeBuffer;
3872 close(fFileDescriptor);
3878 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
3880 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
3881 uint8_t* dtraceProbeSite;
3882 const int64_t kTwoGigLimit = 0x7FFFFFFF;
3883 const int64_t kSixtyFourKiloLimit = 0x7FFF;
3884 int64_t displacement;
3885 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
3888 case x86::kFollowOn:
3891 case x86::kPointerWeakImport:
3894 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
3895 if ( fOptions.prebind() ) {
3896 switch (ref->getTarget().getDefinitionKind()) {
3897 case ObjectFile::Atom::kExternalDefinition:
3898 case ObjectFile::Atom::kExternalWeakDefinition:
3899 // prebound external relocation ==> pointer contains addend
3900 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3902 case ObjectFile::Atom::kTentativeDefinition:
3903 case ObjectFile::Atom::kRegularDefinition:
3904 case ObjectFile::Atom::kWeakDefinition:
3905 // prebound external relocation to internal atom ==> pointer contains target address + addend
3906 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3908 case ObjectFile::Atom::kAbsoluteSymbol:
3913 // external realocation ==> pointer contains addend
3914 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3918 // pointer contains target address
3919 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
3920 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3924 case x86::kPointerDiff:
3925 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
3926 LittleEndian::set32(*fixUp, (uint32_t)displacement);
3928 case x86::kPointerDiff16:
3929 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
3930 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
3931 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
3932 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
3934 case x86::kDtraceProbeSite:
3935 // change call site to a NOP
3936 dtraceProbeSite = (uint8_t*)fixUp;
3937 dtraceProbeSite[-1] = 0x90; // 1-byte nop
3938 dtraceProbeSite[0] = 0x0F; // 4-byte nop
3939 dtraceProbeSite[1] = 0x1F;
3940 dtraceProbeSite[2] = 0x40;
3941 dtraceProbeSite[3] = 0x00;
3943 case x86::kDtraceIsEnabledSite:
3944 // change call site to a clear eax
3945 dtraceProbeSite = (uint8_t*)fixUp;
3946 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
3947 dtraceProbeSite[0] = 0xC0;
3948 dtraceProbeSite[1] = 0x90; // 1-byte nop
3949 dtraceProbeSite[2] = 0x90; // 1-byte nop
3950 dtraceProbeSite[3] = 0x90; // 1-byte nop
3952 case x86::kPCRel32WeakImport:
3956 switch ( ref->getTarget().getDefinitionKind() ) {
3957 case ObjectFile::Atom::kRegularDefinition:
3958 case ObjectFile::Atom::kWeakDefinition:
3959 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
3961 case ObjectFile::Atom::kExternalDefinition:
3962 case ObjectFile::Atom::kExternalWeakDefinition:
3963 throw "codegen problem, can't use rel32 to external symbol";
3964 case ObjectFile::Atom::kTentativeDefinition:
3967 case ObjectFile::Atom::kAbsoluteSymbol:
3968 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
3971 if ( kind == x86::kPCRel16 ) {
3972 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
3973 //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());
3974 throwf("rel16 out of range in %s", inAtom->getDisplayName());
3976 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
3979 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
3980 //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());
3981 throwf("rel32 out of range in %s", inAtom->getDisplayName());
3983 LittleEndian::set32(*fixUp, (int32_t)displacement);
3986 case x86::kAbsolute32:
3987 switch ( ref->getTarget().getDefinitionKind() ) {
3988 case ObjectFile::Atom::kRegularDefinition:
3989 case ObjectFile::Atom::kWeakDefinition:
3990 case ObjectFile::Atom::kTentativeDefinition:
3991 // pointer contains target address
3992 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3994 case ObjectFile::Atom::kExternalDefinition:
3995 case ObjectFile::Atom::kExternalWeakDefinition:
3996 // external realocation ==> pointer contains addend
3997 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3999 case ObjectFile::Atom::kAbsoluteSymbol:
4000 // pointer contains target address
4001 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
4005 case x86::kDtraceTypeReference:
4006 case x86::kDtraceProbe:
4007 // nothing to fix up
4015 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4017 const int64_t kTwoGigLimit = 0x7FFFFFFF;
4018 const int64_t kSixtyFourKiloLimit = 0x7FFF;
4019 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4020 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
4021 int64_t displacement;
4022 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
4025 case x86::kFollowOn:
4029 case x86::kPointerWeakImport:
4030 case x86::kAbsolute32:
4033 // external realocation ==> pointer contains addend
4034 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4036 else if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4037 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
4038 if ( this->indirectSymbolIsLocal(ref) )
4039 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4041 LittleEndian::set32(*fixUp, 0);
4043 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
4044 // internal relocation => pointer contains target address
4045 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4048 // internal relocation to tentative ==> pointer contains addend
4049 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4053 case x86::kPointerDiff:
4054 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4055 LittleEndian::set32(*fixUp, (uint32_t)displacement);
4057 case x86::kPointerDiff16:
4058 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4059 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
4060 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
4061 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
4065 case x86::kPCRel32WeakImport:
4066 case x86::kDtraceProbeSite:
4067 case x86::kDtraceIsEnabledSite:
4070 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4072 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4073 if ( kind == x86::kPCRel16 ) {
4075 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
4076 //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());
4077 throwf("rel16 out of range in %s", inAtom->getDisplayName());
4079 int16_t word = (int16_t)displacement;
4080 LittleEndian::set16(*((uint16_t*)fixUp), word);
4083 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
4084 //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());
4085 throwf("rel32 out of range in %s", inAtom->getDisplayName());
4087 LittleEndian::set32(*fixUp, (int32_t)displacement);
4091 case x86::kDtraceProbe:
4092 case x86::kDtraceTypeReference:
4093 // nothing to fix up
4099 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4101 const int64_t twoGigLimit = 0x7FFFFFFF;
4102 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
4103 uint8_t* dtraceProbeSite;
4104 int64_t displacement = 0;
4105 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
4106 case x86_64::kNoFixUp:
4107 case x86_64::kFollowOn:
4110 case x86_64::kPointerWeakImport:
4111 case x86_64::kPointer:
4113 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
4114 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
4115 // external realocation ==> pointer contains addend
4116 LittleEndian::set64(*fixUp, ref->getTargetOffset());
4119 // internal relocation
4120 // pointer contains target address
4121 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
4122 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4126 case x86_64::kPointerDiff32:
4127 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4128 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
4129 throw "32-bit pointer difference out of range";
4130 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
4132 case x86_64::kPointerDiff:
4133 LittleEndian::set64(*fixUp,
4134 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4136 case x86_64::kPCRel32GOTLoad:
4137 case x86_64::kPCRel32GOTLoadWeakImport:
4138 // if GOT entry was optimized away, change movq instruction to a leaq
4139 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
4140 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
4141 uint8_t* opcodes = (uint8_t*)fixUp;
4142 if ( opcodes[-2] != 0x8B )
4143 throw "GOT load reloc does not point to a movq instruction";
4146 // fall into general rel32 case
4147 case x86_64::kBranchPCRel32WeakImport:
4148 case x86_64::kBranchPCRel32:
4149 case x86_64::kPCRel32:
4150 case x86_64::kPCRel32_1:
4151 case x86_64::kPCRel32_2:
4152 case x86_64::kPCRel32_4:
4153 case x86_64::kPCRel32GOT:
4154 case x86_64::kPCRel32GOTWeakImport:
4155 switch ( ref->getTarget().getDefinitionKind() ) {
4156 case ObjectFile::Atom::kRegularDefinition:
4157 case ObjectFile::Atom::kWeakDefinition:
4158 case ObjectFile::Atom::kTentativeDefinition:
4159 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4161 case ObjectFile::Atom::kAbsoluteSymbol:
4162 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4164 case ObjectFile::Atom::kExternalDefinition:
4165 case ObjectFile::Atom::kExternalWeakDefinition:
4166 throw "codegen problem, can't use rel32 to external symbol";
4169 switch ( ref->getKind() ) {
4170 case x86_64::kPCRel32_1:
4173 case x86_64::kPCRel32_2:
4176 case x86_64::kPCRel32_4:
4180 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
4181 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
4182 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
4183 throw "rel32 out of range";
4185 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
4187 case x86_64::kDtraceProbeSite:
4188 // change call site to a NOP
4189 dtraceProbeSite = (uint8_t*)fixUp;
4190 dtraceProbeSite[-1] = 0x90; // 1-byte nop
4191 dtraceProbeSite[0] = 0x0F; // 4-byte nop
4192 dtraceProbeSite[1] = 0x1F;
4193 dtraceProbeSite[2] = 0x40;
4194 dtraceProbeSite[3] = 0x00;
4196 case x86_64::kDtraceIsEnabledSite:
4197 // change call site to a clear eax
4198 dtraceProbeSite = (uint8_t*)fixUp;
4199 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
4200 dtraceProbeSite[0] = 0x33;
4201 dtraceProbeSite[1] = 0xC0;
4202 dtraceProbeSite[2] = 0x90; // 1-byte nop
4203 dtraceProbeSite[3] = 0x90; // 1-byte nop
4205 case x86_64::kDtraceTypeReference:
4206 case x86_64::kDtraceProbe:
4207 // nothing to fix up
4213 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4215 const int64_t twoGigLimit = 0x7FFFFFFF;
4216 bool external = this->makesExternalRelocatableReference(ref->getTarget());
4217 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
4218 int64_t displacement = 0;
4220 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
4221 case x86_64::kNoFixUp:
4222 case x86_64::kFollowOn:
4225 case x86_64::kPointer:
4226 case x86_64::kPointerWeakImport:
4229 // external realocation ==> pointer contains addend
4230 LittleEndian::set64(*fixUp, ref->getTargetOffset());
4233 // internal relocation ==> pointer contains target address
4234 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4238 case x86_64::kPointerDiff32:
4239 // addend in content
4240 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
4242 case x86_64::kPointerDiff:
4243 // addend in content
4244 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
4246 case x86_64::kBranchPCRel32:
4247 case x86_64::kBranchPCRel32WeakImport:
4248 case x86_64::kDtraceProbeSite:
4249 case x86_64::kDtraceIsEnabledSite:
4250 case x86_64::kPCRel32:
4251 case x86_64::kPCRel32_1:
4252 case x86_64::kPCRel32_2:
4253 case x86_64::kPCRel32_4:
4254 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
4255 temp32 = ref->getTargetOffset();
4257 // extern relocation contains addend
4258 displacement = temp32;
4261 // internal relocations contain delta to target address
4262 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4264 switch ( ref->getKind() ) {
4265 case x86_64::kPCRel32_1:
4268 case x86_64::kPCRel32_2:
4271 case x86_64::kPCRel32_4:
4275 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
4276 //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());
4277 throw "rel32 out of range";
4279 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
4281 case x86_64::kPCRel32GOT:
4282 case x86_64::kPCRel32GOTLoad:
4283 case x86_64::kPCRel32GOTWeakImport:
4284 case x86_64::kPCRel32GOTLoadWeakImport:
4285 // contains addend (usually zero)
4286 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
4288 case x86_64::kDtraceTypeReference:
4289 case x86_64::kDtraceProbe:
4290 // nothing to fix up
4296 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4298 fixUpReference_powerpc(ref, inAtom, buffer, true);
4302 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4304 fixUpReference_powerpc(ref, inAtom, buffer, true);
4308 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4310 fixUpReference_powerpc(ref, inAtom, buffer, false);
4314 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4316 fixUpReference_powerpc(ref, inAtom, buffer, false);
4320 // ppc and ppc64 are mostly the same, so they share a template specialzation
4322 template <typename A>
4323 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
4325 uint32_t instruction;
4326 uint32_t newInstruction;
4327 int64_t displacement;
4328 uint64_t targetAddr = 0;
4329 uint64_t picBaseAddr;
4330 uint16_t instructionLowHalf;
4331 uint16_t instructionHighHalf;
4332 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4333 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
4334 bool relocateableExternal = false;
4335 const int64_t picbase_twoGigLimit = 0x80000000;
4337 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4338 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4339 if ( finalLinkedImage )
4340 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
4342 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
4345 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
4350 case A::kPointerWeakImport:
4353 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
4354 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
4355 if ( fOptions.prebind() ) {
4356 switch (ref->getTarget().getDefinitionKind()) {
4357 case ObjectFile::Atom::kExternalDefinition:
4358 case ObjectFile::Atom::kExternalWeakDefinition:
4359 // prebound lazy pointer to another dylib ==> pointer contains zero
4360 P::setP(*fixUpPointer, 0);
4362 case ObjectFile::Atom::kTentativeDefinition:
4363 case ObjectFile::Atom::kRegularDefinition:
4364 case ObjectFile::Atom::kWeakDefinition:
4365 // prebound lazy pointer to withing this dylib ==> pointer contains address
4366 P::setP(*fixUpPointer, targetAddr);
4368 case ObjectFile::Atom::kAbsoluteSymbol:
4373 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
4374 if ( fDyldHelper == NULL )
4375 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
4376 P::setP(*fixUpPointer, fDyldHelper->getAddress());
4379 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4380 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
4381 if ( this->indirectSymbolIsLocal(ref) )
4382 P::setP(*fixUpPointer, targetAddr);
4384 P::setP(*fixUpPointer, 0);
4386 else if ( relocateableExternal ) {
4387 if ( fOptions.prebind() ) {
4388 switch (ref->getTarget().getDefinitionKind()) {
4389 case ObjectFile::Atom::kExternalDefinition:
4390 case ObjectFile::Atom::kExternalWeakDefinition:
4391 // prebound external relocation ==> pointer contains addend
4392 P::setP(*fixUpPointer, ref->getTargetOffset());
4394 case ObjectFile::Atom::kTentativeDefinition:
4395 case ObjectFile::Atom::kRegularDefinition:
4396 case ObjectFile::Atom::kWeakDefinition:
4397 // prebound external relocation to internal atom ==> pointer contains target address + addend
4398 P::setP(*fixUpPointer, targetAddr);
4400 case ObjectFile::Atom::kAbsoluteSymbol:
4405 // external realocation ==> pointer contains addend
4406 P::setP(*fixUpPointer, ref->getTargetOffset());
4410 // internal relocation
4411 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
4412 // pointer contains target address
4413 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
4414 P::setP(*fixUpPointer, targetAddr);
4417 // pointer contains addend
4418 P::setP(*fixUpPointer, ref->getTargetOffset());
4423 case A::kPointerDiff64:
4424 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4426 case A::kPointerDiff32:
4427 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4429 case A::kPointerDiff16:
4430 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4432 case A::kDtraceProbeSite:
4433 if ( finalLinkedImage ) {
4434 // change call site to a NOP
4435 BigEndian::set32(*fixUp, 0x60000000);
4438 // set bl instuction to branch to address zero in .o file
4439 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
4440 instruction = BigEndian::get32(*fixUp);
4441 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4442 BigEndian::set32(*fixUp, newInstruction);
4445 case A::kDtraceIsEnabledSite:
4446 if ( finalLinkedImage ) {
4447 // change call site to a li r3,0
4448 BigEndian::set32(*fixUp, 0x38600000);
4451 // set bl instuction to branch to address zero in .o file
4452 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
4453 instruction = BigEndian::get32(*fixUp);
4454 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4455 BigEndian::set32(*fixUp, newInstruction);
4458 case A::kBranch24WeakImport:
4461 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
4462 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4463 if ( relocateableExternal ) {
4464 // doing "ld -r" to an external symbol
4465 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4466 displacement -= ref->getTarget().getAddress();
4469 const int64_t bl_eightMegLimit = 0x00FFFFFF;
4470 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
4471 //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());
4472 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",
4473 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
4474 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
4477 instruction = BigEndian::get32(*fixUp);
4478 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4479 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
4480 BigEndian::set32(*fixUp, newInstruction);
4485 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
4486 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4487 if ( relocateableExternal ) {
4488 // doing "ld -r" to an external symbol
4489 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4490 displacement -= ref->getTarget().getAddress();
4493 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
4494 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
4495 //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());
4496 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
4497 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4498 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4501 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
4502 instruction = BigEndian::get32(*fixUp);
4503 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
4504 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
4505 BigEndian::set32(*fixUp, newInstruction);
4508 case A::kPICBaseLow16:
4509 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4510 displacement = targetAddr - picBaseAddr;
4511 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4512 throw "32-bit pic-base out of range";
4513 instructionLowHalf = (displacement & 0xFFFF);
4514 instruction = BigEndian::get32(*fixUp);
4515 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4516 BigEndian::set32(*fixUp, newInstruction);
4518 case A::kPICBaseLow14:
4519 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4520 displacement = targetAddr - picBaseAddr;
4521 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4522 throw "32-bit pic-base out of range";
4523 if ( (displacement & 0x3) != 0 )
4524 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
4525 instructionLowHalf = (displacement & 0xFFFC);
4526 instruction = BigEndian::get32(*fixUp);
4527 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
4528 BigEndian::set32(*fixUp, newInstruction);
4530 case A::kPICBaseHigh16:
4531 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4532 displacement = targetAddr - picBaseAddr;
4533 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4534 throw "32-bit pic-base out of range";
4535 instructionLowHalf = displacement >> 16;
4536 if ( (displacement & 0x00008000) != 0 )
4537 ++instructionLowHalf;
4538 instruction = BigEndian::get32(*fixUp);
4539 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4540 BigEndian::set32(*fixUp, newInstruction);
4543 if ( relocateableExternal && !finalLinkedImage )
4544 targetAddr -= ref->getTarget().getAddress();
4545 instructionLowHalf = (targetAddr & 0xFFFF);
4546 instruction = BigEndian::get32(*fixUp);
4547 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4548 BigEndian::set32(*fixUp, newInstruction);
4551 if ( relocateableExternal && !finalLinkedImage )
4552 targetAddr -= ref->getTarget().getAddress();
4553 if ( (targetAddr & 0x3) != 0 )
4554 throw "bad address for absolute lo14 instruction fix-up";
4555 instructionLowHalf = (targetAddr & 0xFFFF);
4556 instruction = BigEndian::get32(*fixUp);
4557 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
4558 BigEndian::set32(*fixUp, newInstruction);
4561 if ( relocateableExternal ) {
4562 if ( finalLinkedImage ) {
4563 switch (ref->getTarget().getDefinitionKind()) {
4564 case ObjectFile::Atom::kExternalDefinition:
4565 case ObjectFile::Atom::kExternalWeakDefinition:
4566 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
4568 case ObjectFile::Atom::kTentativeDefinition:
4569 case ObjectFile::Atom::kRegularDefinition:
4570 case ObjectFile::Atom::kWeakDefinition:
4571 // use target address
4573 case ObjectFile::Atom::kAbsoluteSymbol:
4574 targetAddr = ref->getTarget().getSectionOffset();
4579 targetAddr -= ref->getTarget().getAddress();
4582 instructionHighHalf = (targetAddr >> 16);
4583 instruction = BigEndian::get32(*fixUp);
4584 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
4585 BigEndian::set32(*fixUp, newInstruction);
4587 case A::kAbsHigh16AddLow:
4588 if ( relocateableExternal ) {
4589 if ( finalLinkedImage ) {
4590 switch (ref->getTarget().getDefinitionKind()) {
4591 case ObjectFile::Atom::kExternalDefinition:
4592 case ObjectFile::Atom::kExternalWeakDefinition:
4593 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
4595 case ObjectFile::Atom::kTentativeDefinition:
4596 case ObjectFile::Atom::kRegularDefinition:
4597 case ObjectFile::Atom::kWeakDefinition:
4598 // use target address
4600 case ObjectFile::Atom::kAbsoluteSymbol:
4601 targetAddr = ref->getTarget().getSectionOffset();
4606 targetAddr -= ref->getTarget().getAddress();
4609 if ( targetAddr & 0x00008000 )
4610 targetAddr += 0x00010000;
4611 instruction = BigEndian::get32(*fixUp);
4612 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
4613 BigEndian::set32(*fixUp, newInstruction);
4615 case A::kDtraceTypeReference:
4616 case A::kDtraceProbe:
4617 // nothing to fix up
4623 bool Writer<ppc>::stubableReference(const ObjectFile::Reference* ref)
4625 uint8_t kind = ref->getKind();
4626 switch ( (ppc::ReferenceKinds)kind ) {
4628 case ppc::kFollowOn:
4630 case ppc::kPointerWeakImport:
4631 case ppc::kPointerDiff16:
4632 case ppc::kPointerDiff32:
4633 case ppc::kPointerDiff64:
4634 case ppc::kDtraceProbe:
4635 case ppc::kDtraceProbeSite:
4636 case ppc::kDtraceIsEnabledSite:
4637 case ppc::kDtraceTypeReference:
4638 // these are never used to call external functions
4640 case ppc::kBranch24:
4641 case ppc::kBranch24WeakImport:
4642 case ppc::kBranch14:
4643 // these are used to call external functions
4645 case ppc::kPICBaseLow16:
4646 case ppc::kPICBaseLow14:
4647 case ppc::kPICBaseHigh16:
4648 case ppc::kAbsLow16:
4649 case ppc::kAbsLow14:
4650 case ppc::kAbsHigh16:
4651 case ppc::kAbsHigh16AddLow:
4652 // these are only used to call external functions
4653 // in -mlong-branch stubs
4654 switch ( ref->getTarget().getDefinitionKind() ) {
4655 case ObjectFile::Atom::kExternalDefinition:
4656 case ObjectFile::Atom::kExternalWeakDefinition:
4658 case ObjectFile::Atom::kTentativeDefinition:
4659 case ObjectFile::Atom::kRegularDefinition:
4660 case ObjectFile::Atom::kWeakDefinition:
4661 case ObjectFile::Atom::kAbsoluteSymbol:
4671 bool Writer<ppc64>::stubableReference(const ObjectFile::Reference* ref)
4673 uint8_t kind = ref->getKind();
4674 switch ( (ppc64::ReferenceKinds)kind ) {
4676 case ppc::kFollowOn:
4678 case ppc::kPointerWeakImport:
4679 case ppc::kPointerDiff16:
4680 case ppc::kPointerDiff32:
4681 case ppc::kPointerDiff64:
4682 case ppc::kPICBaseLow16:
4683 case ppc::kPICBaseLow14:
4684 case ppc::kPICBaseHigh16:
4685 case ppc::kAbsLow16:
4686 case ppc::kAbsLow14:
4687 case ppc::kAbsHigh16:
4688 case ppc::kAbsHigh16AddLow:
4689 case ppc::kDtraceProbe:
4690 case ppc::kDtraceProbeSite:
4691 case ppc::kDtraceIsEnabledSite:
4692 case ppc::kDtraceTypeReference:
4693 // these are never used to call external functions
4695 case ppc::kBranch24:
4696 case ppc::kBranch24WeakImport:
4697 case ppc::kBranch14:
4698 // these are used to call external functions
4705 bool Writer<x86>::stubableReference(const ObjectFile::Reference* ref)
4707 uint8_t kind = ref->getKind();
4708 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
4712 bool Writer<x86_64>::stubableReference(const ObjectFile::Reference* ref)
4714 uint8_t kind = ref->getKind();
4715 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
4720 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
4722 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
4726 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
4728 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
4732 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
4734 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
4738 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
4741 case x86_64::kPointerWeakImport:
4742 case x86_64::kBranchPCRel32WeakImport:
4743 case x86_64::kPCRel32GOTWeakImport:
4744 case x86_64::kPCRel32GOTLoadWeakImport:
4753 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
4759 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
4765 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
4771 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
4774 case x86_64::kPCRel32GOT:
4775 case x86_64::kPCRel32GOTWeakImport:
4776 case x86_64::kPCRel32GOTLoad:
4777 case x86_64::kPCRel32GOTLoadWeakImport:
4784 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
4790 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
4796 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
4802 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
4805 case x86_64::kPCRel32GOTLoad:
4806 case x86_64::kPCRel32GOTLoadWeakImport:
4814 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
4815 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
4816 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
4817 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
4820 template <typename A>
4821 void Writer<A>::optimizeDylibReferences()
4823 //fprintf(stderr, "original ordinals table:\n");
4824 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4825 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
4827 // find unused dylibs that can be removed
4828 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
4829 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
4830 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4831 ObjectFile::Reader* reader = it->first;
4832 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
4833 if ( aliasPos != fLibraryAliases.end() ) {
4834 // already noticed that this reader has same install name as another reader
4835 readerAliases[reader] = aliasPos->second;
4837 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || fOptions.deadStripDylibs()) ) {
4838 // this reader can be optimized away
4839 it->second = 0xFFFFFFFF;
4840 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
4841 if ( pos != fLibraryToLoadCommand.end() )
4842 pos->second->optimizeAway();
4845 // mark this reader as using it ordinal
4846 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
4847 if ( pos == ordinalToReader.end() )
4848 ordinalToReader[it->second] = reader;
4850 readerAliases[reader] = pos->second;
4853 // renumber ordinals (depends on iterator walking in ordinal order)
4854 uint32_t newOrdinal = 0;
4855 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
4856 if ( it->first <= fLibraryToOrdinal.size() )
4857 fLibraryToOrdinal[it->second] = ++newOrdinal;
4860 // add aliases (e.g. -lm points to libSystem.dylib)
4861 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
4862 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
4865 // fprintf(stderr, "new ordinals table:\n");
4866 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4867 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
4873 void Writer<x86_64>::scanForAbsoluteReferences()
4875 // x86_64 codegen never has absolute references
4879 void Writer<x86>::scanForAbsoluteReferences()
4881 // when linking -pie verify there are no absolute addressing
4882 if ( fOptions.positionIndependentExecutable() ) {
4883 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4884 ObjectFile::Atom* atom = *it;
4885 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4886 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4887 ObjectFile::Reference* ref = *rit;
4888 switch (ref->getKind()) {
4889 case x86::kAbsolute32:
4890 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4899 void Writer<ppc>::scanForAbsoluteReferences()
4901 // when linking -pie verify there are no absolute addressing
4902 if ( fOptions.positionIndependentExecutable() ) {
4903 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4904 ObjectFile::Atom* atom = *it;
4905 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4906 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4907 ObjectFile::Reference* ref = *rit;
4908 switch (ref->getKind()) {
4909 case ppc::kAbsLow16:
4910 case ppc::kAbsLow14:
4911 case ppc::kAbsHigh16:
4912 case ppc::kAbsHigh16AddLow:
4913 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4922 // for ppc64 look for any -mdynamic-no-pic codegen
4924 void Writer<ppc64>::scanForAbsoluteReferences()
4926 // only do this for main executable
4927 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
4928 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4929 ObjectFile::Atom* atom = *it;
4930 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4931 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4932 ObjectFile::Reference* ref = *rit;
4933 switch (ref->getKind()) {
4934 case ppc64::kAbsLow16:
4935 case ppc64::kAbsLow14:
4936 case ppc64::kAbsHigh16:
4937 case ppc64::kAbsHigh16AddLow:
4938 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4939 // shrink page-zero and add pad segment to compensate
4940 fPadSegmentInfo = new SegmentInfo();
4941 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
4942 fPageZeroAtom->setSize(0x1000);
4951 template <typename A>
4952 void Writer<A>::insertDummyStubs()
4954 // only needed for x86
4958 void Writer<x86>::insertDummyStubs()
4960 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
4961 std::vector<class StubAtom<x86>*> betterStubs;
4962 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
4963 switch (betterStubs.size() % 64 ) {
4964 case 12:// stub would occupy 0x3C->0x41
4965 case 25:// stub would occupy 0x7D->0x82
4966 case 38:// stub would occupy 0xBE->0xC3
4967 case 51:// stub would occupy 0xFF->0x04
4968 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL))); //pad with dummy stub
4971 betterStubs.push_back(*it);
4974 fAllSynthesizedStubs.clear();
4975 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
4978 template <typename A>
4979 void Writer<A>::synthesizeStubs()
4981 switch ( fOptions.outputKind() ) {
4982 case Options::kObjectFile:
4983 // these output kinds never have stubs
4985 case Options::kStaticExecutable:
4986 case Options::kDyld:
4987 case Options::kDynamicLibrary:
4988 case Options::kDynamicBundle:
4989 case Options::kDynamicExecutable:
4990 // try to synthesize stubs for these
4994 // walk every atom and reference
4995 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4996 ObjectFile::Atom* atom = *it;
4997 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4998 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4999 ObjectFile::Reference* ref = *rit;
5000 switch ( ref->getTargetBinding()) {
5001 case ObjectFile::Reference::kUnboundByName:
5002 case ObjectFile::Reference::kDontBind:
5004 case ObjectFile::Reference::kBoundByName:
5005 case ObjectFile::Reference::kBoundDirectly:
5006 ObjectFile::Atom& target = ref->getTarget();
5007 // build map of which symbols need weak importing
5008 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
5009 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
5010 bool weakImport = this->weakImportReferenceKind(ref->getKind());
5011 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
5012 if ( pos == fWeakImportMap.end() ) {
5013 // target not in fWeakImportMap, so add
5014 fWeakImportMap[&target] = weakImport;
5017 // target in fWeakImportMap, check for weakness mismatch
5018 if ( pos->second != weakImport ) {
5020 switch ( fOptions.weakReferenceMismatchTreatment() ) {
5021 case Options::kWeakReferenceMismatchError:
5022 throwf("mismatching weak references for symbol: %s", target.getName());
5023 case Options::kWeakReferenceMismatchWeak:
5026 case Options::kWeakReferenceMismatchNonWeak:
5027 pos->second = false;
5033 // create stubs as needed
5034 if ( this->stubableReference(ref)
5035 && (ref->getTargetOffset() == 0)
5036 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
5037 ObjectFile::Atom* stub = NULL;
5038 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
5039 if ( pos == fStubsMap.end() ) {
5040 stub = new StubAtom<A>(*this, target);
5041 fStubsMap[&target] = stub;
5046 // alter reference to use stub instead
5047 ref->setTarget(*stub, 0);
5049 // create GOT slots (non-lazy pointers) as needed
5050 else if ( this->GOTReferenceKind(ref->getKind()) ) {
5052 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
5054 if ( fBiggerThanTwoGigs ) {
5055 // in big images use GOT for all zero fill atoms
5056 // this is just a heuristic and may need to be re-examined
5057 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
5060 // < 2GB image so remove all GOT entries that we can
5061 useGOT = mustUseGOT;
5063 // if this GOT usage cannot be optimized away then make a GOT enry
5064 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
5067 ObjectFile::Atom* nlp = NULL;
5068 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
5069 if ( pos == fGOTMap.end() ) {
5070 nlp = new NonLazyPointerAtom<A>(*this, target);
5071 fGOTMap[&target] = nlp;
5076 // alter reference to use non lazy pointer instead
5077 ref->setTarget(*nlp, ref->getTargetOffset());
5085 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
5087 // add dummy stubs (x86 only)
5088 this->insertDummyStubs();
5090 // sort lazy pointers
5091 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
5093 // add stubs to fAllAtoms
5094 if ( fAllSynthesizedStubs.size() != 0 ) {
5095 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
5096 std::vector<ObjectFile::Atom*> mergedStubs;
5097 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
5098 // when we have stubs and helpers, insert both into fAllAtoms
5099 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
5100 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
5101 stubs = &mergedStubs;
5103 ObjectFile::Section* curSection = NULL;
5104 ObjectFile::Atom* prevAtom = NULL;
5105 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5106 ObjectFile::Atom* atom = *it;
5107 ObjectFile::Section* nextSection = atom->getSection();
5108 if ( nextSection != curSection ) {
5109 // HACK HACK for i386 where stubs are not in _TEXT segment
5110 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
5111 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
5112 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
5113 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
5114 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
5119 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
5120 // found end of __text section, insert stubs here
5121 fAllAtoms->insert(it, stubs->begin(), stubs->end());
5125 curSection = nextSection;
5132 // add lazy pointers to fAllAtoms
5133 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
5134 ObjectFile::Section* curSection = NULL;
5135 ObjectFile::Atom* prevAtom = NULL;
5136 bool inserted = false;
5137 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5138 ObjectFile::Atom* atom = *it;
5139 ObjectFile::Section* nextSection = atom->getSection();
5140 if ( nextSection != curSection ) {
5141 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
5142 // found end of __dyld section, insert lazy pointers here
5143 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
5147 curSection = nextSection;
5152 throw "can't insert lazy pointers, __dyld section not found";
5156 // add non-lazy pointers to fAllAtoms
5157 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
5158 ObjectFile::Section* curSection = NULL;
5159 ObjectFile::Atom* prevAtom = NULL;
5160 bool inserted = false;
5161 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5162 ObjectFile::Atom* atom = *it;
5163 ObjectFile::Section* nextSection = atom->getSection();
5164 if ( nextSection != curSection ) {
5165 if ( (prevAtom != NULL)
5166 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
5167 || ((strcmp(prevAtom->getSectionName(), "__data") == 0) &&
5168 ((fOptions.outputKind() == Options::kDyld) || (fOptions.outputKind() == Options::kStaticExecutable))) ) ) {
5169 // found end of __dyld section, insert lazy pointers here
5170 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
5174 curSection = nextSection;
5179 throw "can't insert non-lazy pointers, __dyld section not found";
5183 // build LC_SEGMENT_SPLIT_INFO content now that all atoms exist
5184 if ( fSplitCodeToDataContentAtom != NULL ) {
5185 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5186 ObjectFile::Atom* atom = *it;
5187 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5188 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
5189 ObjectFile::Reference* ref = *rit;
5190 switch ( ref->getTargetBinding()) {
5191 case ObjectFile::Reference::kUnboundByName:
5192 case ObjectFile::Reference::kDontBind:
5194 case ObjectFile::Reference::kBoundByName:
5195 case ObjectFile::Reference::kBoundDirectly:
5196 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
5197 this->addCrossSegmentRef(atom, ref);
5208 template <typename A>
5209 void Writer<A>::partitionIntoSections()
5211 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
5213 // for every atom, set its sectionInfo object and section offset
5214 // build up fSegmentInfos along the way
5215 ObjectFile::Section* curSection = NULL;
5216 SectionInfo* currentSectionInfo = NULL;
5217 SegmentInfo* currentSegmentInfo = NULL;
5218 SectionInfo* cstringSectionInfo = NULL;
5219 unsigned int sectionIndex = 1;
5220 fSegmentInfos.reserve(8);
5221 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
5222 ObjectFile::Atom* atom = (*fAllAtoms)[i];
5223 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
5224 if ( oneSegmentCommand ) {
5225 if ( currentSegmentInfo == NULL ) {
5226 currentSegmentInfo = new SegmentInfo();
5227 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5228 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5229 this->fSegmentInfos.push_back(currentSegmentInfo);
5231 currentSectionInfo = new SectionInfo();
5232 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
5233 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
5234 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
5235 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
5236 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
5237 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
5238 currentSectionInfo->setIndex(sectionIndex++);
5239 currentSegmentInfo->fSections.push_back(currentSectionInfo);
5240 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
5241 cstringSectionInfo = currentSectionInfo;
5244 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
5245 currentSegmentInfo = new SegmentInfo();
5246 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
5247 uint32_t initprot = 0;
5248 if ( atom->getSegment().isContentReadable() )
5249 initprot |= VM_PROT_READ;
5250 if ( atom->getSegment().isContentWritable() )
5251 initprot |= VM_PROT_WRITE;
5252 if ( atom->getSegment().isContentExecutable() )
5253 initprot |= VM_PROT_EXECUTE;
5254 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
5255 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
5256 currentSegmentInfo->fInitProtection = initprot;
5257 if ( initprot == 0 )
5258 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
5260 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5261 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
5262 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
5263 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
5264 currentSegmentInfo->fInitProtection = it->init;
5265 currentSegmentInfo->fMaxProtection = it->max;
5268 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
5269 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
5270 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
5271 currentSegmentInfo->fIndependentAddress = true;
5272 this->fSegmentInfos.push_back(currentSegmentInfo);
5274 currentSectionInfo = new SectionInfo();
5275 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
5276 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
5277 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
5278 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
5279 // check for -sectalign override
5280 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
5281 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
5282 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
5283 currentSectionInfo->fAlignment = it->alignment;
5285 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
5286 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
5287 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
5288 currentSectionInfo->setIndex(sectionIndex++);
5289 currentSegmentInfo->fSections.push_back(currentSectionInfo);
5291 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
5292 fLoadCommandsSection = currentSectionInfo;
5293 fLoadCommandsSegment = currentSegmentInfo;
5295 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
5296 currentSectionInfo->fAllLazyPointers = true;
5297 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
5298 currentSectionInfo->fAllLazyPointers = true;
5299 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
5300 currentSectionInfo->fAllNonLazyPointers = true;
5301 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
5302 currentSectionInfo->fAllNonLazyPointers = true;
5303 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
5304 currentSectionInfo->fAllNonLazyPointers = true;
5305 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
5306 currentSectionInfo->fAllStubs = true;
5307 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
5308 currentSectionInfo->fAllStubs = true;
5309 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
5310 currentSectionInfo->fAllStubs = true;
5311 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
5312 currentSectionInfo->fAllStubs = true;
5313 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
5314 currentSectionInfo->fAllSelfModifyingStubs = true;
5315 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
5317 curSection = atom->getSection();
5318 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers
5319 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllStubs ) {
5320 fSymbolTableCommands->needDynamicTable();
5323 // any non-zero fill atoms make whole section marked not-zero-fill
5324 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
5325 currentSectionInfo->fAllZeroFill = false;
5326 // change section object to be Writer's SectionInfo object
5327 atom->setSection(currentSectionInfo);
5328 // section alignment is that of a contained atom with the greatest alignment
5329 uint8_t atomAlign = atom->getAlignment().powerOf2;
5330 if ( currentSectionInfo->fAlignment < atomAlign )
5331 currentSectionInfo->fAlignment = atomAlign;
5332 // calculate section offset for this atom
5333 uint64_t offset = currentSectionInfo->fSize;
5334 uint64_t alignment = 1 << atomAlign;
5335 uint64_t currentModulus = (offset % alignment);
5336 uint64_t requiredModulus = atom->getAlignment().modulus;
5337 if ( currentModulus != requiredModulus ) {
5338 if ( requiredModulus > currentModulus )
5339 offset += requiredModulus-currentModulus;
5341 offset += requiredModulus+alignment-currentModulus;
5343 atom->setSectionOffset(offset);
5344 uint64_t curAtomSize = atom->getSize();
5345 currentSectionInfo->fSize = offset + curAtomSize;
5346 // add atom to section vector
5347 currentSectionInfo->fAtoms.push_back(atom);
5348 // update largest size
5349 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
5350 fLargestAtomSize = curAtomSize;
5352 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
5353 // when merging cstring sections in .o files, all strings need to use the max alignment
5354 uint64_t offset = 0;
5355 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
5356 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
5357 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
5358 ObjectFile::Atom* atom = *it;
5359 atom->setSectionOffset(offset);
5360 offset += atom->getSize();
5362 cstringSectionInfo->fSize = offset;
5367 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
5368 class TargetAndOffsetComparor
5371 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
5373 if ( left.atom != right.atom )
5374 return ( left.atom < right.atom );
5375 return ( left.offset < right.offset );
5380 bool Writer<ppc>::addBranchIslands()
5382 return this->addPPCBranchIslands();
5386 bool Writer<ppc64>::addBranchIslands()
5388 return this->addPPCBranchIslands();
5392 bool Writer<x86>::addBranchIslands()
5394 // x86 branches can reach entire 4G address space, so no need for branch islands
5399 bool Writer<x86_64>::addBranchIslands()
5401 // x86 branches can reach entire 4G size of largest image
5407 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
5410 case ppc::kBranch24:
5411 case ppc::kBranch24WeakImport:
5418 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
5421 case ppc64::kBranch24:
5422 case ppc64::kBranch24WeakImport:
5429 // PowerPC can do PC relative branches as far as +/-16MB.
5430 // If a branch target is >16MB then we insert one or more
5431 // "branch islands" between the branch and its target that
5432 // allows island hoping to the target.
5434 // Branch Island Algorithm
5436 // If the __TEXT segment < 16MB, then no branch islands needed
5437 // Otherwise, every 15MB into the __TEXT segment is region is
5438 // added which can contain branch islands. Every out of range
5439 // bl instruction is checked. If it crosses a region, an island
5440 // is added to that region with the same target and the bl is
5441 // adjusted to target the island instead.
5443 // In theory, if too many islands are added to one region, it
5444 // could grow the __TEXT enough that other previously in-range
5445 // bl branches could be pushed out of range. We reduce the
5446 // probability this could happen by placing the ranges every
5447 // 15MB which means the region would have to be 1MB (256K islands)
5448 // before any branches could be pushed out of range.
5450 template <typename A>
5451 bool Writer<A>::addPPCBranchIslands()
5454 bool result = false;
5455 // Can only possibly need branch islands if __TEXT segment > 16M
5456 if ( fLoadCommandsSegment->fSize > 16000000 ) {
5457 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
5458 const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section
5459 SectionInfo* textSection = NULL;
5460 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
5461 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
5463 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
5467 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
5468 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
5469 AtomToIsland regionsMap[kIslandRegionsCount];
5470 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
5471 unsigned int islandCount = 0;
5473 // create islands for branch references that are out of range
5474 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5475 ObjectFile::Atom* atom = *it;
5476 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5477 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
5478 ObjectFile::Reference* ref = *rit;
5479 if ( this->isBranch24Reference(ref->getKind()) ) {
5480 ObjectFile::Atom& target = ref->getTarget();
5481 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
5482 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
5483 int64_t displacement = dstAddr - srcAddr;
5484 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
5485 const int64_t kFifteenMegLimit = kBetweenRegions;
5486 if ( displacement > kFifteenMegLimit ) {
5487 // create forward branch chain
5488 ObjectFile::Atom* nextTarget = ⌖
5489 uint64_t nextTargetOffset = ref->getTargetOffset();
5490 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
5491 AtomToIsland* region = ®ionsMap[i];
5492 int64_t islandRegionAddr = kBetweenRegions * (i+1);
5493 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
5494 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
5495 if ( pos == region->end() ) {
5496 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
5497 island->setSection(textSection);
5498 (*region)[finalTargetAndOffset] = island;
5499 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
5500 regionsIslands[i].push_back(island);
5502 nextTarget = island;
5503 nextTargetOffset = 0;
5506 nextTarget = pos->second;
5507 nextTargetOffset = 0;
5511 if (log) fprintf(stderr, "using island %s for %s\n", nextTarget->getDisplayName(), atom->getDisplayName());
5512 ref->setTarget(*nextTarget, nextTargetOffset);
5514 else if ( displacement < (-kFifteenMegLimit) ) {
5515 // create back branching chain
5516 ObjectFile::Atom* prevTarget = ⌖
5517 uint64_t prevTargetOffset = ref->getTargetOffset();
5518 for (int i=0; i < kIslandRegionsCount ; ++i) {
5519 AtomToIsland* region = ®ionsMap[i];
5520 int64_t islandRegionAddr = kBetweenRegions * (i+1);
5521 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
5522 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
5523 if ( pos == region->end() ) {
5524 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
5525 island->setSection(textSection);
5526 (*region)[finalTargetAndOffset] = island;
5527 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
5528 regionsIslands[i].push_back(island);
5530 prevTarget = island;
5531 prevTargetOffset = 0;
5534 prevTarget = pos->second;
5535 prevTargetOffset = 0;
5539 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
5540 ref->setTarget(*prevTarget, prevTargetOffset);
5546 // insert islands into __text section and adjust section offsets
5547 if ( islandCount > 0 ) {
5548 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
5549 std::vector<ObjectFile::Atom*> newAtomList;
5550 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
5551 uint64_t islandRegionAddr = kBetweenRegions;
5552 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
5553 int regionIndex = 0;
5554 uint64_t atomSlide = 0;
5555 uint64_t sectionOffset = 0;
5556 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
5557 ObjectFile::Atom* atom = *it;
5558 newAtomList.push_back(atom);
5559 if ( atom->getAddress() > islandRegionAddr ) {
5560 uint64_t islandStartOffset = atom->getSectionOffset();
5561 sectionOffset = islandStartOffset + atomSlide;
5562 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
5563 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
5564 ObjectFile::Atom* islandAtom = *rit;
5565 newAtomList.push_back(islandAtom);
5566 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
5567 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5568 islandAtom->setSectionOffset(sectionOffset);
5569 sectionOffset += islandAtom->getSize();
5572 islandRegionAddr += kBetweenRegions;
5573 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
5574 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
5576 if ( atomSlide != 0 )
5577 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
5579 sectionOffset = textSection->fSize+atomSlide;
5580 // put any remaining islands at end of __text section
5581 if ( regionIndex < kIslandRegionsCount ) {
5582 std::vector<ObjectFile::Atom*>* regionIslands = ®ionsIslands[regionIndex];
5583 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
5584 ObjectFile::Atom* islandAtom = *rit;
5585 newAtomList.push_back(islandAtom);
5586 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
5587 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5588 islandAtom->setSectionOffset(sectionOffset);
5589 sectionOffset += islandAtom->getSize();
5593 textSection->fAtoms = newAtomList;
5594 textSection->fSize = sectionOffset;
5603 template <typename A>
5604 void Writer<A>::adjustLoadCommandsAndPadding()
5606 fSegmentCommands->computeSize();
5608 // recompute load command section offsets
5609 uint64_t offset = 0;
5610 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
5611 const unsigned int atomCount = loadCommandAtoms.size();
5612 for (unsigned int i=0; i < atomCount; ++i) {
5613 ObjectFile::Atom* atom = loadCommandAtoms[i];
5614 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
5615 offset = ( (offset+alignment-1) & (-alignment) );
5616 atom->setSectionOffset(offset);
5617 uint32_t atomSize = atom->getSize();
5618 if ( atomSize > fLargestAtomSize )
5619 fLargestAtomSize = atomSize;
5621 fLoadCommandsSection->fSize = offset;
5624 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
5625 const int sectionCount = sectionInfos.size();
5626 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
5627 for(int j=0; j < sectionCount; ++j) {
5628 SectionInfo* curSection = sectionInfos[j];
5629 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
5630 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
5633 uint64_t paddingSize = 0;
5634 if ( fOptions.outputKind() == Options::kDyld ) {
5635 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
5636 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
5638 else if ( fOptions.outputKind() == Options::kObjectFile ) {
5639 // mach-o .o files need no padding between load commands and first section
5643 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
5645 for(int j=sectionCount-1; j >=0; --j) {
5646 SectionInfo* curSection = sectionInfos[j];
5647 addr -= curSection->fSize;
5648 addr = addr & (0 - (1 << curSection->fAlignment));
5649 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
5650 addr -= totalSizeOfHeaderAndLoadCommands;
5651 paddingSize = addr % 4096;
5656 // if command line requires more padding than this
5657 uint32_t minPad = fOptions.minimumHeaderPad();
5658 if ( fOptions.maxMminimumHeaderPad() ) {
5659 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
5660 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
5661 if ( fOptions.outputKind() == Options::kDynamicLibrary )
5662 altMin += MAXPATHLEN;
5663 if ( altMin > minPad )
5666 if ( paddingSize < minPad ) {
5667 int extraPages = (minPad - paddingSize + 4095)/4096;
5668 paddingSize += extraPages * 4096;
5672 // adjust atom size and update section size
5673 fHeaderPadding->setSize(paddingSize);
5674 for(int j=0; j < sectionCount; ++j) {
5675 SectionInfo* curSection = sectionInfos[j];
5676 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
5677 curSection->fSize = paddingSize;
5681 // assign file offsets and logical address to all segments
5682 template <typename A>
5683 void Writer<A>::assignFileOffsets()
5685 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
5686 bool haveFixedSegments = false;
5687 uint64_t fileOffset = 0;
5688 uint64_t nextContiguousAddress = fOptions.baseAddress();
5689 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
5690 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
5692 // process segments with fixed addresses (-segaddr)
5693 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
5694 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5695 SegmentInfo* curSegment = *segit;
5696 if ( strcmp(curSegment->fName, it->name) == 0 ) {
5697 curSegment->fBaseAddress = it->address;
5698 curSegment->fFixedAddress = true;
5704 // Run through the segments and each segment's sections to assign addresses
5705 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5706 SegmentInfo* curSegment = *segit;
5708 if ( fOptions.splitSeg() ) {
5709 if ( curSegment->fInitProtection & VM_PROT_WRITE )
5710 nextContiguousAddress = nextWritableAddress;
5712 nextContiguousAddress = nextReadOnlyAddress;
5715 fileOffset = (fileOffset+4095) & (-4096);
5716 curSegment->fFileOffset = fileOffset;
5718 // Set the segment base address
5719 if ( curSegment->fFixedAddress )
5720 haveFixedSegments = true;
5722 curSegment->fBaseAddress = nextContiguousAddress;
5724 // We've set the segment address, now run through each section.
5725 uint64_t address = curSegment->fBaseAddress;
5726 SectionInfo* firstZeroFillSection = NULL;
5727 SectionInfo* prevSection = NULL;
5729 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5731 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
5732 SectionInfo* curSection = *it;
5734 // adjust section address based on alignment
5735 uint64_t alignment = 1 << curSection->fAlignment;
5736 address = ( (address+alignment-1) & (-alignment) );
5738 // adjust file offset to match address
5739 if ( prevSection != NULL ) {
5740 if ( finalLinkedImage || !prevSection->fVirtualSection )
5741 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
5743 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
5746 // update section info
5747 curSection->fFileOffset = fileOffset;
5748 curSection->setBaseAddress(address);
5750 // keep track of trailing zero fill sections
5751 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
5752 firstZeroFillSection = curSection;
5753 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
5754 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
5756 // update running pointers
5757 if ( finalLinkedImage || !curSection->fVirtualSection )
5758 address += curSection->fSize;
5759 fileOffset += curSection->fSize;
5761 // sanity check size of 32-bit binaries
5762 if ( address > maxAddress() )
5763 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
5765 // update segment info
5766 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
5767 curSegment->fSize = curSegment->fFileSize;
5768 prevSection = curSection;
5771 if ( fOptions.outputKind() == Options::kObjectFile ) {
5772 // don't page align .o files
5775 // optimize trailing zero-fill sections to not occupy disk space
5776 if ( firstZeroFillSection != NULL ) {
5777 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
5778 fileOffset = firstZeroFillSection->fFileOffset;
5780 // page align segment size
5781 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
5782 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
5783 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
5784 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
5785 if ( curSegment->fInitProtection & VM_PROT_WRITE )
5786 nextWritableAddress = nextContiguousAddress;
5788 nextReadOnlyAddress = nextContiguousAddress;
5793 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
5794 if ( haveFixedSegments ) {
5795 int segCount = fSegmentInfos.size();
5796 for(int i=0; i < segCount; ++i) {
5797 SegmentInfo* segment1 = fSegmentInfos[i];
5799 for(int j=0; j < segCount; ++j) {
5801 SegmentInfo* segment2 = fSegmentInfos[j];
5803 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
5804 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
5805 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5806 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5808 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
5809 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
5810 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5811 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5813 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
5814 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5815 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5822 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
5823 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5824 SegmentInfo* curSegment = *segit;
5825 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
5826 if ( fFirstWritableSegment == NULL )
5827 fFirstWritableSegment = curSegment;
5828 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
5829 fWritableSegmentPastFirst4GB = true;
5835 template <typename A>
5836 void Writer<A>::adjustLinkEditSections()
5838 // link edit content is always in last segment
5839 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
5840 unsigned int firstLinkEditSectionIndex = 0;
5841 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
5842 ++firstLinkEditSectionIndex;
5844 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
5845 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
5846 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
5847 if ( fPadSegmentInfo != NULL ) {
5848 // insert __4GBFILL segment into segments vector before LINKEDIT
5849 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
5850 if ( *it == lastSeg ) {
5851 fSegmentInfos.insert(it, fPadSegmentInfo);
5855 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
5856 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
5857 fPadSegmentInfo->fBaseAddress = address;
5858 // adjust LINKEDIT to start at zeroPageSize
5859 address = fOptions.zeroPageSize();
5860 lastSeg->fBaseAddress = fOptions.zeroPageSize();
5862 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
5863 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
5864 // adjust section address based on alignment
5865 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
5866 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
5868 fileOffset += pad; // adjust file offset to match address
5869 lastSeg->fSections[i]->setBaseAddress(address);
5870 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
5871 lastSeg->fSections[i]->setBaseAddress(0);
5872 lastSeg->fSections[i]->fFileOffset = fileOffset;
5873 uint64_t sectionOffset = 0;
5874 for (unsigned int j=0; j < atoms.size(); ++j) {
5875 ObjectFile::Atom* atom = atoms[j];
5876 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
5877 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5878 atom->setSectionOffset(sectionOffset);
5879 uint64_t size = atom->getSize();
5880 sectionOffset += size;
5881 if ( size > fLargestAtomSize )
5882 fLargestAtomSize = size;
5884 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
5885 lastSeg->fSections[i]->fSize = sectionOffset;
5886 fileOffset += sectionOffset;
5887 address += sectionOffset;
5889 if ( fOptions.outputKind() == Options::kObjectFile ) {
5890 //lastSeg->fBaseAddress = 0;
5891 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
5892 //lastSeg->fFileOffset = 0;
5893 //lastSeg->fFileSize =
5896 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
5897 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
5902 template <typename A>
5903 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
5905 switch ( fWriter.fOptions.outputKind() ) {
5906 case Options::kDynamicExecutable:
5907 case Options::kStaticExecutable:
5908 return ObjectFile::Atom::scopeGlobal;
5909 case Options::kDynamicLibrary:
5910 case Options::kDynamicBundle:
5911 case Options::kDyld:
5912 case Options::kObjectFile:
5913 return ObjectFile::Atom::scopeLinkageUnit;
5915 throw "unknown header type";
5918 template <typename A>
5919 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
5921 switch ( fWriter.fOptions.outputKind() ) {
5922 case Options::kDynamicExecutable:
5923 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
5924 case Options::kStaticExecutable:
5925 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
5926 case Options::kDynamicLibrary:
5927 case Options::kDynamicBundle:
5928 case Options::kDyld:
5929 return ObjectFile::Atom::kSymbolTableIn;
5930 case Options::kObjectFile:
5931 return ObjectFile::Atom::kSymbolTableNotIn;
5933 throw "unknown header type";
5936 template <typename A>
5937 const char* MachHeaderAtom<A>::getName() const
5939 switch ( fWriter.fOptions.outputKind() ) {
5940 case Options::kDynamicExecutable:
5941 case Options::kStaticExecutable:
5942 return "__mh_execute_header";
5943 case Options::kDynamicLibrary:
5944 return "__mh_dylib_header";
5945 case Options::kDynamicBundle:
5946 return "__mh_bundle_header";
5947 case Options::kObjectFile:
5949 case Options::kDyld:
5950 return "__mh_dylinker_header";
5952 throw "unknown header type";
5955 template <typename A>
5956 const char* MachHeaderAtom<A>::getDisplayName() const
5958 switch ( fWriter.fOptions.outputKind() ) {
5959 case Options::kDynamicExecutable:
5960 case Options::kStaticExecutable:
5961 case Options::kDynamicLibrary:
5962 case Options::kDynamicBundle:
5963 case Options::kDyld:
5964 return this->getName();
5965 case Options::kObjectFile:
5966 return "mach header";
5968 throw "unknown header type";
5971 template <typename A>
5972 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
5975 uint32_t fileType = 0;
5976 switch ( fWriter.fOptions.outputKind() ) {
5977 case Options::kDynamicExecutable:
5978 case Options::kStaticExecutable:
5979 fileType = MH_EXECUTE;
5981 case Options::kDynamicLibrary:
5982 fileType = MH_DYLIB;
5984 case Options::kDynamicBundle:
5985 fileType = MH_BUNDLE;
5987 case Options::kObjectFile:
5988 fileType = MH_OBJECT;
5990 case Options::kDyld:
5991 fileType = MH_DYLINKER;
5997 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
5998 if ( fWriter.fCanScatter )
5999 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
6002 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
6003 flags |= MH_NOUNDEFS;
6006 flags = MH_DYLDLINK;
6007 if ( fWriter.fOptions.bindAtLoad() )
6008 flags |= MH_BINDATLOAD;
6009 switch ( fWriter.fOptions.nameSpace() ) {
6010 case Options::kTwoLevelNameSpace:
6011 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
6013 case Options::kFlatNameSpace:
6015 case Options::kForceFlatNameSpace:
6016 flags |= MH_FORCE_FLAT;
6019 if ( fWriter.fHasWeakExports )
6020 flags |= MH_WEAK_DEFINES;
6021 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
6022 flags |= MH_BINDS_TO_WEAK;
6023 if ( fWriter.fOptions.prebind() )
6024 flags |= MH_PREBOUND;
6025 if ( fWriter.fOptions.splitSeg() )
6026 flags |= MH_SPLIT_SEGS;
6027 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
6028 flags |= MH_NO_REEXPORTED_DYLIBS;
6029 if ( fWriter.fOptions.positionIndependentExecutable() )
6032 if ( fWriter.fOptions.hasExecutableStack() )
6033 flags |= MH_ALLOW_STACK_EXECUTION;
6034 if ( fWriter.fOptions.readerOptions().fRootSafe )
6035 flags |= MH_ROOT_SAFE;
6036 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
6037 flags |= MH_SETUID_SAFE;
6040 // get commands info
6041 uint32_t commandsSize = 0;
6042 uint32_t commandsCount = 0;
6044 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
6045 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
6046 ObjectFile::Atom* atom = *it;
6047 commandsSize += atom->getSize();
6048 // segment and symbol table atoms can contain more than one load command
6049 if ( atom == fWriter.fSegmentCommands )
6050 commandsCount += fWriter.fSegmentCommands->commandCount();
6051 else if ( atom == fWriter.fSymbolTableCommands )
6052 commandsCount += fWriter.fSymbolTableCommands->commandCount();
6053 else if ( atom->getSize() != 0 )
6057 // fill out mach_header
6058 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
6060 mh->set_filetype(fileType);
6061 mh->set_ncmds(commandsCount);
6062 mh->set_sizeofcmds(commandsSize);
6063 mh->set_flags(flags);
6067 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
6069 header.set_magic(MH_MAGIC);
6070 header.set_cputype(CPU_TYPE_POWERPC);
6071 switch ( fWriter.fCpuConstraint ) {
6072 case ObjectFile::Reader::kCpuAny:
6073 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
6075 case ObjectFile::Reader::kCpuG3:
6076 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_750);
6078 case ObjectFile::Reader::kCpuG4:
6079 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_7400);
6081 case ObjectFile::Reader::kCpuG5:
6082 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_970);
6088 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
6090 header.set_magic(MH_MAGIC_64);
6091 header.set_cputype(CPU_TYPE_POWERPC64);
6092 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6093 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
6095 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
6096 header.set_reserved(0);
6100 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
6102 header.set_magic(MH_MAGIC);
6103 header.set_cputype(CPU_TYPE_I386);
6104 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
6108 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
6110 header.set_magic(MH_MAGIC_64);
6111 header.set_cputype(CPU_TYPE_X86_64);
6112 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6113 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
6115 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
6116 header.set_reserved(0);
6120 template <typename A>
6121 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
6122 : WriterAtom<A>(writer, Segment::fgStackSegment)
6124 if ( stackGrowsDown() )
6125 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
6127 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
6132 bool CustomStackAtom<ppc>::stackGrowsDown()
6138 bool CustomStackAtom<ppc64>::stackGrowsDown()
6144 bool CustomStackAtom<x86>::stackGrowsDown()
6150 bool CustomStackAtom<x86_64>::stackGrowsDown()
6156 template <typename A>
6157 void SegmentLoadCommandsAtom<A>::computeSize()
6160 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6161 const int segCount = segmentInfos.size();
6162 for(int i=0; i < segCount; ++i) {
6163 size += sizeof(macho_segment_command<P>);
6164 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
6165 const int sectionCount = sectionInfos.size();
6166 for(int j=0; j < sectionCount; ++j) {
6167 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
6168 size += sizeof(macho_section<P>);
6172 fCommandCount = segCount;
6173 if ( fWriter.fPadSegmentInfo != NULL ) {
6175 fSize += sizeof(macho_segment_command<P>);
6180 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
6182 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
6186 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
6188 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
6192 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
6194 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
6198 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
6200 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
6203 template <typename A>
6204 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6206 uint64_t size = this->getSize();
6207 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
6208 bzero(buffer, size);
6209 uint8_t* p = buffer;
6210 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6211 const int segCount = segmentInfos.size();
6212 for(int i=0; i < segCount; ++i) {
6213 SegmentInfo* segInfo = segmentInfos[i];
6214 const int sectionCount = segInfo->fSections.size();
6215 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
6216 cmd->set_cmd(macho_segment_command<P>::CMD);
6217 cmd->set_segname(segInfo->fName);
6218 cmd->set_vmaddr(segInfo->fBaseAddress);
6219 cmd->set_vmsize(segInfo->fSize);
6220 cmd->set_fileoff(segInfo->fFileOffset);
6221 cmd->set_filesize(segInfo->fFileSize);
6222 cmd->set_maxprot(segInfo->fMaxProtection);
6223 cmd->set_initprot(segInfo->fInitProtection);
6224 // add sections array
6225 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
6226 unsigned int sectionsEmitted = 0;
6227 for (int j=0; j < sectionCount; ++j) {
6228 SectionInfo* sectInfo = segInfo->fSections[j];
6229 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
6230 macho_section<P>* sect = §ions[sectionsEmitted++];
6232 // .o file segment does not cover load commands, so recalc at first real section
6233 if ( sectionsEmitted == 1 ) {
6234 cmd->set_vmaddr(sectInfo->getBaseAddress());
6235 cmd->set_fileoff(sectInfo->fFileOffset);
6237 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
6238 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
6240 sect->set_sectname(sectInfo->fSectionName);
6241 sect->set_segname(sectInfo->fSegmentName);
6242 sect->set_addr(sectInfo->getBaseAddress());
6243 sect->set_size(sectInfo->fSize);
6244 sect->set_offset(sectInfo->fFileOffset);
6245 sect->set_align(sectInfo->fAlignment);
6246 if ( sectInfo->fRelocCount != 0 ) {
6247 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
6248 sect->set_nreloc(sectInfo->fRelocCount);
6250 if ( sectInfo->fAllZeroFill ) {
6251 sect->set_flags(S_ZEROFILL);
6252 sect->set_offset(0);
6254 else if ( sectInfo->fAllLazyPointers ) {
6255 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
6256 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6258 else if ( sectInfo->fAllNonLazyPointers ) {
6259 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
6260 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6262 else if ( sectInfo->fAllStubs ) {
6263 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
6264 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6265 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
6267 else if ( sectInfo->fAllSelfModifyingStubs ) {
6268 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
6269 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6270 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
6272 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6273 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
6275 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6276 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
6278 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6279 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
6281 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6282 sect->set_flags(S_COALESCED);
6284 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6285 sect->set_flags(S_COALESCED);
6287 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6288 sect->set_flags(S_INTERPOSING);
6290 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6291 sect->set_flags(S_CSTRING_LITERALS);
6293 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6294 sect->set_flags(S_4BYTE_LITERALS);
6296 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6297 sect->set_flags(S_8BYTE_LITERALS);
6299 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6300 sect->set_flags(S_16BYTE_LITERALS);
6302 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
6303 sect->set_flags(S_LITERAL_POINTERS);
6305 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6306 sect->set_flags(S_DTRACE_DOF);
6308 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6309 sect->set_flags(S_DTRACE_DOF);
6311 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6312 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
6316 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
6317 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
6318 cmd->set_nsects(sectionsEmitted);
6323 template <typename A>
6324 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
6325 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
6327 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
6328 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
6329 switch ( fWriter.fOptions.outputKind() ) {
6330 case Options::kDynamicExecutable:
6331 case Options::kDynamicLibrary:
6332 case Options::kDynamicBundle:
6333 case Options::kDyld:
6334 fNeedsDynamicSymbolTable = true;
6336 case Options::kObjectFile:
6337 case Options::kStaticExecutable:
6338 fNeedsDynamicSymbolTable = false;
6341 writer.fSymbolTableCommands = this;
6346 template <typename A>
6347 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
6349 fNeedsDynamicSymbolTable = true;
6353 template <typename A>
6354 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
6356 if ( fNeedsDynamicSymbolTable )
6357 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
6359 return this->alignedSize(sizeof(macho_symtab_command<P>));
6362 template <typename A>
6363 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6365 // build LC_DYSYMTAB command
6366 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
6367 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
6368 symbolTableCmd->set_cmd(LC_SYMTAB);
6369 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
6370 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
6371 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
6372 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
6373 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
6375 // build LC_DYSYMTAB command
6376 if ( fNeedsDynamicSymbolTable ) {
6377 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
6378 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
6379 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
6380 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
6381 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
6382 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
6383 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
6384 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
6385 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
6386 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
6387 if ( fWriter.fModuleInfoAtom != NULL ) {
6388 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
6389 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
6390 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
6391 dynamicSymbolTableCmd->set_nmodtab(1);
6392 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
6393 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
6395 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
6396 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
6397 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
6398 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
6399 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
6400 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
6401 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
6407 template <typename A>
6408 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
6410 return fNeedsDynamicSymbolTable ? 2 : 1;
6413 template <typename A>
6414 uint64_t DyldLoadCommandsAtom<A>::getSize() const
6416 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
6419 template <typename A>
6420 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6422 uint64_t size = this->getSize();
6423 bzero(buffer, size);
6424 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
6425 if ( fWriter.fOptions.outputKind() == Options::kDyld )
6426 cmd->set_cmd(LC_ID_DYLINKER);
6428 cmd->set_cmd(LC_LOAD_DYLINKER);
6429 cmd->set_cmdsize(this->getSize());
6430 cmd->set_name_offset();
6431 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
6434 template <typename A>
6435 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
6437 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
6440 template <typename A>
6441 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6443 uint64_t size = this->getSize();
6445 bzero(buffer, size);
6446 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
6447 cmd->set_cmd(LC_SUB_CLIENT);
6448 cmd->set_cmdsize(size);
6449 cmd->set_client_offset();
6450 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
6454 template <typename A>
6455 uint64_t DylibLoadCommandsAtom<A>::getSize() const
6457 if ( fOptimizedAway ) {
6461 const char* path = fInfo.reader->getInstallPath();
6462 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
6466 template <typename A>
6467 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6469 if ( fOptimizedAway )
6471 uint64_t size = this->getSize();
6472 bzero(buffer, size);
6473 const char* path = fInfo.reader->getInstallPath();
6474 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
6475 if ( fInfo.options.fWeakImport )
6476 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
6477 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6478 cmd->set_cmd(LC_REEXPORT_DYLIB);
6480 cmd->set_cmd(LC_LOAD_DYLIB);
6481 cmd->set_cmdsize(this->getSize());
6482 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
6483 cmd->set_current_version(fInfo.reader->getCurrentVersion());
6484 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
6485 cmd->set_name_offset();
6486 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
6491 template <typename A>
6492 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
6494 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
6497 template <typename A>
6498 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6500 uint64_t size = this->getSize();
6501 bzero(buffer, size);
6502 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
6503 cmd->set_cmd(LC_ID_DYLIB);
6504 cmd->set_cmdsize(this->getSize());
6505 cmd->set_name_offset();
6506 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
6507 cmd->set_current_version(fWriter.fOptions.currentVersion());
6508 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
6509 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
6513 template <typename A>
6514 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6516 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6517 bzero(buffer, sizeof(macho_routines_command<P>));
6518 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
6519 cmd->set_cmd(macho_routines_command<P>::CMD);
6520 cmd->set_cmdsize(this->getSize());
6521 cmd->set_init_address(initAddr);
6525 template <typename A>
6526 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
6528 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
6531 template <typename A>
6532 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6534 uint64_t size = this->getSize();
6535 bzero(buffer, size);
6536 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
6537 cmd->set_cmd(LC_SUB_UMBRELLA);
6538 cmd->set_cmdsize(this->getSize());
6539 cmd->set_sub_umbrella_offset();
6540 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
6543 template <typename A>
6544 void UUIDLoadCommandAtom<A>::generate()
6546 switch ( fWriter.fOptions.getUUIDMode() ) {
6547 case Options::kUUIDNone:
6550 case Options::kUUIDRandom:
6551 ::uuid_generate_random(fUUID);
6554 case Options::kUUIDContent:
6561 template <typename A>
6562 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
6564 memcpy(fUUID, uuid, 16);
6567 template <typename A>
6568 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
6571 uint64_t size = this->getSize();
6572 bzero(buffer, size);
6573 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
6574 cmd->set_cmd(LC_UUID);
6575 cmd->set_cmdsize(this->getSize());
6576 cmd->set_uuid((uint8_t*)fUUID);
6581 template <typename A>
6582 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
6584 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
6587 template <typename A>
6588 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6590 uint64_t size = this->getSize();
6591 bzero(buffer, size);
6592 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
6593 cmd->set_cmd(LC_SUB_LIBRARY);
6594 cmd->set_cmdsize(this->getSize());
6595 cmd->set_sub_library_offset();
6596 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
6597 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
6600 template <typename A>
6601 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
6603 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
6606 template <typename A>
6607 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6609 uint64_t size = this->getSize();
6610 bzero(buffer, size);
6611 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
6612 cmd->set_cmd(LC_SUB_FRAMEWORK);
6613 cmd->set_cmdsize(this->getSize());
6614 cmd->set_umbrella_offset();
6615 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
6619 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
6621 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
6625 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
6627 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
6631 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
6633 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
6637 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
6639 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
6643 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
6645 uint64_t size = this->getSize();
6646 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6647 bzero(buffer, size);
6648 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
6649 cmd->set_cmd(LC_UNIXTHREAD);
6650 cmd->set_cmdsize(size);
6651 cmd->set_flavor(1); // PPC_THREAD_STATE
6652 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
6653 cmd->set_thread_register(0, start);
6654 if ( fWriter.fOptions.hasCustomStack() )
6655 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
6660 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
6662 uint64_t size = this->getSize();
6663 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6664 bzero(buffer, size);
6665 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
6666 cmd->set_cmd(LC_UNIXTHREAD);
6667 cmd->set_cmdsize(size);
6668 cmd->set_flavor(5); // PPC_THREAD_STATE64
6669 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
6670 cmd->set_thread_register(0, start);
6671 if ( fWriter.fOptions.hasCustomStack() )
6672 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
6676 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
6678 uint64_t size = this->getSize();
6679 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6680 bzero(buffer, size);
6681 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
6682 cmd->set_cmd(LC_UNIXTHREAD);
6683 cmd->set_cmdsize(size);
6684 cmd->set_flavor(1); // i386_THREAD_STATE
6685 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
6686 cmd->set_thread_register(10, start);
6687 if ( fWriter.fOptions.hasCustomStack() )
6688 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
6693 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
6695 uint64_t size = this->getSize();
6696 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6697 bzero(buffer, size);
6698 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
6699 cmd->set_cmd(LC_UNIXTHREAD);
6700 cmd->set_cmdsize(size);
6701 cmd->set_flavor(x86_THREAD_STATE64);
6702 cmd->set_count(x86_THREAD_STATE64_COUNT);
6703 cmd->set_thread_register(16, start); // rip
6704 if ( fWriter.fOptions.hasCustomStack() )
6705 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
6709 template <typename A>
6710 uint64_t RPathLoadCommandsAtom<A>::getSize() const
6712 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
6715 template <typename A>
6716 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6718 uint64_t size = this->getSize();
6719 bzero(buffer, size);
6720 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
6721 cmd->set_cmd(LC_RPATH);
6722 cmd->set_cmdsize(this->getSize());
6723 cmd->set_path_offset();
6724 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
6728 template <typename A>
6729 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
6731 bzero(buffer, fSize);
6734 template <typename A>
6735 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
6738 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
6739 if ( fWriter.fLargestAtomSize < newSize )
6740 fWriter.fLargestAtomSize = newSize;
6743 template <typename A>
6744 uint64_t LinkEditAtom<A>::getFileOffset() const
6746 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
6750 template <typename A>
6751 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
6753 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
6756 template <typename A>
6757 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6759 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
6763 template <typename A>
6764 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
6766 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
6769 template <typename A>
6770 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6772 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
6777 template <typename A>
6778 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
6780 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
6783 template <typename A>
6784 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6786 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
6789 template <typename A>
6790 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
6792 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
6795 template <typename A>
6796 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6798 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
6799 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
6804 template <typename A>
6805 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
6807 return fTable.size() * sizeof(uint32_t);
6810 template <typename A>
6811 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6813 uint64_t size = this->getSize();
6814 bzero(buffer, size);
6815 const uint32_t indirectTableSize = fTable.size();
6816 uint32_t* indirectTable = (uint32_t*)buffer;
6817 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
6818 if ( it->indirectIndex < indirectTableSize ) {
6819 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
6822 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
6829 template <typename A>
6830 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
6832 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
6833 + sizeof(macho_dylib_module<P>)
6834 + this->getReferencesCount()*sizeof(uint32_t);
6837 template <typename A>
6838 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
6840 return this->getFileOffset();
6843 template <typename A>
6844 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
6846 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
6849 template <typename A>
6850 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
6852 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
6855 template <typename A>
6856 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
6858 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
6861 template <typename A>
6862 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6864 uint64_t size = this->getSize();
6865 bzero(buffer, size);
6866 // create toc. The symbols are already sorted, they are all in the smae module
6867 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
6868 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
6869 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
6870 p->set_module_index(0);
6872 // create module table (one entry)
6873 uint16_t numInits = 0;
6874 uint16_t numTerms = 0;
6875 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6876 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
6877 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
6878 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
6879 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
6880 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
6881 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
6882 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
6883 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
6887 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
6888 module->set_module_name(fModuleNameOffset);
6889 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
6890 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
6891 module->set_irefsym(0);
6892 module->set_nrefsym(this->getReferencesCount());
6893 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
6894 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
6895 module->set_iextrel(0);
6896 module->set_nextrel(fWriter.fExternalRelocs.size());
6897 module->set_iinit_iterm(0,0);
6898 module->set_ninit_nterm(numInits,numTerms);
6899 module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years
6900 module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years
6901 // create reference table
6902 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
6903 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
6904 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
6905 ref->set_flags(REFERENCE_FLAG_DEFINED);
6907 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
6908 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
6909 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
6910 if ( pos != fWriter.fStubsMap.end() )
6911 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
6913 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
6919 template <typename A>
6920 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
6921 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
6923 fCurrentBuffer = new char[kBufferSize];
6924 // burn first byte of string pool (so zero is never a valid string offset)
6925 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
6926 // make offset 1 always point to an empty string
6927 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
6930 template <typename A>
6931 uint64_t StringsLinkEditAtom<A>::getSize() const
6934 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
6937 template <typename A>
6938 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6940 uint64_t offset = 0;
6941 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
6942 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
6943 offset += kBufferSize;
6945 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
6946 // zero fill end to align
6947 offset += fCurrentBufferUsed;
6948 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
6949 buffer[offset++] = 0;
6952 template <typename A>
6953 int32_t StringsLinkEditAtom<A>::add(const char* name)
6955 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
6956 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
6957 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
6958 fCurrentBufferUsed += lenNeeded;
6961 int copied = kBufferSize-fCurrentBufferUsed-1;
6962 // change trailing '\0' that strlcpy added to real char
6963 fCurrentBuffer[kBufferSize-1] = name[copied];
6964 // alloc next buffer
6965 fFullBuffers.push_back(fCurrentBuffer);
6966 fCurrentBuffer = new char[kBufferSize];
6967 fCurrentBufferUsed = 0;
6968 // append rest of string
6969 this->add(&name[copied+1]);
6975 template <typename A>
6976 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
6978 StringToOffset::iterator pos = fUniqueStrings.find(name);
6979 if ( pos != fUniqueStrings.end() ) {
6983 int32_t offset = this->add(name);
6984 fUniqueStrings[name] = offset;
6990 template <typename A>
6991 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
6993 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
6994 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
6995 // check for out of bounds
6996 if ( index > maxIndex )
6998 // check for index in fCurrentBuffer
6999 if ( index > currentBufferStartIndex )
7000 return &fCurrentBuffer[index-currentBufferStartIndex];
7001 // otherwise index is in a full buffer
7002 uint32_t fullBufferIndex = index/kBufferSize;
7003 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
7008 template <typename A>
7009 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
7010 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
7012 char* buf = new char[strlen(name)+32];
7013 if ( targetOffset == 0 ) {
7014 if ( islandRegion == 0 )
7015 sprintf(buf, "%s$island", name);
7017 sprintf(buf, "%s$island_%d", name, islandRegion);
7020 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
7027 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
7029 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
7030 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
7031 OSWriteBigInt32(buffer, 0, branchInstruction);
7035 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
7037 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
7038 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
7039 OSWriteBigInt32(buffer, 0, branchInstruction);
7043 uint64_t BranchIslandAtom<ppc>::getSize() const
7049 uint64_t BranchIslandAtom<ppc64>::getSize() const
7056 template <typename A>
7057 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
7059 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
7060 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
7062 return 0; // a zero size causes the load command to be suppressed
7065 template <typename A>
7066 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7068 uint64_t size = this->getSize();
7069 bzero(buffer, size);
7070 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
7071 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
7072 cmd->set_cmdsize(size);
7073 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
7074 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
7078 template <typename A>
7079 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
7081 return fEncodedData.size();
7084 template <typename A>
7085 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
7087 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
7091 template <typename A>
7092 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
7094 pint_t addr = fWriter.fOptions.baseAddress();
7095 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
7096 pint_t nextAddr = it->atom->getAddress() + it->offset;
7097 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
7098 uint64_t delta = nextAddr - addr;
7100 throw "double split seg info for same address";
7104 byte = delta & 0x7F;
7108 fEncodedData.push_back(byte);
7111 while( byte >= 0x80 );
7116 template <typename A>
7117 void SegmentSplitInfoContentAtom<A>::encode()
7119 if ( ! fCantEncode ) {
7120 fEncodedData.reserve(8192);
7122 if ( fKind1Locations.size() != 0 ) {
7123 fEncodedData.push_back(1);
7124 //fprintf(stderr, "type 1:\n");
7125 this->uleb128EncodeAddresses(fKind1Locations);
7126 fEncodedData.push_back(0);
7129 if ( fKind2Locations.size() != 0 ) {
7130 fEncodedData.push_back(2);
7131 //fprintf(stderr, "type 2:\n");
7132 this->uleb128EncodeAddresses(fKind2Locations);
7133 fEncodedData.push_back(0);
7136 if ( fKind3Locations.size() != 0 ) {
7137 fEncodedData.push_back(3);
7138 //fprintf(stderr, "type 3:\n");
7139 this->uleb128EncodeAddresses(fKind3Locations);
7140 fEncodedData.push_back(0);
7143 if ( fKind4Locations.size() != 0 ) {
7144 fEncodedData.push_back(4);
7145 //fprintf(stderr, "type 4:\n");
7146 this->uleb128EncodeAddresses(fKind4Locations);
7147 fEncodedData.push_back(0);
7150 // always add zero byte to mark end
7151 fEncodedData.push_back(0);
7153 // add zeros to end to align size
7154 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
7155 fEncodedData.push_back(0);
7160 template <typename A>
7161 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
7162 : WriterAtom<A>(writer, getInfoSegment())
7166 // struct objc_image_info {
7167 // uint32_t version; // initially 0
7170 // #define OBJC_IMAGE_SUPPORTS_GC 2
7171 // #define OBJC_IMAGE_GC_ONLY 4
7173 if ( objcReplacementClasses )
7175 switch ( objcConstraint ) {
7176 case ObjectFile::Reader::kObjcNone:
7177 case ObjectFile::Reader::kObjcRetainRelease:
7179 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
7182 case ObjectFile::Reader::kObjcGC:
7186 A::P::E::set32(fContent[1], value);
7189 template <typename A>
7190 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
7192 memcpy(buffer, &fContent[0], 8);
7196 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
7197 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
7198 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
7199 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
7200 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
7202 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
7203 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
7204 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
7205 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
7209 }; // namespace executable
7210 }; // namespace mach_o
7213 #endif // __EXECUTABLE_MACH_O__