]> git.saurik.com Git - apple/ld64.git/blob - src/MachOWriterExecutable.hpp
30aa24b3081cccd475f09cb1ce1ae931ad41aadd
[apple/ld64.git] / src / MachOWriterExecutable.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #ifndef __EXECUTABLE_MACH_O__
26 #define __EXECUTABLE_MACH_O__
27
28 #include <stdint.h>
29 #include <stddef.h>
30 #include <fcntl.h>
31 #include <sys/time.h>
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
41 #include <vector>
42 #include <algorithm>
43 #include <map>
44 #include <set>
45 #include <ext/hash_map>
46
47 #include "ObjectFile.h"
48 #include "ExecutableFile.h"
49 #include "Options.h"
50
51 #include "MachOFileAbstraction.hpp"
52
53
54 //
55 //
56 // To implement architecture xxx, you must write template specializations for the following methods:
57 // MachHeaderAtom<xxx>::setHeaderInfo()
58 // ThreadsLoadCommandsAtom<xxx>::getSize()
59 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
60 // Writer<xxx>::addObjectRelocs()
61 // Writer<xxx>::fixUpReferenceRelocatable()
62 // Writer<xxx>::fixUpReferenceFinal()
63 // Writer<xxx>::stubableReferenceKind()
64 // Writer<xxx>::weakImportReferenceKind()
65 // Writer<xxx>::GOTReferenceKind()
66 //
67
68
69 namespace mach_o {
70 namespace executable {
71
72 // forward references
73 template <typename A> class WriterAtom;
74 template <typename A> class PageZeroAtom;
75 template <typename A> class CustomStackAtom;
76 template <typename A> class MachHeaderAtom;
77 template <typename A> class SegmentLoadCommandsAtom;
78 template <typename A> class SymbolTableLoadCommandsAtom;
79 template <typename A> class ThreadsLoadCommandsAtom;
80 template <typename A> class DylibIDLoadCommandsAtom;
81 template <typename A> class RoutinesLoadCommandsAtom;
82 template <typename A> class DyldLoadCommandsAtom;
83 template <typename A> class UUIDLoadCommandAtom;
84 template <typename A> class LinkEditAtom;
85 template <typename A> class SectionRelocationsLinkEditAtom;
86 template <typename A> class LocalRelocationsLinkEditAtom;
87 template <typename A> class ExternalRelocationsLinkEditAtom;
88 template <typename A> class SymbolTableLinkEditAtom;
89 template <typename A> class IndirectTableLinkEditAtom;
90 template <typename A> class StringsLinkEditAtom;
91 template <typename A> class LoadCommandsPaddingAtom;
92 template <typename A> class StubAtom;
93 template <typename A> class StubHelperAtom;
94 template <typename A> class LazyPointerAtom;
95 template <typename A> class NonLazyPointerAtom;
96
97
98 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
99 class SectionInfo : public ObjectFile::Section {
100 public:
101 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0),
102 fAlignment(0), fAllLazyPointers(false), fAllNonLazyPointers(false), fAllStubs(false),
103 fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false)
104 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
105 void setIndex(unsigned int index) { fIndex=index; }
106 std::vector<ObjectFile::Atom*> fAtoms;
107 char fSegmentName[20];
108 char fSectionName[20];
109 uint64_t fFileOffset;
110 uint64_t fSize;
111 uint32_t fRelocCount;
112 uint32_t fRelocOffset;
113 uint32_t fIndirectSymbolOffset;
114 uint8_t fAlignment;
115 bool fAllLazyPointers;
116 bool fAllNonLazyPointers;
117 bool fAllStubs;
118 bool fAllSelfModifyingStubs;
119 bool fAllZeroFill;
120 bool fVirtualSection;
121 };
122
123 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
124 class SegmentInfo
125 {
126 public:
127 SegmentInfo() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
128 fBaseAddress(0), fSize(0), fFixedAddress(false) { fName[0] = '\0'; }
129 std::vector<class SectionInfo*> fSections;
130 char fName[20];
131 uint32_t fInitProtection;
132 uint32_t fMaxProtection;
133 uint64_t fFileOffset;
134 uint64_t fFileSize;
135 uint64_t fBaseAddress;
136 uint64_t fSize;
137 bool fFixedAddress;
138 };
139
140 template <typename A>
141 class Writer : public ExecutableFile::Writer
142 {
143 public:
144 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
145 virtual ~Writer();
146
147 virtual const char* getPath() { return fFilePath; }
148 virtual time_t getModificationTime() { return 0; }
149 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
150 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
151 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
152 virtual std::vector<Stab>* getStabs() { return NULL; }
153
154 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
155 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
156 std::vector<class ObjectFile::Reader::Stab>& stabs,
157 class ObjectFile::Atom* entryPointAtom,
158 class ObjectFile::Atom* dyldHelperAtom,
159 bool createUUID);
160
161 private:
162 typedef typename A::P P;
163 typedef typename A::P::uint_t pint_t;
164
165 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
166
167 void assignFileOffsets();
168 void synthesizeStubs();
169 void partitionIntoSections();
170 bool addBranchIslands();
171 bool addPPCBranchIslands();
172 uint8_t branch24Reference();
173 void adjustLoadCommandsAndPadding();
174 void createDynamicLinkerCommand();
175 void createDylibCommands();
176 void buildLinkEdit();
177 uint64_t writeAtoms();
178 void writeNoOps(uint32_t from, uint32_t to);
179 void collectExportedAndImportedAndLocalAtoms();
180 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
181 void buildSymbolTable();
182 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
183 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
184 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
185 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
186 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
187 bool shouldExport(const ObjectFile::Atom& atom) const;
188 void buildFixups();
189 void adjustLinkEditSections();
190 void buildObjectFileFixups();
191 void buildExecutableFixups();
192 bool referenceRequiresRuntimeFixUp(const ObjectFile::Reference* ref, bool slideable) const;
193 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
194 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
195 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
196 uint8_t buffer[], bool finalLinkedImage) const;
197 uint32_t symbolIndex(ObjectFile::Atom& atom);
198 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
199 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
200 uint8_t getRelocPointerSize();
201 bool stubableReferenceKind(uint8_t kind);
202 bool GOTReferenceKind(uint8_t kind);
203 bool weakImportReferenceKind(uint8_t kind);
204 unsigned int collectStabs();
205 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
206 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
207 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
208 void addStabs(uint32_t startIndex);
209 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
210 bool illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable);
211
212
213 struct DirectLibrary {
214 class ObjectFile::Reader* fLibrary;
215 bool fWeak;
216 bool fReExport;
217 };
218
219 friend class WriterAtom<A>;
220 friend class PageZeroAtom<A>;
221 friend class CustomStackAtom<A>;
222 friend class MachHeaderAtom<A>;
223 friend class SegmentLoadCommandsAtom<A>;
224 friend class SymbolTableLoadCommandsAtom<A>;
225 friend class ThreadsLoadCommandsAtom<A>;
226 friend class DylibIDLoadCommandsAtom<A>;
227 friend class RoutinesLoadCommandsAtom<A>;
228 friend class DyldLoadCommandsAtom<A>;
229 friend class UUIDLoadCommandAtom<A>;
230 friend class LinkEditAtom<A>;
231 friend class SectionRelocationsLinkEditAtom<A>;
232 friend class LocalRelocationsLinkEditAtom<A>;
233 friend class ExternalRelocationsLinkEditAtom<A>;
234 friend class SymbolTableLinkEditAtom<A>;
235 // friend class IndirectTableLinkEditAtom<A>;
236 friend class StringsLinkEditAtom<A>;
237 friend class LoadCommandsPaddingAtom<A>;
238 friend class StubAtom<A>;
239 friend class StubHelperAtom<A>;
240 friend class LazyPointerAtom<A>;
241 friend class NonLazyPointerAtom<A>;
242
243 const char* fFilePath;
244 Options& fOptions;
245 int fFileDescriptor;
246 std::vector<class ObjectFile::Atom*>* fAllAtoms;
247 std::vector<class ObjectFile::Reader::Stab>* fStabs;
248 class SectionInfo* fLoadCommandsSection;
249 class SegmentInfo* fLoadCommandsSegment;
250 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
251 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
252 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
253 class UUIDLoadCommandAtom<A>* fUUIDAtom;
254 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
255 std::vector<SegmentInfo*> fSegmentInfos;
256 class ObjectFile::Atom* fEntryPoint;
257 class ObjectFile::Atom* fDyldHelper;
258 std::vector<DirectLibrary> fDirectLibraries;
259 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
260 std::vector<class ObjectFile::Atom*> fExportedAtoms;
261 std::vector<class ObjectFile::Atom*> fImportedAtoms;
262 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
263 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
264 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
265 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
266 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
267 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
268 class StringsLinkEditAtom<A>* fStringsAtom;
269 macho_nlist<P>* fSymbolTable;
270 std::vector<macho_relocation_info<P> > fSectionRelocs;
271 std::vector<macho_relocation_info<P> > fInternalRelocs;
272 std::vector<macho_relocation_info<P> > fExternalRelocs;
273 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
274 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
275 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
276 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
277 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
278 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
279 uint32_t fSymbolTableCount;
280 uint32_t fSymbolTableStabsCount;
281 uint32_t fSymbolTableStabsStartIndex;
282 uint32_t fSymbolTableLocalCount;
283 uint32_t fSymbolTableLocalStartIndex;
284 uint32_t fSymbolTableExportCount;
285 uint32_t fSymbolTableExportStartIndex;
286 uint32_t fSymbolTableImportCount;
287 uint32_t fSymbolTableImportStartIndex;
288 uint32_t fLargestAtomSize;
289 bool fEmitVirtualSections;
290 bool fHasWeakExports;
291 bool fReferencesWeakImports;
292 bool fSeenFollowOnReferences;
293 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
294 };
295
296
297 class Segment : public ObjectFile::Segment
298 {
299 public:
300 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
301 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
302 virtual const char* getName() const { return fName; }
303 virtual bool isContentReadable() const { return fReadable; }
304 virtual bool isContentWritable() const { return fWritable; }
305 virtual bool isContentExecutable() const { return fExecutable; }
306 virtual bool hasFixedAddress() const { return fFixedAddress; }
307
308 static Segment fgTextSegment;
309 static Segment fgPageZeroSegment;
310 static Segment fgLinkEditSegment;
311 static Segment fgStackSegment;
312 static Segment fgImportSegment;
313 static Segment fgDataSegment;
314 private:
315 const char* fName;
316 const bool fReadable;
317 const bool fWritable;
318 const bool fExecutable;
319 const bool fFixedAddress;
320 };
321
322 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
323 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
324 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
325 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
326 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
327 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
328
329
330 template <typename A>
331 class WriterAtom : public ObjectFile::Atom
332 {
333 public:
334 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
335 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { setDontDeadStrip(); }
336
337 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
338 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
339 virtual const char* getName() const { return NULL; }
340 virtual const char* getDisplayName() const { return this->getName(); }
341 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
342 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
343 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
344 virtual bool isZeroFill() const { return false; }
345 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
346 virtual bool mustRemainInSection() const { return true; }
347 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
348 virtual bool requiresFollowOnAtom() const { return false; }
349 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
350 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
351 virtual uint8_t getAlignment() const { return 2; }
352 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
353 virtual void setScope(Scope) { }
354
355
356 protected:
357 virtual ~WriterAtom() {}
358 typedef typename A::P P;
359 typedef typename A::P::E E;
360
361 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
362
363 Writer<A>& fWriter;
364 Segment& fSegment;
365 };
366
367 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
368
369
370 template <typename A>
371 class PageZeroAtom : public WriterAtom<A>
372 {
373 public:
374 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment) {}
375 virtual const char* getDisplayName() const { return "page zero content"; }
376 virtual bool isZeroFill() const { return true; }
377 virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); }
378 virtual const char* getSectionName() const { return "._zeropage"; }
379 virtual uint8_t getAlignment() const { return 12; }
380 private:
381 using WriterAtom<A>::fWriter;
382 typedef typename A::P P;
383 };
384
385 template <typename A>
386 class DsoHandleAtom : public WriterAtom<A>
387 {
388 public:
389 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
390 virtual const char* getName() const { return "___dso_handle"; }
391 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
392 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
393 virtual uint64_t getSize() const { return 0; }
394 virtual uint8_t getAlignment() const { return 12; }
395 virtual const char* getSectionName() const { return "._mach_header"; }
396 virtual void copyRawContent(uint8_t buffer[]) const {}
397 };
398
399
400 template <typename A>
401 class MachHeaderAtom : public WriterAtom<A>
402 {
403 public:
404 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
405 virtual const char* getName() const;
406 virtual const char* getDisplayName() const;
407 virtual ObjectFile::Atom::Scope getScope() const;
408 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
409 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
410 virtual uint8_t getAlignment() const { return 12; }
411 virtual const char* getSectionName() const { return "._mach_header"; }
412 virtual void copyRawContent(uint8_t buffer[]) const;
413 private:
414 using WriterAtom<A>::fWriter;
415 typedef typename A::P P;
416 void setHeaderInfo(macho_header<typename A::P>& header) const;
417 };
418
419 template <typename A>
420 class CustomStackAtom : public WriterAtom<A>
421 {
422 public:
423 CustomStackAtom(Writer<A>& writer);
424 virtual const char* getDisplayName() const { return "custom stack content"; }
425 virtual bool isZeroFill() const { return true; }
426 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
427 virtual const char* getSectionName() const { return "._stack"; }
428 virtual uint8_t getAlignment() const { return 12; }
429 private:
430 using WriterAtom<A>::fWriter;
431 typedef typename A::P P;
432 static bool stackGrowsDown();
433 };
434
435 template <typename A>
436 class LoadCommandAtom : public WriterAtom<A>
437 {
438 protected:
439 LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment) {}
440 static uint64_t alignedSize(uint64_t size);
441 };
442
443
444 template <typename A>
445 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
446 {
447 public:
448 SegmentLoadCommandsAtom(Writer<A>& writer)
449 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0)
450 { writer.fSegmentCommands = this; }
451 virtual const char* getDisplayName() const { return "segment load commands"; }
452 virtual uint64_t getSize() const { return fSize; }
453 virtual uint8_t getAlignment() const { return 2; }
454 virtual const char* getSectionName() const { return "._load_commands"; }
455 virtual void copyRawContent(uint8_t buffer[]) const;
456
457 void computeSize();
458 void setup();
459 unsigned int commandCount() { return fCommandCount; }
460 void assignFileOffsets();
461 private:
462 using WriterAtom<A>::fWriter;
463 typedef typename A::P P;
464 unsigned int fCommandCount;
465 uint32_t fSize;
466 };
467
468 template <typename A>
469 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
470 {
471 public:
472 SymbolTableLoadCommandsAtom(Writer<A>&);
473 virtual const char* getDisplayName() const { return "symbol table load commands"; }
474 virtual uint64_t getSize() const;
475 virtual uint8_t getAlignment() const { return 2; }
476 virtual const char* getSectionName() const { return "._load_commands"; }
477 virtual void copyRawContent(uint8_t buffer[]) const;
478 unsigned int commandCount();
479
480 private:
481 using WriterAtom<A>::fWriter;
482 typedef typename A::P P;
483 macho_symtab_command<typename A::P> fSymbolTable;
484 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
485 };
486
487 template <typename A>
488 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
489 {
490 public:
491 ThreadsLoadCommandsAtom(Writer<A>& writer)
492 : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
493 virtual const char* getDisplayName() const { return "thread load commands"; }
494 virtual uint64_t getSize() const;
495 virtual uint8_t getAlignment() const { return 2; }
496 virtual const char* getSectionName() const { return "._load_commands"; }
497 virtual void copyRawContent(uint8_t buffer[]) const;
498 private:
499 using WriterAtom<A>::fWriter;
500 typedef typename A::P P;
501 uint8_t* fBuffer;
502 uint32_t fBufferSize;
503 };
504
505 template <typename A>
506 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
507 {
508 public:
509 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
510 virtual const char* getDisplayName() const { return "dyld load command"; }
511 virtual uint64_t getSize() const;
512 virtual uint8_t getAlignment() const { return 2; }
513 virtual const char* getSectionName() const { return "._load_commands"; }
514 virtual void copyRawContent(uint8_t buffer[]) const;
515 private:
516 using WriterAtom<A>::fWriter;
517 typedef typename A::P P;
518 };
519
520 template <typename A>
521 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
522 {
523 public:
524 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
525 LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
526 virtual const char* getDisplayName() const { return "allowable_client load command"; }
527 virtual uint64_t getSize() const;
528 virtual uint8_t getAlignment() const { return 2; }
529 virtual const char* getSectionName() const { return "._load_commands"; }
530 virtual void copyRawContent(uint8_t buffer[]) const;
531 private:
532 using WriterAtom<A>::fWriter;
533 typedef typename A::P P;
534 const char* clientString;
535 };
536
537 template <typename A>
538 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
539 {
540 public:
541 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
542 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info) {}
543 virtual const char* getDisplayName() const { return "dylib load command"; }
544 virtual uint64_t getSize() const;
545 virtual uint8_t getAlignment() const { return 2; }
546 virtual const char* getSectionName() const { return "._load_commands"; }
547 virtual void copyRawContent(uint8_t buffer[]) const;
548 private:
549 using WriterAtom<A>::fWriter;
550 typedef typename A::P P;
551 ExecutableFile::DyLibUsed& fInfo;
552 };
553
554 template <typename A>
555 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
556 {
557 public:
558 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
559 virtual const char* getDisplayName() const { return "dylib ID load command"; }
560 virtual uint64_t getSize() const;
561 virtual uint8_t getAlignment() const { return 2; }
562 virtual const char* getSectionName() const { return "._load_commands"; }
563 virtual void copyRawContent(uint8_t buffer[]) const;
564 private:
565 using WriterAtom<A>::fWriter;
566 typedef typename A::P P;
567 };
568
569 template <typename A>
570 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
571 {
572 public:
573 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
574 virtual const char* getDisplayName() const { return "routines load command"; }
575 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
576 virtual uint8_t getAlignment() const { return 2; }
577 virtual const char* getSectionName() const { return "._load_commands"; }
578 virtual void copyRawContent(uint8_t buffer[]) const;
579 private:
580 using WriterAtom<A>::fWriter;
581 typedef typename A::P P;
582 };
583
584 template <typename A>
585 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
586 {
587 public:
588 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
589 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
590 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
591 virtual uint64_t getSize() const;
592 virtual uint8_t getAlignment() const { return 2; }
593 virtual const char* getSectionName() const { return "._load_commands"; }
594 virtual void copyRawContent(uint8_t buffer[]) const;
595 private:
596 typedef typename A::P P;
597 const char* fName;
598 };
599
600 template <typename A>
601 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
602 {
603 public:
604 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
605 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
606 virtual const char* getDisplayName() const { return "sub-library load command"; }
607 virtual uint64_t getSize() const;
608 virtual uint8_t getAlignment() const { return 2; }
609 virtual const char* getSectionName() const { return "._load_commands"; }
610 virtual void copyRawContent(uint8_t buffer[]) const;
611 private:
612 using WriterAtom<A>::fWriter;
613 typedef typename A::P P;
614 const char* fNameStart;
615 int fNameLength;
616 };
617
618 template <typename A>
619 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
620 {
621 public:
622 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
623 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
624 virtual const char* getDisplayName() const { return "umbrella load command"; }
625 virtual uint64_t getSize() const;
626 virtual uint8_t getAlignment() const { return 2; }
627 virtual const char* getSectionName() const { return "._load_commands"; }
628 virtual void copyRawContent(uint8_t buffer[]) const;
629 private:
630 using WriterAtom<A>::fWriter;
631 typedef typename A::P P;
632 const char* fName;
633 };
634
635 template <typename A>
636 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
637 {
638 public:
639 UUIDLoadCommandAtom(Writer<A>& writer)
640 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) { ::uuid_generate_random(fUUID);}
641 virtual const char* getDisplayName() const { return "uuid load command"; }
642 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
643 virtual uint8_t getAlignment() const { return 2; }
644 virtual const char* getSectionName() const { return "._load_commands"; }
645 virtual void copyRawContent(uint8_t buffer[]) const;
646 virtual void emit() { fEmit = true; }
647 private:
648 using WriterAtom<A>::fWriter;
649 typedef typename A::P P;
650 uuid_t fUUID;
651 bool fEmit;
652 };
653
654 template <typename A>
655 class LoadCommandsPaddingAtom : public WriterAtom<A>
656 {
657 public:
658 LoadCommandsPaddingAtom(Writer<A>& writer)
659 : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
660 virtual const char* getDisplayName() const { return "header padding"; }
661 virtual uint64_t getSize() const { return fSize; }
662 virtual uint8_t getAlignment() const { return 2; }
663 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
664 virtual void copyRawContent(uint8_t buffer[]) const;
665
666 void setSize(uint64_t newSize);
667 private:
668 using WriterAtom<A>::fWriter;
669 typedef typename A::P P;
670 uint64_t fSize;
671 };
672
673 template <typename A>
674 class LinkEditAtom : public WriterAtom<A>
675 {
676 public:
677 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment) {}
678 uint64_t getFileOffset() const;
679 private:
680 typedef typename A::P P;
681 };
682
683 template <typename A>
684 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
685 {
686 public:
687 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
688 virtual const char* getDisplayName() const { return "section relocations"; }
689 virtual uint64_t getSize() const;
690 virtual uint8_t getAlignment() const { return 3; }
691 virtual const char* getSectionName() const { return "._section_relocs"; }
692 virtual void copyRawContent(uint8_t buffer[]) const;
693 private:
694 using WriterAtom<A>::fWriter;
695 typedef typename A::P P;
696 };
697
698 template <typename A>
699 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
700 {
701 public:
702 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
703 virtual const char* getDisplayName() const { return "local relocations"; }
704 virtual uint64_t getSize() const;
705 virtual uint8_t getAlignment() const { return 3; }
706 virtual const char* getSectionName() const { return "._local_relocs"; }
707 virtual void copyRawContent(uint8_t buffer[]) const;
708 private:
709 using WriterAtom<A>::fWriter;
710 typedef typename A::P P;
711 };
712
713 template <typename A>
714 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
715 {
716 public:
717 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
718 virtual const char* getDisplayName() const { return "symbol table"; }
719 virtual uint64_t getSize() const;
720 virtual uint8_t getAlignment() const { return 2; }
721 virtual const char* getSectionName() const { return "._symbol_table"; }
722 virtual void copyRawContent(uint8_t buffer[]) const;
723 private:
724 using WriterAtom<A>::fWriter;
725 typedef typename A::P P;
726 };
727
728 template <typename A>
729 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
730 {
731 public:
732 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
733 virtual const char* getDisplayName() const { return "external relocations"; }
734 virtual uint64_t getSize() const;
735 virtual uint8_t getAlignment() const { return 3; }
736 virtual const char* getSectionName() const { return "._extern_relocs"; }
737 virtual void copyRawContent(uint8_t buffer[]) const;
738 private:
739 using WriterAtom<A>::fWriter;
740 typedef typename A::P P;
741 };
742
743 struct IndirectEntry {
744 uint32_t indirectIndex;
745 uint32_t symbolIndex;
746 };
747
748 template <typename A>
749 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
750 {
751 public:
752 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
753 virtual const char* getDisplayName() const { return "indirect symbol table"; }
754 virtual uint64_t getSize() const;
755 virtual uint8_t getAlignment() const { return 2; }
756 virtual const char* getSectionName() const { return "._indirect_syms"; }
757 virtual void copyRawContent(uint8_t buffer[]) const;
758
759 std::vector<IndirectEntry> fTable;
760
761 private:
762 using WriterAtom<A>::fWriter;
763 typedef typename A::P P;
764 };
765
766 class CStringEquals
767 {
768 public:
769 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
770 };
771
772 template <typename A>
773 class StringsLinkEditAtom : public LinkEditAtom<A>
774 {
775 public:
776 StringsLinkEditAtom(Writer<A>& writer);
777 virtual const char* getDisplayName() const { return "string pool"; }
778 virtual uint64_t getSize() const;
779 virtual uint8_t getAlignment() const { return 2; }
780 virtual const char* getSectionName() const { return "._string_pool"; }
781 virtual void copyRawContent(uint8_t buffer[]) const;
782
783 int32_t add(const char* name);
784 int32_t addUnique(const char* name);
785 int32_t emptyString() { return 1; }
786
787 private:
788 using WriterAtom<A>::fWriter;
789 typedef typename A::P P;
790 enum { kBufferSize = 0x01000000 };
791 class CStringComparor {
792 public:
793 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
794 };
795 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
796
797 std::vector<char*> fFullBuffers;
798 char* fCurrentBuffer;
799 uint32_t fCurrentBufferUsed;
800 StringToOffset fUniqueStrings;
801 };
802
803
804
805 template <typename A>
806 class UndefinedSymbolProxyAtom : public WriterAtom<A>
807 {
808 public:
809 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
810 virtual const char* getName() const { return fName; }
811 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
812 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
813 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
814 virtual uint64_t getSize() const { return 0; }
815 virtual const char* getSectionName() const { return "._imports"; }
816 private:
817 using WriterAtom<A>::fWriter;
818 typedef typename A::P P;
819 const char* fName;
820 };
821
822 template <typename A>
823 class BranchIslandAtom : public WriterAtom<A>
824 {
825 public:
826 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
827 virtual const char* getName() const { return fName; }
828 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
829 virtual uint64_t getSize() const;
830 virtual const char* getSectionName() const { return "__text"; }
831 virtual void copyRawContent(uint8_t buffer[]) const;
832 private:
833 using WriterAtom<A>::fWriter;
834 const char* fName;
835 ObjectFile::Atom& fTarget;
836 uint32_t fTargetOffset;
837 };
838
839 template <typename A>
840 class StubAtom : public WriterAtom<A>
841 {
842 public:
843 StubAtom(Writer<A>& writer, ObjectFile::Atom& target);
844 virtual const char* getName() const { return fName; }
845 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
846 virtual uint8_t getAlignment() const { return 2; }
847 virtual uint64_t getSize() const;
848 virtual const char* getSectionName() const { return "__symbol_stub1"; }
849 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
850 virtual void copyRawContent(uint8_t buffer[]) const;
851 ObjectFile::Atom* getTarget() { return &fTarget; }
852 private:
853 static const char* stubName(const char* importName);
854 bool pic() const;
855 using WriterAtom<A>::fWriter;
856 const char* fName;
857 ObjectFile::Atom& fTarget;
858 std::vector<ObjectFile::Reference*> fReferences;
859 };
860
861
862 template <typename A>
863 class LazyPointerAtom : public WriterAtom<A>
864 {
865 public:
866 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
867 virtual const char* getName() const { return fName; }
868 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
869 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
870 virtual const char* getSectionName() const { return "__la_symbol_ptr"; }
871 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
872 virtual void copyRawContent(uint8_t buffer[]) const;
873 ObjectFile::Atom* getTarget() { return &fTarget; }
874 private:
875 using WriterAtom<A>::fWriter;
876 static const char* lazyPointerName(const char* importName);
877 const char* fName;
878 ObjectFile::Atom& fTarget;
879 std::vector<ObjectFile::Reference*> fReferences;
880 };
881
882
883 template <typename A>
884 class NonLazyPointerAtom : public WriterAtom<A>
885 {
886 public:
887 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
888 virtual const char* getName() const { return fName; }
889 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
890 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
891 virtual const char* getSectionName() const { return "__nl_symbol_ptr"; }
892 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
893 virtual void copyRawContent(uint8_t buffer[]) const;
894 ObjectFile::Atom* getTarget() { return &fTarget; }
895 private:
896 using WriterAtom<A>::fWriter;
897 static const char* nonlazyPointerName(const char* importName);
898 const char* fName;
899 ObjectFile::Atom& fTarget;
900 std::vector<ObjectFile::Reference*> fReferences;
901 };
902
903
904 template <typename A>
905 class WriterReference : public ObjectFile::Reference
906 {
907 public:
908 typedef typename A::ReferenceKinds Kinds;
909
910 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
911 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
912 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target),
913 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
914
915 virtual ~WriterReference() {}
916
917 virtual bool isTargetUnbound() const { return false; }
918 virtual bool isFromTargetUnbound() const { return false; }
919 virtual uint8_t getKind() const { return (uint8_t)fKind; }
920 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
921 virtual const char* getTargetName() const { return fTarget->getName(); }
922 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
923 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
924 virtual bool hasFromTarget() const { return (fFromTarget != NULL); }
925 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
926 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
927 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = &target; fTargetOffset = offset; }
928 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = &target; }
929 virtual void setFromTargetName(const char* name) { }
930 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
931 virtual const char* getDescription() const { return "writer refrence"; }
932 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
933
934 private:
935 Kinds fKind;
936 uint32_t fFixUpOffsetInSrc;
937 ObjectFile::Atom* fTarget;
938 uint32_t fTargetOffset;
939 ObjectFile::Atom* fFromTarget;
940 uint32_t fFromTargetOffset;
941 };
942
943
944
945 struct ExportSorter
946 {
947 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
948 {
949 return (strcmp(left->getName(), right->getName()) < 0);
950 }
951 };
952
953
954
955
956 template <typename A>
957 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
958 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
959 fLoadCommandsSegment(NULL), fLargestAtomSize(1),
960 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
961 fSeenFollowOnReferences(false)
962 {
963 int permissions = 0777;
964 if ( fOptions.outputKind() == Options::kObjectFile )
965 permissions = 0666;
966 // Calling unlink first assures the file is gone so that open creates it with correct permissions
967 // It also handles the case where fFilePath file is not writeable but its directory is
968 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
969 (void)unlink(fFilePath);
970 fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
971 if ( fFileDescriptor == -1 ) {
972 throw "can't open file for writing";
973 }
974
975 switch ( fOptions.outputKind() ) {
976 case Options::kDynamicExecutable:
977 case Options::kStaticExecutable:
978 fWriterSynthesizedAtoms.push_back(new PageZeroAtom<A>(*this));
979 if ( fOptions.outputKind() == Options::kDynamicExecutable )
980 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
981 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
982 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
983 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
984 if ( fOptions.outputKind() == Options::kDynamicExecutable )
985 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
986 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
987 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
988 if ( fOptions.hasCustomStack() )
989 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
990 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
991 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
992 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
993 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
994 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
995 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
996 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
997 break;
998 case Options::kDynamicLibrary:
999 case Options::kDynamicBundle:
1000 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1001 // fall through
1002 case Options::kObjectFile:
1003 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1004 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1005 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
1006 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
1007 if ( fOptions.initFunctionName() != NULL )
1008 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
1009 }
1010 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1011 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1012 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1013 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1014 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1015 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1016 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1017 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1018 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1019 break;
1020 case Options::kDyld:
1021 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1022 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1023 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1024 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1025 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1026 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1027 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1028 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1029 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1030 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1031 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1032 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1033 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1034 break;
1035 }
1036
1037 // add extra commmands
1038 uint8_t ordinal = 1;
1039 switch ( fOptions.outputKind() ) {
1040 case Options::kDynamicExecutable:
1041 case Options::kDynamicLibrary:
1042 case Options::kDynamicBundle:
1043 {
1044 // add dylib load command atoms for all dynamic libraries
1045 const unsigned int libCount = dynamicLibraries.size();
1046 for (unsigned int i=0; i < libCount; ++i) {
1047 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
1048 if ( dylibInfo.indirect ) {
1049 // find ordinal of direct reader
1050 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
1051 bool found = false;
1052 for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1053 if ( it->first == dylibInfo.directReader ) {
1054 //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
1055 fLibraryToOrdinal[dylibInfo.reader] = it->second;
1056 found = true;
1057 break;
1058 }
1059 }
1060 if ( ! found )
1061 fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
1062 }
1063 }
1064 else {
1065 // see if a DylibLoadCommandsAtom has already been created for this install path
1066 bool newDylib = true;
1067 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
1068 if ( dylibInfo.options.fInstallPathOverride != NULL )
1069 dylibInstallPath = dylibInfo.options.fInstallPathOverride;
1070 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
1071 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
1072 if ( !seenDylibInfo.indirect ) {
1073 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
1074 if ( seenDylibInfo.options.fInstallPathOverride != NULL )
1075 seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
1076 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
1077 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
1078 newDylib = false;
1079 break;
1080 }
1081 }
1082 }
1083
1084 if ( newDylib ) {
1085 // assign new ordinal and check for other paired load commands
1086 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
1087 fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom<A>(*this, dylibInfo));
1088 if ( dylibInfo.options.fReExport ) {
1089 // this dylib also needs a sub_x load command
1090 bool isFrameworkReExport = false;
1091 const char* lastSlash = strrchr(dylibInstallPath, '/');
1092 if ( lastSlash != NULL ) {
1093 char frameworkName[strlen(lastSlash)+20];
1094 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
1095 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
1096 }
1097 if ( isFrameworkReExport ) {
1098 // needs a LC_SUB_UMBRELLA command
1099 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
1100 }
1101 else {
1102 // needs a LC_SUB_LIBRARY command
1103 const char* nameStart = &lastSlash[1];
1104 if ( lastSlash == NULL )
1105 nameStart = dylibInstallPath;
1106 int len = strlen(nameStart);
1107 const char* dot = strchr(nameStart, '.');
1108 if ( dot != NULL )
1109 len = dot - nameStart;
1110 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
1111 }
1112 }
1113 }
1114 }
1115 }
1116 // add umbrella command if needed
1117 if ( fOptions.umbrellaName() != NULL ) {
1118 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
1119 }
1120 std::vector<const char*>& allowableClients = fOptions.allowableClients();
1121 if ( allowableClients.size() != 0 ) {
1122 for (std::vector<const char*>::iterator it=allowableClients.begin();
1123 it != allowableClients.end();
1124 it++)
1125 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
1126 }
1127 }
1128 break;
1129 case Options::kStaticExecutable:
1130 case Options::kObjectFile:
1131 case Options::kDyld:
1132 break;
1133 }
1134
1135 //fprintf(stderr, "ordinals table:\n");
1136 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1137 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
1138 //}
1139 }
1140
1141 template <typename A>
1142 Writer<A>::~Writer()
1143 {
1144 if ( fFilePath != NULL )
1145 free((void*)fFilePath);
1146 if ( fSymbolTable != NULL )
1147 delete [] fSymbolTable;
1148 }
1149
1150
1151 template <typename A>
1152 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
1153 {
1154 if ( (fOptions.outputKind() == Options::kObjectFile)
1155 || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
1156 return new UndefinedSymbolProxyAtom<A>(*this, name);
1157 else
1158 return NULL;
1159 }
1160
1161 template <typename A>
1162 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
1163 {
1164 // flat namespace images use zero for all ordinals
1165 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
1166 return 0;
1167
1168 // is an UndefinedSymbolProxyAtom
1169 if ( lib == this )
1170 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
1171 return DYNAMIC_LOOKUP_ORDINAL;
1172
1173 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
1174 if ( pos != fLibraryToOrdinal.end() )
1175 return pos->second;
1176
1177 throw "can't find ordinal for imported symbol";
1178 }
1179
1180
1181 template <typename A>
1182 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
1183 std::vector<class ObjectFile::Reader::Stab>& stabs,
1184 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
1185 bool createUUID)
1186 {
1187 fAllAtoms = &atoms;
1188 fStabs = &stabs;
1189 fEntryPoint = entryPointAtom;
1190 fDyldHelper = dyldHelperAtom;
1191
1192 // Set for create UUID
1193 if (createUUID)
1194 fUUIDAtom->emit();
1195
1196 // create inter-library stubs
1197 synthesizeStubs();
1198
1199 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
1200 partitionIntoSections();
1201
1202 // segment load command can now be sized and padding can be set
1203 adjustLoadCommandsAndPadding();
1204
1205 // assign each section a file offset
1206 assignFileOffsets();
1207
1208 // if need to add branch islands, reassign file offsets
1209 if ( addBranchIslands() )
1210 assignFileOffsets();
1211
1212 // build symbol table and relocations
1213 buildLinkEdit();
1214
1215 // write everything
1216 return writeAtoms();
1217 }
1218
1219 template <typename A>
1220 void Writer<A>::buildLinkEdit()
1221 {
1222 this->collectExportedAndImportedAndLocalAtoms();
1223 this->buildSymbolTable();
1224 this->buildFixups();
1225 this->adjustLinkEditSections();
1226 }
1227
1228
1229
1230 template <typename A>
1231 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
1232 {
1233 return atom->getAddress();
1234 // SectionInfo* info = (SectionInfo*)atom->getSection();
1235 // return info->getBaseAddress() + atom->getSectionOffset();
1236 }
1237
1238 template <typename A>
1239 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1240 {
1241 // set n_type
1242 entry->set_n_type(N_EXT | N_SECT);
1243 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
1244 if ( fOptions.keepPrivateExterns() )
1245 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
1246 }
1247
1248 // set n_sect (section number of implementation )
1249 uint8_t sectionIndex = atom->getSection()->getIndex();
1250 entry->set_n_sect(sectionIndex);
1251
1252 // the __mh_execute_header is magic and must be an absolute symbol
1253 if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0)
1254 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
1255 entry->set_n_type(N_EXT | N_ABS);
1256
1257 // set n_desc
1258 uint16_t desc = 0;
1259 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1260 desc |= REFERENCED_DYNAMICALLY;
1261 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
1262 desc |= N_WEAK_DEF;
1263 fHasWeakExports = true;
1264 }
1265 entry->set_n_desc(desc);
1266
1267 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1268 entry->set_n_value(this->getAtomLoadAddress(atom));
1269 }
1270
1271 template <typename A>
1272 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1273 {
1274 // set n_type
1275 entry->set_n_type(N_UNDF | N_EXT);
1276 if ( fOptions.keepPrivateExterns()
1277 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
1278 && (fOptions.outputKind() == Options::kObjectFile) )
1279 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
1280
1281 // set n_sect
1282 entry->set_n_sect(0);
1283
1284 uint16_t desc = 0;
1285 if ( fOptions.outputKind() != Options::kObjectFile ) {
1286 // set n_desc ( high byte is library ordinal, low byte is reference type )
1287 desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
1288 try {
1289 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
1290 SET_LIBRARY_ORDINAL(desc, ordinal);
1291 }
1292 catch (const char* msg) {
1293 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
1294 }
1295 }
1296 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
1297 desc |= REFERENCED_DYNAMICALLY;
1298 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
1299 desc |= N_REF_TO_WEAK;
1300 fReferencesWeakImports = true;
1301 }
1302 // set weak_import attribute
1303 if ( fWeakImportMap[atom] )
1304 desc |= N_WEAK_REF;
1305 entry->set_n_desc(desc);
1306
1307 // set n_value, zero for import proxy and size for tentative definition
1308 entry->set_n_value(atom->getSize());
1309 }
1310
1311 template <typename A>
1312 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
1313 {
1314 // set n_type
1315 uint8_t type = N_SECT;
1316 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
1317 type |= N_PEXT;
1318 entry->set_n_type(type);
1319
1320 // set n_sect (section number of implementation )
1321 uint8_t sectIndex = atom->getSection()->getIndex();
1322 if ( sectIndex == 0 ) {
1323 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
1324 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
1325 sectIndex = 1;
1326 }
1327 entry->set_n_sect(sectIndex);
1328
1329 // set n_desc
1330 uint16_t desc = 0;
1331 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
1332 desc |= N_WEAK_DEF;
1333 entry->set_n_desc(desc);
1334
1335 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
1336 entry->set_n_value(this->getAtomLoadAddress(atom));
1337 }
1338
1339
1340 template <typename A>
1341 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
1342 {
1343 macho_nlist<P>* entry = &fSymbolTable[startIndex];
1344 for (uint32_t i=0; i < count; ++i, ++entry) {
1345 ObjectFile::Atom* atom = atoms[i];
1346 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
1347 if ( &atoms == &fExportedAtoms ) {
1348 this->setExportNlist(atom, entry);
1349 }
1350 else if ( &atoms == &fImportedAtoms ) {
1351 this->setImportNlist(atom, entry);
1352 }
1353 else {
1354 this->setLocalNlist(atom, entry);
1355 }
1356 }
1357 }
1358
1359 template <typename A>
1360 void Writer<A>::buildSymbolTable()
1361 {
1362 fSymbolTableStabsStartIndex = 0;
1363 fSymbolTableStabsCount = fStabs->size();
1364 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
1365 fSymbolTableLocalCount = fLocalSymbolAtoms.size();
1366 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
1367 fSymbolTableExportCount = fExportedAtoms.size();
1368 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
1369 fSymbolTableImportCount = fImportedAtoms.size();
1370
1371 // allocate symbol table
1372 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
1373 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
1374
1375 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
1376 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount);
1377 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
1378 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
1379 addStabs(fSymbolTableStabsStartIndex);
1380 }
1381
1382
1383
1384 template <typename A>
1385 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
1386 {
1387 if ( atom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
1388 return false;
1389 switch ( atom.getScope() ) {
1390 case ObjectFile::Atom::scopeGlobal:
1391 return true;
1392 case ObjectFile::Atom::scopeLinkageUnit:
1393 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
1394 default:
1395 return false;
1396 }
1397 }
1398
1399 template <typename A>
1400 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
1401 {
1402 const int atomCount = fAllAtoms->size();
1403 // guess at sizes of each bucket to minimize re-allocations
1404 fImportedAtoms.reserve(100);
1405 fExportedAtoms.reserve(atomCount/2);
1406 fLocalSymbolAtoms.reserve(atomCount);
1407 for (int i=0; i < atomCount; ++i) {
1408 ObjectFile::Atom* atom = (*fAllAtoms)[i];
1409 // only named atoms go in symbol table
1410 if ( atom->getName() != NULL ) {
1411 // put atom into correct bucket: imports, exports, locals
1412 //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
1413 switch ( atom->getDefinitionKind() ) {
1414 case ObjectFile::Atom::kExternalDefinition:
1415 case ObjectFile::Atom::kExternalWeakDefinition:
1416 fImportedAtoms.push_back(atom);
1417 break;
1418 case ObjectFile::Atom::kTentativeDefinition:
1419 if ( fOptions.outputKind() == Options::kObjectFile ) {
1420 fImportedAtoms.push_back(atom);
1421 break;
1422 }
1423 // else fall into
1424 case ObjectFile::Atom::kRegularDefinition:
1425 case ObjectFile::Atom::kWeakDefinition:
1426 if ( this->shouldExport(*atom) )
1427 fExportedAtoms.push_back(atom);
1428 else if ( !fOptions.stripLocalSymbols()
1429 && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) )
1430 fLocalSymbolAtoms.push_back(atom);
1431 break;
1432 }
1433 }
1434 }
1435
1436 // sort exported atoms by name
1437 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
1438 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
1439 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), ExportSorter());
1440 }
1441
1442
1443 template <typename A>
1444 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
1445 {
1446 switch ( stab.type ) {
1447 case N_FUN:
1448 if ( stab.other == 0 ) {
1449 // end of function N_FUN has size
1450 return stab.atom->getSize();
1451 }
1452 else {
1453 // start of function N_FUN has address
1454 return getAtomLoadAddress(stab.atom);
1455 }
1456 case N_LBRAC:
1457 case N_RBRAC:
1458 case N_SLINE:
1459 if ( stab.atom == NULL )
1460 // some weird assembly files have slines not associated with a function
1461 return stab.value;
1462 else
1463 // all these stab types need their value changed from an offset in the atom to an address
1464 return getAtomLoadAddress(stab.atom) + stab.value;
1465 case N_STSYM:
1466 case N_LCSYM:
1467 case N_BNSYM:
1468 // all these need address of atom
1469 return getAtomLoadAddress(stab.atom);;
1470 case N_ENSYM:
1471 return stab.atom->getSize();
1472 case N_SO:
1473 return 0;
1474 default:
1475 return stab.value;
1476 }
1477 }
1478
1479 template <typename A>
1480 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
1481 {
1482 switch (stab.type) {
1483 case N_SO:
1484 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
1485 return this->fStringsAtom->emptyString();
1486 break;
1487 }
1488 // fall into uniquing case
1489 case N_SOL:
1490 case N_BINCL:
1491 case N_EXCL:
1492 return this->fStringsAtom->addUnique(stab.string);
1493 break;
1494 default:
1495 if ( stab.string == NULL )
1496 return 0;
1497 else if ( stab.string[0] == '\0' )
1498 return this->fStringsAtom->emptyString();
1499 else
1500 return this->fStringsAtom->add(stab.string);
1501 }
1502 return 0;
1503 }
1504
1505 template <typename A>
1506 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
1507 {
1508 if ( stab.atom != NULL )
1509 return stab.atom->getSection()->getIndex();
1510 else
1511 return stab.other;
1512 }
1513
1514 template <typename A>
1515 void Writer<A>::addStabs(uint32_t startIndex)
1516 {
1517 macho_nlist<P>* entry = &fSymbolTable[startIndex];
1518 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
1519 const ObjectFile::Reader::Stab& stab = *it;
1520 entry->set_n_type(stab.type);
1521 entry->set_n_sect(sectionIndexForStab(stab));
1522 entry->set_n_desc(stab.desc);
1523 entry->set_n_value(valueForStab(stab));
1524 entry->set_n_strx(stringOffsetForStab(stab));
1525 }
1526 }
1527
1528
1529
1530 template <typename A>
1531 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
1532 {
1533 // search imports
1534 int i = 0;
1535 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
1536 if ( &atom == *it )
1537 return i + fSymbolTableImportStartIndex;
1538 ++i;
1539 }
1540
1541 // search locals
1542 i = 0;
1543 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
1544 if ( &atom == *it )
1545 return i + fSymbolTableLocalStartIndex;
1546 ++i;
1547 }
1548
1549 // search exports
1550 i = 0;
1551 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
1552 if ( &atom == *it )
1553 return i + fSymbolTableExportStartIndex;
1554 ++i;
1555 }
1556
1557 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
1558 }
1559
1560
1561 template <typename A>
1562 void Writer<A>::buildFixups()
1563 {
1564 if ( fOptions.outputKind() == Options::kObjectFile ) {
1565 this->buildObjectFileFixups();
1566 }
1567 else {
1568 if ( fOptions.keepRelocations() )
1569 this->buildObjectFileFixups();
1570 this->buildExecutableFixups();
1571 }
1572 }
1573
1574
1575 template <>
1576 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1577 {
1578 ObjectFile::Atom& target = ref->getTarget();
1579 bool isExtern = false;
1580 switch ( target.getDefinitionKind() ) {
1581 case ObjectFile::Atom::kRegularDefinition:
1582 isExtern = false;
1583 break;
1584 case ObjectFile::Atom::kWeakDefinition:
1585 case ObjectFile::Atom::kTentativeDefinition:
1586 case ObjectFile::Atom::kExternalDefinition:
1587 case ObjectFile::Atom::kExternalWeakDefinition:
1588 isExtern = shouldExport(target);
1589 break;
1590 }
1591 uint32_t symbolIndex = 0;
1592 if ( isExtern )
1593 symbolIndex = this->symbolIndex(target);
1594 uint32_t sectionNum = target.getSection()->getIndex();
1595 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1596 macho_relocation_info<P> reloc1;
1597 macho_relocation_info<P> reloc2;
1598 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1599 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1600 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
1601
1602 switch ( kind ) {
1603 case x86::kNoFixUp:
1604 case x86::kFollowOn:
1605 return 0;
1606
1607 case x86::kPointer:
1608 case x86::kPointerWeakImport:
1609 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1610 // use scattered reloc is target offset is non-zero
1611 sreloc1->set_r_scattered(true);
1612 sreloc1->set_r_pcrel(false);
1613 sreloc1->set_r_length(2);
1614 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1615 sreloc1->set_r_address(address);
1616 sreloc1->set_r_value(target.getAddress());
1617 }
1618 else {
1619 reloc1.set_r_address(address);
1620 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1621 reloc1.set_r_pcrel(false);
1622 reloc1.set_r_length(2);
1623 reloc1.set_r_extern(isExtern);
1624 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1625 }
1626 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1627 return 1;
1628
1629 case x86::kPointerDiff:
1630 {
1631 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1632 sreloc1->set_r_scattered(true);
1633 sreloc1->set_r_pcrel(false);
1634 sreloc1->set_r_length(2);
1635 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
1636 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
1637 else
1638 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
1639 sreloc1->set_r_address(address);
1640 sreloc1->set_r_value(target.getAddress());
1641 sreloc2->set_r_scattered(true);
1642 sreloc2->set_r_pcrel(false);
1643 sreloc2->set_r_length(2);
1644 sreloc2->set_r_type(PPC_RELOC_PAIR);
1645 sreloc2->set_r_address(0);
1646 sreloc2->set_r_value(fromAddr);
1647 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1648 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1649 return 2;
1650 }
1651
1652 case x86::kPCRel32WeakImport:
1653 case x86::kPCRel32:
1654 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1655 // use scattered reloc is target offset is non-zero
1656 sreloc1->set_r_scattered(true);
1657 sreloc1->set_r_pcrel(true);
1658 sreloc1->set_r_length(2);
1659 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1660 sreloc1->set_r_address(address);
1661 sreloc1->set_r_value(target.getAddress());
1662 }
1663 else {
1664 reloc1.set_r_address(address);
1665 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1666 reloc1.set_r_pcrel(true);
1667 reloc1.set_r_length(2);
1668 reloc1.set_r_extern(isExtern);
1669 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1670 }
1671 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1672 return 1;
1673
1674 }
1675 return 0;
1676 }
1677
1678
1679
1680 template <>
1681 uint8_t Writer<ppc>::getRelocPointerSize()
1682 {
1683 return 2;
1684 }
1685
1686 template <>
1687 uint8_t Writer<ppc64>::getRelocPointerSize()
1688 {
1689 return 3;
1690 }
1691
1692 template <>
1693 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1694 {
1695 return addObjectRelocs_powerpc(atom, ref);
1696 }
1697
1698 template <>
1699 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1700 {
1701 return addObjectRelocs_powerpc(atom, ref);
1702 }
1703
1704 //
1705 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
1706 // they use a common addObjectRelocs_powerpc() method.
1707 //
1708 template <typename A>
1709 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1710 {
1711 ObjectFile::Atom& target = ref->getTarget();
1712 bool isExtern = false;
1713 switch ( target.getDefinitionKind() ) {
1714 case ObjectFile::Atom::kRegularDefinition:
1715 isExtern = false;
1716 break;
1717 case ObjectFile::Atom::kWeakDefinition:
1718 case ObjectFile::Atom::kTentativeDefinition:
1719 case ObjectFile::Atom::kExternalDefinition:
1720 case ObjectFile::Atom::kExternalWeakDefinition:
1721 isExtern = shouldExport(target);
1722 break;
1723 }
1724
1725 uint32_t symbolIndex = 0;
1726 if ( isExtern )
1727 symbolIndex = this->symbolIndex(target);
1728 uint32_t sectionNum = target.getSection()->getIndex();
1729 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1730 macho_relocation_info<P> reloc1;
1731 macho_relocation_info<P> reloc2;
1732 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1733 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1734 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
1735
1736 switch ( kind ) {
1737 case A::kNoFixUp:
1738 case A::kFollowOn:
1739 return 0;
1740
1741 case A::kPointer:
1742 case A::kPointerWeakImport:
1743 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
1744 // use scattered reloc is target offset is outside target
1745 sreloc1->set_r_scattered(true);
1746 sreloc1->set_r_pcrel(false);
1747 sreloc1->set_r_length(getRelocPointerSize());
1748 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1749 sreloc1->set_r_address(address);
1750 sreloc1->set_r_value(target.getAddress());
1751 }
1752 else {
1753 reloc1.set_r_address(address);
1754 if ( isExtern )
1755 reloc1.set_r_symbolnum(symbolIndex);
1756 else
1757 reloc1.set_r_symbolnum(sectionNum);
1758 reloc1.set_r_pcrel(false);
1759 reloc1.set_r_length(getRelocPointerSize());
1760 reloc1.set_r_extern(isExtern);
1761 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1762 }
1763 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1764 return 1;
1765
1766 case A::kPointerDiff32:
1767 case A::kPointerDiff64:
1768 {
1769 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1770 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1771 sreloc1->set_r_scattered(true);
1772 sreloc1->set_r_pcrel(false);
1773 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1774 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
1775 sreloc1->set_r_address(address);
1776 sreloc1->set_r_value(toAddr);
1777 sreloc2->set_r_scattered(true);
1778 sreloc2->set_r_pcrel(false);
1779 sreloc2->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1780 sreloc2->set_r_type(PPC_RELOC_PAIR);
1781 sreloc2->set_r_address(0);
1782 sreloc2->set_r_value(fromAddr);
1783 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1784 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1785 return 2;
1786 }
1787
1788 case A::kBranch24WeakImport:
1789 case A::kBranch24:
1790 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1791 reloc1.set_r_address(address);
1792 if ( isExtern )
1793 reloc1.set_r_symbolnum(symbolIndex);
1794 else
1795 reloc1.set_r_symbolnum(sectionNum);
1796 reloc1.set_r_pcrel(true);
1797 reloc1.set_r_length(2);
1798 reloc1.set_r_type(PPC_RELOC_BR24);
1799 reloc1.set_r_extern(isExtern);
1800 }
1801 else {
1802 sreloc1->set_r_scattered(true);
1803 sreloc1->set_r_pcrel(true);
1804 sreloc1->set_r_length(2);
1805 sreloc1->set_r_type(PPC_RELOC_BR24);
1806 sreloc1->set_r_address(address);
1807 sreloc1->set_r_value(target.getAddress());
1808 }
1809 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1810 return 1;
1811
1812 case A::kBranch14:
1813 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1814 reloc1.set_r_address(address);
1815 if ( isExtern )
1816 reloc1.set_r_symbolnum(symbolIndex);
1817 else
1818 reloc1.set_r_symbolnum(sectionNum);
1819 reloc1.set_r_pcrel(true);
1820 reloc1.set_r_length(2);
1821 reloc1.set_r_type(PPC_RELOC_BR14);
1822 reloc1.set_r_extern(isExtern);
1823 }
1824 else {
1825 sreloc1->set_r_scattered(true);
1826 sreloc1->set_r_pcrel(true);
1827 sreloc1->set_r_length(2);
1828 sreloc1->set_r_type(PPC_RELOC_BR14);
1829 sreloc1->set_r_address(address);
1830 sreloc1->set_r_value(target.getAddress());
1831 }
1832 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1833 return 1;
1834
1835 case A::kPICBaseLow16:
1836 case A::kPICBaseLow14:
1837 {
1838 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
1839 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1840 sreloc1->set_r_scattered(true);
1841 sreloc1->set_r_pcrel(false);
1842 sreloc1->set_r_length(2);
1843 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
1844 sreloc1->set_r_address(address);
1845 sreloc1->set_r_value(target.getAddress());
1846 sreloc2->set_r_scattered(true);
1847 sreloc2->set_r_pcrel(false);
1848 sreloc2->set_r_length(2);
1849 sreloc2->set_r_type(PPC_RELOC_PAIR);
1850 sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
1851 sreloc2->set_r_value(fromAddr);
1852 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1853 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1854 return 2;
1855 }
1856
1857 case A::kPICBaseHigh16:
1858 {
1859 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
1860 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1861 sreloc1->set_r_scattered(true);
1862 sreloc1->set_r_pcrel(false);
1863 sreloc1->set_r_length(2);
1864 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
1865 sreloc1->set_r_address(address);
1866 sreloc1->set_r_value(target.getAddress());
1867 sreloc2->set_r_scattered(true);
1868 sreloc2->set_r_pcrel(false);
1869 sreloc2->set_r_length(2);
1870 sreloc2->set_r_type(PPC_RELOC_PAIR);
1871 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
1872 sreloc2->set_r_value(fromAddr);
1873 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1874 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1875 return 2;
1876 }
1877
1878 case A::kAbsLow14:
1879 case A::kAbsLow16:
1880 {
1881 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1882 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1883 reloc1.set_r_address(address);
1884 if ( isExtern )
1885 reloc1.set_r_symbolnum(symbolIndex);
1886 else
1887 reloc1.set_r_symbolnum(sectionNum);
1888 reloc1.set_r_pcrel(false);
1889 reloc1.set_r_length(2);
1890 reloc1.set_r_extern(isExtern);
1891 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
1892 }
1893 else {
1894 sreloc1->set_r_scattered(true);
1895 sreloc1->set_r_pcrel(false);
1896 sreloc1->set_r_length(2);
1897 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
1898 sreloc1->set_r_address(address);
1899 sreloc1->set_r_value(target.getAddress());
1900 }
1901 if ( isExtern )
1902 reloc2.set_r_address(ref->getTargetOffset() >> 16);
1903 else
1904 reloc2.set_r_address(toAddr >> 16);
1905 reloc2.set_r_symbolnum(0);
1906 reloc2.set_r_pcrel(false);
1907 reloc2.set_r_length(2);
1908 reloc2.set_r_extern(false);
1909 reloc2.set_r_type(PPC_RELOC_PAIR);
1910 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1911 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1912 return 2;
1913 }
1914
1915 case A::kAbsHigh16:
1916 {
1917 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1918 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1919 reloc1.set_r_address(address);
1920 if ( isExtern )
1921 reloc1.set_r_symbolnum(symbolIndex);
1922 else
1923 reloc1.set_r_symbolnum(sectionNum);
1924 reloc1.set_r_pcrel(false);
1925 reloc1.set_r_length(2);
1926 reloc1.set_r_extern(isExtern);
1927 reloc1.set_r_type(PPC_RELOC_HI16);
1928 }
1929 else {
1930 sreloc1->set_r_scattered(true);
1931 sreloc1->set_r_pcrel(false);
1932 sreloc1->set_r_length(2);
1933 sreloc1->set_r_type(PPC_RELOC_HI16);
1934 sreloc1->set_r_address(address);
1935 sreloc1->set_r_value(target.getAddress());
1936 }
1937 if ( isExtern )
1938 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
1939 else
1940 reloc2.set_r_address(toAddr & 0xFFFF);
1941 reloc2.set_r_symbolnum(0);
1942 reloc2.set_r_pcrel(false);
1943 reloc2.set_r_length(2);
1944 reloc2.set_r_extern(false);
1945 reloc2.set_r_type(PPC_RELOC_PAIR);
1946 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1947 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1948 return 2;
1949 }
1950
1951 case A::kAbsHigh16AddLow:
1952 {
1953 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1954 uint32_t overflow = 0;
1955 if ( (toAddr & 0x00008000) != 0 )
1956 overflow = 0x10000;
1957 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1958 reloc1.set_r_address(address);
1959 if ( isExtern )
1960 reloc1.set_r_symbolnum(symbolIndex);
1961 else
1962 reloc1.set_r_symbolnum(sectionNum);
1963 reloc1.set_r_pcrel(false);
1964 reloc1.set_r_length(2);
1965 reloc1.set_r_extern(isExtern);
1966 reloc1.set_r_type(PPC_RELOC_HA16);
1967 }
1968 else {
1969 sreloc1->set_r_scattered(true);
1970 sreloc1->set_r_pcrel(false);
1971 sreloc1->set_r_length(2);
1972 sreloc1->set_r_type(PPC_RELOC_HA16);
1973 sreloc1->set_r_address(address);
1974 sreloc1->set_r_value(target.getAddress());
1975 }
1976 if ( isExtern )
1977 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
1978 else
1979 reloc2.set_r_address(toAddr & 0xFFFF);
1980 reloc2.set_r_symbolnum(0);
1981 reloc2.set_r_pcrel(false);
1982 reloc2.set_r_length(2);
1983 reloc2.set_r_extern(false);
1984 reloc2.set_r_type(PPC_RELOC_PAIR);
1985 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1986 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1987 return 2;
1988 }
1989
1990 }
1991 return 0;
1992 }
1993
1994
1995 template <typename A>
1996 void Writer<A>::buildObjectFileFixups()
1997 {
1998 uint32_t relocIndex = 0;
1999 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2000 const int segCount = segmentInfos.size();
2001 for(int i=0; i < segCount; ++i) {
2002 SegmentInfo* curSegment = segmentInfos[i];
2003 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2004 const int sectionCount = sectionInfos.size();
2005 for(int j=0; j < sectionCount; ++j) {
2006 SectionInfo* curSection = sectionInfos[j];
2007 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
2008 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2009 if ( ! curSection->fAllZeroFill ) {
2010 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
2011 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2012 curSection->fRelocOffset = relocIndex;
2013 const int atomCount = sectionAtoms.size();
2014 for (int k=0; k < atomCount; ++k) {
2015 ObjectFile::Atom* atom = sectionAtoms[k];
2016 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
2017 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2018 const int refCount = refs.size();
2019 for (int l=0; l < refCount; ++l) {
2020 ObjectFile::Reference* ref = refs[l];
2021 if ( ref->getKind() == A::kFollowOn )
2022 fSeenFollowOnReferences = true;
2023 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
2024 uint32_t offsetInSection = atom->getSectionOffset();
2025 uint32_t indexInSection = offsetInSection / atom->getSize();
2026 uint32_t undefinedSymbolIndex;
2027 if ( curSection->fAllStubs ) {
2028 ObjectFile::Atom& stubTarget =ref->getTarget();
2029 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
2030 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
2031 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
2032 }
2033 else {
2034 if ( curSection->fAllNonLazyPointers
2035 && (ref->getTarget().getScope() == ObjectFile::Atom::scopeLinkageUnit)
2036 && !fOptions.keepPrivateExterns() )
2037 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2038 else
2039 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
2040 }
2041 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2042 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2043 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
2044 fIndirectTableAtom->fTable.push_back(entry);
2045 if ( curSection->fAllLazyPointers ) {
2046 ObjectFile::Atom& target = ref->getTarget();
2047 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2048 if ( &fromTarget == NULL ) {
2049 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
2050 }
2051 else {
2052 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
2053 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
2054 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
2055 macho_relocation_info<P> reloc1;
2056 reloc1.set_r_address(atom->getSectionOffset());
2057 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
2058 reloc1.set_r_pcrel(false);
2059 reloc1.set_r_length();
2060 reloc1.set_r_extern(isExtern);
2061 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2062 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2063 ++relocIndex;
2064 }
2065 }
2066 else if ( curSection->fAllStubs ) {
2067 relocIndex += this->addObjectRelocs(atom, ref);
2068 }
2069 }
2070 else {
2071 relocIndex += this->addObjectRelocs(atom, ref);
2072 }
2073 }
2074 }
2075 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
2076 }
2077 }
2078 }
2079
2080 // now reverse reloc entries
2081 for(int i=0; i < segCount; ++i) {
2082 SegmentInfo* curSegment = segmentInfos[i];
2083 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2084 const int sectionCount = sectionInfos.size();
2085 for(int j=0; j < sectionCount; ++j) {
2086 SectionInfo* curSection = sectionInfos[j];
2087 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
2088 }
2089 }
2090
2091 }
2092
2093 template <>
2094 bool Writer<ppc>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
2095 {
2096 switch ( kind ) {
2097 case ppc::kAbsLow16:
2098 case ppc::kAbsLow14:
2099 case ppc::kAbsHigh16:
2100 case ppc::kAbsHigh16AddLow:
2101 if ( slideable )
2102 return true;
2103 }
2104 return false;
2105 }
2106
2107
2108 template <>
2109 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
2110 {
2111 switch ( kind ) {
2112 case ppc::kAbsLow16:
2113 case ppc::kAbsLow14:
2114 case ppc::kAbsHigh16:
2115 case ppc::kAbsHigh16AddLow:
2116 if ( slideable )
2117 return true;
2118 }
2119 return false;
2120 }
2121
2122 template <>
2123 bool Writer<x86>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
2124 {
2125 return false;
2126 }
2127
2128
2129
2130 template <typename A>
2131 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
2132 {
2133 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2134
2135 switch ( target.getDefinitionKind() ) {
2136 case ObjectFile::Atom::kTentativeDefinition:
2137 case ObjectFile::Atom::kRegularDefinition:
2138 // for flat-namespace or interposable two-level-namespace
2139 // all references to exported symbols get indirected
2140 if ( this->shouldExport(target) &&
2141 ((fOptions.nameSpace() == Options::kFlatNameSpace)
2142 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
2143 || fOptions.interposable()) )
2144 return kRelocExternal;
2145 else if ( slideable )
2146 return kRelocInternal;
2147 else
2148 return kRelocNone;
2149 case ObjectFile::Atom::kWeakDefinition:
2150 // all calls to global weak definitions get indirected
2151 if ( this->shouldExport(target) )
2152 return kRelocExternal;
2153 else if ( slideable )
2154 return kRelocInternal;
2155 else
2156 return kRelocNone;
2157 case ObjectFile::Atom::kExternalDefinition:
2158 case ObjectFile::Atom::kExternalWeakDefinition:
2159 return kRelocExternal;
2160 }
2161 return kRelocNone;
2162 }
2163
2164 template <typename A>
2165 void Writer<A>::buildExecutableFixups()
2166 {
2167 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2168 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
2169 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2170 const int segCount = segmentInfos.size();
2171 for(int i=0; i < segCount; ++i) {
2172 SegmentInfo* curSegment = segmentInfos[i];
2173 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2174 const int sectionCount = sectionInfos.size();
2175 for(int j=0; j < sectionCount; ++j) {
2176 SectionInfo* curSection = sectionInfos[j];
2177 //fprintf(stderr, "starting section %p\n", curSection->fSectionName);
2178 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2179 if ( ! curSection->fAllZeroFill ) {
2180 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
2181 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2182 const int atomCount = sectionAtoms.size();
2183 for (int k=0; k < atomCount; ++k) {
2184 ObjectFile::Atom* atom = sectionAtoms[k];
2185 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2186 const int refCount = refs.size();
2187 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
2188 for (int l=0; l < refCount; ++l) {
2189 ObjectFile::Reference* ref = refs[l];
2190 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
2191 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
2192 if ( atom->getSize() != sizeof(pint_t) ) {
2193 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
2194 }
2195 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
2196 if ( curSection->fAllLazyPointers ) {
2197 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
2198 }
2199 uint32_t offsetInSection = atom->getSectionOffset();
2200 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
2201 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2202 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
2203 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
2204 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2205 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2206 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
2207 fIndirectTableAtom->fTable.push_back(entry);
2208 if ( slideable && curSection->fAllLazyPointers ) {
2209 // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
2210 macho_relocation_info<P> pblaReloc;
2211 uint32_t sectionNum = 1;
2212 if ( fDyldHelper != NULL )
2213 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
2214 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
2215 pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
2216 pblaReloc.set_r_symbolnum(sectionNum);
2217 pblaReloc.set_r_pcrel(false);
2218 pblaReloc.set_r_length();
2219 pblaReloc.set_r_extern(false);
2220 pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
2221 fInternalRelocs.push_back(pblaReloc);
2222 }
2223 }
2224 else if ( ref->getKind() == A::kPointer ) {
2225 if ( slideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
2226 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
2227 }
2228 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
2229 case kRelocNone:
2230 // no reloc needed
2231 break;
2232 case kRelocInternal:
2233 {
2234 macho_relocation_info<P> internalReloc;
2235 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
2236 uint32_t sectionNum = sectInfo->getIndex();
2237 // special case _mh_dylib_header and friends which are not in any real section
2238 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
2239 sectionNum = 1;
2240 internalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
2241 internalReloc.set_r_symbolnum(sectionNum);
2242 internalReloc.set_r_pcrel(false);
2243 internalReloc.set_r_length();
2244 internalReloc.set_r_extern(false);
2245 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2246 fInternalRelocs.push_back(internalReloc);
2247 }
2248 break;
2249 case kRelocExternal:
2250 {
2251 macho_relocation_info<P> externalReloc;
2252 externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
2253 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
2254 externalReloc.set_r_pcrel(false);
2255 externalReloc.set_r_length();
2256 externalReloc.set_r_extern(true);
2257 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2258 fExternalRelocs.push_back(externalReloc);
2259 }
2260 break;
2261 }
2262 }
2263 else if ( this->illegalRelocInFinalLinkedImage(ref->getKind(), slideable) ) {
2264 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
2265 }
2266 }
2267 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
2268 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
2269 uint32_t undefinedSymbolIndex = this->symbolIndex(*stubTarget);
2270 uint32_t offsetInSection = atom->getSectionOffset();
2271 uint32_t indexInSection = offsetInSection / atom->getSize();
2272 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2273 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2274 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
2275 fIndirectTableAtom->fTable.push_back(entry);
2276 }
2277 }
2278 }
2279 }
2280 }
2281 }
2282
2283
2284 template <>
2285 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
2286 {
2287 uint32_t ppcNop;
2288 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2289 for (uint32_t p=from; p < to; p += 4)
2290 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2291 }
2292
2293 template <>
2294 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
2295 {
2296 uint32_t ppcNop;
2297 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2298 for (uint32_t p=from; p < to; p += 4)
2299 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2300 }
2301
2302 template <>
2303 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
2304 {
2305 uint8_t x86Nop = 0x90;
2306 for (uint32_t p=from; p < to; ++p)
2307 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
2308 }
2309
2310
2311 template <typename A>
2312 uint64_t Writer<A>::writeAtoms()
2313 {
2314 uint32_t end = 0;
2315 uint8_t* buffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
2316 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2317 const int segCount = segmentInfos.size();
2318 for(int i=0; i < segCount; ++i) {
2319 SegmentInfo* curSegment = segmentInfos[i];
2320 bool isTextSeg = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
2321 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2322 const int sectionCount = sectionInfos.size();
2323 for(int j=0; j < sectionCount; ++j) {
2324 SectionInfo* curSection = sectionInfos[j];
2325 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2326 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
2327 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
2328 if ( ! curSection->fAllZeroFill ) {
2329 const int atomCount = sectionAtoms.size();
2330 end = curSection->fFileOffset;
2331 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
2332 for (int k=0; k < atomCount; ++k) {
2333 ObjectFile::Atom* atom = sectionAtoms[k];
2334 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
2335 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) ) {
2336 uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
2337 if ( offset != end ) {
2338 if ( needsNops ) {
2339 // fill gaps with no-ops
2340 writeNoOps(end, offset);
2341 }
2342 else {
2343 // zero fill gaps
2344 if ( (offset-end) == 4 ) {
2345 uint32_t zero = 0;
2346 ::pwrite(fFileDescriptor, &zero, 4, end);
2347 }
2348 else {
2349 uint8_t zero = 0x00;
2350 for (uint32_t p=end; p < offset; ++p)
2351 ::pwrite(fFileDescriptor, &zero, 1, p);
2352 }
2353 }
2354 }
2355 uint64_t atomSize = atom->getSize();
2356 if ( atomSize > fLargestAtomSize ) {
2357 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
2358 atom->getDisplayName(), atomSize, fLargestAtomSize);
2359 }
2360 end = offset+atomSize;
2361 // copy raw bytes
2362 atom->copyRawContent(buffer);
2363 // apply any fix-ups
2364 try {
2365 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2366 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
2367 ObjectFile::Reference* ref = *it;
2368 if ( fOptions.outputKind() == Options::kObjectFile ) {
2369 // doing ld -r
2370 // skip fix-ups for undefined targets
2371 if ( &(ref->getTarget()) != NULL )
2372 this->fixUpReferenceRelocatable(ref, atom, buffer);
2373 }
2374 else {
2375 // producing final linked image
2376 this->fixUpReferenceFinal(ref, atom, buffer);
2377 }
2378 }
2379 }
2380 catch (const char* msg) {
2381 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
2382 }
2383 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s\n", offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName());
2384 // write out
2385 ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
2386 }
2387 }
2388 }
2389 }
2390 }
2391 delete [] buffer;
2392 return end;
2393 }
2394
2395
2396 template <>
2397 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2398 {
2399 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2400 switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
2401 case x86::kNoFixUp:
2402 case x86::kFollowOn:
2403 // do nothing
2404 break;
2405 case x86::kPointerWeakImport:
2406 case x86::kPointer:
2407 {
2408 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition ) {
2409 // external realocation ==> pointer contains addend
2410 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2411 }
2412 else {
2413 // internal relocation => pointer contains target address
2414 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2415 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2416 }
2417 }
2418 break;
2419 case x86::kPointerDiff:
2420 LittleEndian::set32(*fixUp,
2421 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2422 break;
2423 case x86::kPCRel32WeakImport:
2424 case x86::kPCRel32:
2425 int64_t displacement = 0;
2426 switch ( ref->getTarget().getDefinitionKind() ) {
2427 case ObjectFile::Atom::kRegularDefinition:
2428 case ObjectFile::Atom::kWeakDefinition:
2429 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2430 break;
2431 case ObjectFile::Atom::kExternalDefinition:
2432 case ObjectFile::Atom::kExternalWeakDefinition:
2433 throw "codegen problem, can't use rel32 to external symbol";
2434 case ObjectFile::Atom::kTentativeDefinition:
2435 displacement = 0;
2436 break;
2437 }
2438 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2439 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2440 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
2441 throw "rel32 out of range";
2442 }
2443 LittleEndian::set32(*fixUp, (int32_t)displacement);
2444 break;
2445 }
2446 }
2447
2448 template <>
2449 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2450 {
2451 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2452 bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2453 && shouldExport(ref->getTarget()) );
2454 switch (ref->getKind()) {
2455 case x86::kNoFixUp:
2456 case x86::kFollowOn:
2457 // do nothing
2458 break;
2459 case x86::kPointer:
2460 {
2461 if ( isExternal ) {
2462 // external realocation ==> pointer contains addend
2463 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2464 }
2465 else {
2466 // internal relocation
2467 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
2468 // pointer contains target address
2469 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2470 }
2471 else {
2472 // pointer contains addend
2473 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2474 }
2475 }
2476 }
2477 break;
2478 case x86::kPointerDiff:
2479 LittleEndian::set32(*fixUp,
2480 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2481 break;
2482 case x86::kPCRel32:
2483 int64_t displacement = 0;
2484 if ( isExternal )
2485 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2486 else
2487 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2488 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2489 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2490 //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
2491 throw "rel32 out of range";
2492 }
2493 LittleEndian::set32(*fixUp, (int32_t)displacement);
2494 break;
2495 }
2496 }
2497
2498
2499 template <>
2500 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2501 {
2502 fixUpReference_powerpc(ref, inAtom, buffer, true);
2503 }
2504
2505 template <>
2506 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2507 {
2508 fixUpReference_powerpc(ref, inAtom, buffer, true);
2509 }
2510
2511 template <>
2512 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2513 {
2514 fixUpReference_powerpc(ref, inAtom, buffer, false);
2515 }
2516
2517 template <>
2518 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2519 {
2520 fixUpReference_powerpc(ref, inAtom, buffer, false);
2521 }
2522
2523 //
2524 // ppc and ppc64 are mostly the same, so they share a template specialzation
2525 //
2526 template <typename A>
2527 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
2528 {
2529 uint32_t instruction;
2530 uint32_t newInstruction;
2531 int64_t displacement;
2532 uint64_t targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
2533 uint64_t picBaseAddr;
2534 uint16_t instructionLowHalf;
2535 uint16_t instructionHighHalf;
2536 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2537 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
2538 bool relocateableExternal;
2539
2540 if ( finalLinkedImage )
2541 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
2542 else
2543 relocateableExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2544 && shouldExport(ref->getTarget()) );
2545
2546 const int64_t picbase_twoGigLimit = 0x80000000;
2547
2548 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
2549 case A::kNoFixUp:
2550 case A::kFollowOn:
2551 // do nothing
2552 break;
2553 case A::kPointerWeakImport:
2554 case A::kPointer:
2555 {
2556 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
2557 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
2558 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
2559 if ( fDyldHelper == NULL )
2560 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2561 P::setP(*fixUpPointer, fDyldHelper->getAddress());
2562 }
2563 else if ( relocateableExternal ) {
2564 // external realocation ==> pointer contains addend
2565 P::setP(*fixUpPointer, ref->getTargetOffset());
2566 }
2567 else {
2568 // internal relocation
2569 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
2570 // pointer contains target address
2571 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2572 P::setP(*fixUpPointer, targetAddr);
2573 }
2574 else {
2575 // pointer contains addend
2576 P::setP(*fixUpPointer, ref->getTargetOffset());
2577 }
2578 }
2579 }
2580 break;
2581 case A::kPointerDiff64:
2582 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2583 break;
2584 case A::kPointerDiff32:
2585 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2586 break;
2587 case A::kBranch24WeakImport:
2588 case A::kBranch24:
2589 {
2590 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
2591 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
2592 if ( relocateableExternal ) {
2593 // doing "ld -r" to an external symbol
2594 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
2595 displacement -= ref->getTarget().getAddress();
2596 }
2597 else {
2598 const int64_t bl_eightMegLimit = 0x00FFFFFF;
2599 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
2600 //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
2601 throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s",
2602 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
2603 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
2604 }
2605 }
2606 instruction = BigEndian::get32(*fixUp);
2607 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
2608 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
2609 BigEndian::set32(*fixUp, newInstruction);
2610 }
2611 break;
2612 case A::kBranch14:
2613 {
2614 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
2615 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
2616 if ( relocateableExternal ) {
2617 // doing "ld -r" to an external symbol
2618 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
2619 displacement -= ref->getTarget().getAddress();
2620 }
2621 else {
2622 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
2623 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
2624 //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
2625 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
2626 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
2627 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
2628 }
2629 }
2630 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
2631 instruction = BigEndian::get32(*fixUp);
2632 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
2633 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
2634 BigEndian::set32(*fixUp, newInstruction);
2635 }
2636 break;
2637 case A::kPICBaseLow16:
2638 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
2639 displacement = targetAddr - picBaseAddr;
2640 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
2641 throw "32-bit pic-base out of range";
2642 instructionLowHalf = (displacement & 0xFFFF);
2643 instruction = BigEndian::get32(*fixUp);
2644 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
2645 BigEndian::set32(*fixUp, newInstruction);
2646 break;
2647 case A::kPICBaseLow14:
2648 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
2649 displacement = targetAddr - picBaseAddr;
2650 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
2651 throw "32-bit pic-base out of range";
2652 if ( (displacement & 0x3) != 0 )
2653 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
2654 instructionLowHalf = (displacement & 0xFFFC);
2655 instruction = BigEndian::get32(*fixUp);
2656 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
2657 BigEndian::set32(*fixUp, newInstruction);
2658 break;
2659 case A::kPICBaseHigh16:
2660 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
2661 displacement = targetAddr - picBaseAddr;
2662 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
2663 throw "32-bit pic-base out of range";
2664 instructionLowHalf = displacement >> 16;
2665 if ( (displacement & 0x00008000) != 0 )
2666 ++instructionLowHalf;
2667 instruction = BigEndian::get32(*fixUp);
2668 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
2669 BigEndian::set32(*fixUp, newInstruction);
2670 break;
2671 case A::kAbsLow16:
2672 if ( relocateableExternal )
2673 targetAddr -= ref->getTarget().getAddress();
2674 instructionLowHalf = (targetAddr & 0xFFFF);
2675 instruction = BigEndian::get32(*fixUp);
2676 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
2677 BigEndian::set32(*fixUp, newInstruction);
2678 break;
2679 case A::kAbsLow14:
2680 if ( relocateableExternal )
2681 targetAddr -= ref->getTarget().getAddress();
2682 if ( (targetAddr & 0x3) != 0 )
2683 throw "bad address for absolute lo14 instruction fix-up";
2684 instructionLowHalf = (targetAddr & 0xFFFF);
2685 instruction = BigEndian::get32(*fixUp);
2686 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
2687 BigEndian::set32(*fixUp, newInstruction);
2688 break;
2689 case A::kAbsHigh16:
2690 if ( relocateableExternal )
2691 targetAddr -= ref->getTarget().getAddress();
2692 instructionHighHalf = (targetAddr >> 16);
2693 instruction = BigEndian::get32(*fixUp);
2694 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
2695 BigEndian::set32(*fixUp, newInstruction);
2696 break;
2697 case A::kAbsHigh16AddLow:
2698 if ( relocateableExternal )
2699 targetAddr -= ref->getTarget().getAddress();
2700 if ( targetAddr & 0x00008000 )
2701 targetAddr += 0x00010000;
2702 instruction = BigEndian::get32(*fixUp);
2703 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
2704 BigEndian::set32(*fixUp, newInstruction);
2705 break;
2706 }
2707 }
2708
2709 template <>
2710 bool Writer<ppc>::stubableReferenceKind(uint8_t kind)
2711 {
2712 return (kind == ppc::kBranch24 || kind == ppc::kBranch24WeakImport);
2713 }
2714
2715 template <>
2716 bool Writer<ppc64>::stubableReferenceKind(uint8_t kind)
2717 {
2718 return (kind == ppc64::kBranch24 || kind == ppc64::kBranch24WeakImport);
2719 }
2720
2721 template <>
2722 bool Writer<x86>::stubableReferenceKind(uint8_t kind)
2723 {
2724 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
2725 }
2726
2727
2728 template <>
2729 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
2730 {
2731 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
2732 }
2733
2734 template <>
2735 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
2736 {
2737 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
2738 }
2739
2740 template <>
2741 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
2742 {
2743 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
2744 }
2745
2746
2747
2748 template <>
2749 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
2750 {
2751 return false;
2752 }
2753
2754 template <>
2755 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
2756 {
2757 return false;
2758 }
2759
2760 template <>
2761 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
2762 {
2763 return false;
2764 }
2765
2766
2767
2768 template <typename A>
2769 void Writer<A>::synthesizeStubs()
2770 {
2771 switch ( fOptions.outputKind() ) {
2772 case Options::kStaticExecutable:
2773 case Options::kDyld:
2774 case Options::kObjectFile:
2775 // these output kinds never have stubs
2776 return;
2777 case Options::kDynamicLibrary:
2778 case Options::kDynamicBundle:
2779 case Options::kDynamicExecutable:
2780 // try to synthesize stubs for these
2781 break;
2782 }
2783
2784 // walk every atom and reference
2785 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2786 ObjectFile::Atom* atom = *it;
2787 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2788 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2789 ObjectFile::Reference* ref = *rit;
2790 ObjectFile::Atom& target = ref->getTarget();
2791 // build map of which symbols need weak importing
2792 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
2793 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
2794 bool weakImport = this->weakImportReferenceKind(ref->getKind());
2795 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
2796 if ( pos == fWeakImportMap.end() ) {
2797 // target not in fWeakImportMap, so add
2798 fWeakImportMap[&target] = weakImport;
2799 }
2800 else {
2801 // target in fWeakImportMap, check for weakness mismatch
2802 if ( pos->second != weakImport ) {
2803 // found mismatch
2804 switch ( fOptions.weakReferenceMismatchTreatment() ) {
2805 case Options::kWeakReferenceMismatchError:
2806 throwf("mismatching weak references for symbol: %s", target.getName());
2807 case Options::kWeakReferenceMismatchWeak:
2808 pos->second = true;
2809 break;
2810 case Options::kWeakReferenceMismatchNonWeak:
2811 pos->second = false;
2812 break;
2813 }
2814 }
2815 }
2816 }
2817 // create stubs as needed
2818 if ( this->stubableReferenceKind(ref->getKind())
2819 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
2820 ObjectFile::Atom* stub = NULL;
2821 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
2822 if ( pos == fStubsMap.end() ) {
2823 stub = new StubAtom<A>(*this, target);
2824 fStubsMap[&target] = stub;
2825 }
2826 else {
2827 stub = pos->second;
2828 }
2829 // alter reference to use stub instead
2830 ref->setTarget(*stub, 0);
2831 }
2832 // create GOT slots (non-lazy pointers) as needed
2833 else if ( this->GOTReferenceKind(ref->getKind()) ) {
2834 ObjectFile::Atom* nlp = NULL;
2835 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
2836 if ( pos == fGOTMap.end() ) {
2837 nlp = new NonLazyPointerAtom<A>(*this, target);
2838 fGOTMap[&target] = nlp;
2839 }
2840 else {
2841 nlp = pos->second;
2842 }
2843 // alter reference to use non lazy pointer instead
2844 ref->setTarget(*nlp, 0);
2845 }
2846 }
2847 }
2848
2849 // sort stubs
2850
2851 // sort lazy pointers
2852
2853 // add stubs to fAllAtoms
2854 if ( fAllSynthesizedStubs.size() != 0 ) {
2855 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
2856 std::vector<ObjectFile::Atom*> mergedStubs;
2857 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
2858 // when we have stubs and helpers, insert both into fAllAtoms
2859 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
2860 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
2861 stubs = &mergedStubs;
2862 }
2863 ObjectFile::Section* curSection = NULL;
2864 ObjectFile::Atom* prevAtom = NULL;
2865 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2866 ObjectFile::Atom* atom = *it;
2867 ObjectFile::Section* nextSection = atom->getSection();
2868 if ( nextSection != curSection ) {
2869 // HACK HACK for i386 where stubs are not in _TEXT segment
2870 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
2871 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
2872 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
2873 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
2874 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
2875 break;
2876 }
2877 }
2878 else {
2879 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
2880 // found end of __text section, insert stubs here
2881 fAllAtoms->insert(it, stubs->begin(), stubs->end());
2882 break;
2883 }
2884 }
2885 curSection = nextSection;
2886 }
2887 prevAtom = atom;
2888 }
2889 }
2890
2891
2892 // add lazy pointers to fAllAtoms
2893 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
2894 ObjectFile::Section* curSection = NULL;
2895 ObjectFile::Atom* prevAtom = NULL;
2896 bool inserted = false;
2897 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2898 ObjectFile::Atom* atom = *it;
2899 ObjectFile::Section* nextSection = atom->getSection();
2900 if ( nextSection != curSection ) {
2901 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
2902 // found end of __dyld section, insert lazy pointers here
2903 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
2904 inserted = true;
2905 break;
2906 }
2907 curSection = nextSection;
2908 }
2909 prevAtom = atom;
2910 }
2911 if ( !inserted ) {
2912 throw "can't insert lazy pointers, __dyld section not found";
2913 }
2914 }
2915
2916 // add non-lazy pointers to fAllAtoms
2917 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
2918 ObjectFile::Section* curSection = NULL;
2919 ObjectFile::Atom* prevAtom = NULL;
2920 bool inserted = false;
2921 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2922 ObjectFile::Atom* atom = *it;
2923 ObjectFile::Section* nextSection = atom->getSection();
2924 if ( nextSection != curSection ) {
2925 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
2926 // found end of __dyld section, insert lazy pointers here
2927 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
2928 inserted = true;
2929 break;
2930 }
2931 curSection = nextSection;
2932 }
2933 prevAtom = atom;
2934 }
2935 if ( !inserted ) {
2936 throw "can't insert non-lazy pointers, __dyld section not found";
2937 }
2938 }
2939 }
2940
2941
2942 template <typename A>
2943 void Writer<A>::partitionIntoSections()
2944 {
2945 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
2946
2947 // for every atom, set its sectionInfo object and section offset
2948 // build up fSegmentInfos along the way
2949 ObjectFile::Section* curSection = NULL;
2950 SectionInfo* currentSectionInfo = NULL;
2951 SegmentInfo* currentSegmentInfo = NULL;
2952 unsigned int sectionIndex = 1;
2953 fSegmentInfos.reserve(8);
2954 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
2955 ObjectFile::Atom* atom = (*fAllAtoms)[i];
2956 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
2957 if ( oneSegmentCommand ) {
2958 if ( currentSegmentInfo == NULL ) {
2959 currentSegmentInfo = new SegmentInfo();
2960 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
2961 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
2962 this->fSegmentInfos.push_back(currentSegmentInfo);
2963 }
2964 currentSectionInfo = new SectionInfo();
2965 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
2966 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
2967 currentSectionInfo->fAlignment = atom->getAlignment();
2968 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
2969 currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') || (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) );
2970 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
2971 currentSectionInfo->setIndex(sectionIndex++);
2972 currentSegmentInfo->fSections.push_back(currentSectionInfo);
2973 }
2974 else {
2975 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
2976 currentSegmentInfo = new SegmentInfo();
2977 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
2978 uint32_t initprot = 0;
2979 if ( atom->getSegment().isContentReadable() )
2980 initprot |= VM_PROT_READ;
2981 if ( atom->getSegment().isContentWritable() )
2982 initprot |= VM_PROT_WRITE;
2983 if ( atom->getSegment().isContentExecutable() )
2984 initprot |= VM_PROT_EXECUTE;
2985 currentSegmentInfo->fInitProtection = initprot;
2986 if ( initprot == 0 )
2987 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
2988 else
2989 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
2990 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
2991 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
2992 this->fSegmentInfos.push_back(currentSegmentInfo);
2993 }
2994 currentSectionInfo = new SectionInfo();
2995 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
2996 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
2997 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
2998 currentSectionInfo->fAlignment = atom->getAlignment();
2999 // check for -sectalign override
3000 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
3001 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
3002 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
3003 currentSectionInfo->fAlignment = it->alignment;
3004 }
3005 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
3006 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
3007 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
3008 currentSectionInfo->setIndex(sectionIndex++);
3009 currentSegmentInfo->fSections.push_back(currentSectionInfo);
3010 }
3011 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
3012 fLoadCommandsSection = currentSectionInfo;
3013 fLoadCommandsSegment = currentSegmentInfo;
3014 }
3015 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
3016 currentSectionInfo->fAllLazyPointers = true;
3017 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
3018 currentSectionInfo->fAllLazyPointers = true;
3019 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
3020 currentSectionInfo->fAllNonLazyPointers = true;
3021 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
3022 currentSectionInfo->fAllNonLazyPointers = true;
3023 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
3024 currentSectionInfo->fAllStubs = true;
3025 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
3026 currentSectionInfo->fAllStubs = true;
3027 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
3028 currentSectionInfo->fAllStubs = true;
3029 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
3030 currentSectionInfo->fAllStubs = true;
3031 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) )
3032 currentSectionInfo->fAllSelfModifyingStubs = true;
3033 curSection = atom->getSection();
3034 }
3035 // any non-zero fill atoms make whole section marked not-zero-fill
3036 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
3037 currentSectionInfo->fAllZeroFill = false;
3038 // change section object to be Writer's SectionInfo object
3039 atom->setSection(currentSectionInfo);
3040 // section alignment is that of a contained atom with the greatest alignment
3041 uint8_t atomAlign = atom->getAlignment();
3042 if ( currentSectionInfo->fAlignment < atomAlign )
3043 currentSectionInfo->fAlignment = atomAlign;
3044 // calculate section offset for this atom
3045 uint64_t offset = currentSectionInfo->fSize;
3046 uint64_t alignment = 1 << atomAlign;
3047 offset = ( (offset+alignment-1) & (-alignment) );
3048 atom->setSectionOffset(offset);
3049 uint64_t curAtomSize = atom->getSize();
3050 currentSectionInfo->fSize = offset + curAtomSize;
3051 // add atom to section vector
3052 currentSectionInfo->fAtoms.push_back(atom);
3053 // update largest size
3054 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
3055 fLargestAtomSize = curAtomSize;
3056 }
3057 }
3058
3059
3060 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
3061 class TargetAndOffsetComparor
3062 {
3063 public:
3064 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
3065 {
3066 if ( left.atom != right.atom )
3067 return ( left.atom < right.atom );
3068 return ( left.offset < right.offset );
3069 }
3070 };
3071
3072 template <>
3073 bool Writer<ppc>::addBranchIslands()
3074 {
3075 return this->addPPCBranchIslands();
3076 }
3077
3078 template <>
3079 bool Writer<ppc64>::addBranchIslands()
3080 {
3081 return this->addPPCBranchIslands();
3082 }
3083
3084 template <>
3085 bool Writer<x86>::addBranchIslands()
3086 {
3087 // x86 branches can reach entire 4G address space, so no need for branch islands
3088 return false;
3089 }
3090
3091
3092 template <>
3093 inline uint8_t Writer<ppc>::branch24Reference()
3094 {
3095 return ppc::kBranch24;
3096 }
3097
3098 template <>
3099 inline uint8_t Writer<ppc64>::branch24Reference()
3100 {
3101 return ppc64::kBranch24;
3102 }
3103
3104 //
3105 // PowerPC can do PC relative branches as far as +/-16MB.
3106 // If a branch target is >16MB then we insert one or more
3107 // "branch islands" between the branch and its target that
3108 // allows island hoping to the target.
3109 //
3110 // Branch Island Algorithm
3111 //
3112 // If the __TEXT segment < 16MB, then no branch islands needed
3113 // Otherwise, every 15MB into the __TEXT segment is region is
3114 // added which can contain branch islands. Every out of range
3115 // bl instruction is checked. If it crosses a region, an island
3116 // is added to that region with the same target and the bl is
3117 // adjusted to target the island instead.
3118 //
3119 // In theory, if too many islands are added to one region, it
3120 // could grow the __TEXT enough that other previously in-range
3121 // bl branches could be pushed out of range. We reduce the
3122 // probability this could happen by placing the ranges every
3123 // 15MB which means the region would have to be 1MB (256K islands)
3124 // before any branches could be pushed out of range.
3125 //
3126 template <typename A>
3127 bool Writer<A>::addPPCBranchIslands()
3128 {
3129 bool result = false;
3130 // Can only possibly need branch islands if __TEXT segment > 16M
3131 if ( fLoadCommandsSegment->fSize > 16000000 ) {
3132 //fprintf(stderr, "ld64: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
3133 const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
3134 SectionInfo* textSection = NULL;
3135 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
3136 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
3137 textSection = *it;
3138 //fprintf(stderr, "ld64: checking for branch islands, __text section size=%llu\n", textSection->fSize);
3139 break;
3140 }
3141 }
3142 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
3143 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
3144 AtomToIsland regionsMap[kIslandRegionsCount];
3145 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
3146 unsigned int islandCount = 0;
3147
3148 // create islands for branch references that are out of range
3149 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3150 ObjectFile::Atom* atom = *it;
3151 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3152 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3153 ObjectFile::Reference* ref = *rit;
3154 if ( ref->getKind() == this->branch24Reference() ) {
3155 ObjectFile::Atom& target = ref->getTarget();
3156 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
3157 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
3158 int64_t displacement = dstAddr - srcAddr;
3159 const int64_t kFifteenMegLimit = kBetweenRegions;
3160 if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
3161 for (int i=0; i < kIslandRegionsCount; ++i) {
3162 AtomToIsland* region=&regionsMap[i];
3163 int64_t islandRegionAddr = kBetweenRegions * (i+1);
3164 if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
3165 ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
3166 TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
3167 AtomToIsland::iterator pos = region->find(islandTarget);
3168 if ( pos == region->end() ) {
3169 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
3170 island->setSection(textSection);
3171 (*region)[islandTarget] = island;
3172 regionsIslands[i].push_back(island);
3173 ++islandCount;
3174 ref->setTarget(*island, 0);
3175 }
3176 else {
3177 ref->setTarget(*(pos->second), 0);
3178 }
3179 }
3180 }
3181 }
3182 }
3183 }
3184 }
3185
3186 // insert islands into __text section and adjust section offsets
3187 if ( islandCount > 0 ) {
3188 //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
3189 std::vector<ObjectFile::Atom*> newAtomList;
3190 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
3191 uint64_t islandRegionAddr = kBetweenRegions;
3192 int regionIndex = 0;
3193 uint64_t sectionOffset = 0;
3194 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
3195 ObjectFile::Atom* atom = *it;
3196 newAtomList.push_back(atom);
3197 if ( atom->getAddress() > islandRegionAddr ) {
3198 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
3199 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3200 ObjectFile::Atom* islandAtom = *rit;
3201 newAtomList.push_back(islandAtom);
3202 uint64_t alignment = 1 << (islandAtom->getAlignment());
3203 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3204 islandAtom->setSectionOffset(sectionOffset);
3205 sectionOffset += islandAtom->getSize();
3206 }
3207 ++regionIndex;
3208 islandRegionAddr += kBetweenRegions;
3209 }
3210 uint64_t alignment = 1 << (atom->getAlignment());
3211 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3212 atom->setSectionOffset(sectionOffset);
3213 sectionOffset += atom->getSize();
3214 }
3215 // put any remaining islands at end of __text section
3216 if ( regionIndex < kIslandRegionsCount ) {
3217 sectionOffset = textSection->fSize;
3218 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
3219 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3220 ObjectFile::Atom* islandAtom = *rit;
3221 newAtomList.push_back(islandAtom);
3222 uint64_t alignment = 1 << (islandAtom->getAlignment());
3223 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3224 islandAtom->setSectionOffset(sectionOffset);
3225 sectionOffset += islandAtom->getSize();
3226 }
3227 }
3228
3229 textSection->fAtoms = newAtomList;
3230 textSection->fSize = sectionOffset;
3231 result = true;
3232 }
3233
3234 }
3235 return result;
3236 }
3237
3238
3239 template <typename A>
3240 void Writer<A>::adjustLoadCommandsAndPadding()
3241 {
3242 fSegmentCommands->computeSize();
3243
3244 // recompute load command section offsets
3245 uint64_t offset = 0;
3246 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
3247 const unsigned int atomCount = loadCommandAtoms.size();
3248 for (unsigned int i=0; i < atomCount; ++i) {
3249 ObjectFile::Atom* atom = loadCommandAtoms[i];
3250 uint64_t alignment = 1 << atom->getAlignment();
3251 offset = ( (offset+alignment-1) & (-alignment) );
3252 atom->setSectionOffset(offset);
3253 uint32_t atomSize = atom->getSize();
3254 if ( atomSize > fLargestAtomSize )
3255 fLargestAtomSize = atomSize;
3256 offset += atomSize;
3257 fLoadCommandsSection->fSize = offset;
3258 }
3259
3260 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
3261 const int sectionCount = sectionInfos.size();
3262 uint64_t paddingSize = 0;
3263 if ( fOptions.outputKind() == Options::kDyld ) {
3264 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
3265 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
3266 for(int j=0; j < sectionCount; ++j) {
3267 SectionInfo* curSection = sectionInfos[j];
3268 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
3269 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3270 break;
3271 }
3272 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
3273 }
3274 else if ( fOptions.outputKind() == Options::kObjectFile ) {
3275 // mach-o .o files need no padding between load commands and first section
3276 paddingSize = 0;
3277 }
3278 else {
3279 // calculate max padding to keep segment size same, but all free space at end of load commands
3280 uint64_t totalSize = 0;
3281 uint64_t worstCaseAlignmentPadding = 0;
3282 for(int j=0; j < sectionCount; ++j) {
3283 SectionInfo* curSection = sectionInfos[j];
3284 totalSize += curSection->fSize;
3285 if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
3286 worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
3287 }
3288 uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
3289 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
3290 paddingSize = segmentSize - (totalSize+worstCaseAlignmentPadding);
3291
3292 // if command line requires more padding than this
3293 if ( paddingSize < fOptions.minimumHeaderPad() ) {
3294 int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
3295 paddingSize += extraPages * 4096;
3296 }
3297 }
3298
3299 // adjust atom size and update section size
3300 fHeaderPadding->setSize(paddingSize);
3301 for(int j=0; j < sectionCount; ++j) {
3302 SectionInfo* curSection = sectionInfos[j];
3303 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3304 curSection->fSize = paddingSize;
3305 }
3306 }
3307
3308 // assign file offsets and logical address to all segments
3309 template <typename A>
3310 void Writer<A>::assignFileOffsets()
3311 {
3312 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
3313 bool haveFixedSegments = false;
3314 uint64_t fileOffset = 0;
3315 uint64_t nextContiguousAddress = fOptions.baseAddress();
3316
3317 // Run through the segments and each segment's sections to assign addresses
3318 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3319 SegmentInfo* curSegment = *segit;
3320
3321 fileOffset = (fileOffset+4095) & (-4096);
3322 curSegment->fFileOffset = fileOffset;
3323
3324 // Set the segment base address
3325 if ( curSegment->fFixedAddress )
3326 haveFixedSegments = true;
3327 else
3328 curSegment->fBaseAddress = nextContiguousAddress;
3329
3330 // We've set the segment address, now run through each section.
3331 uint64_t address = curSegment->fBaseAddress;
3332 SectionInfo* firstZeroFillSection = NULL;
3333 SectionInfo* prevSection = NULL;
3334
3335 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3336
3337 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
3338 SectionInfo* curSection = *it;
3339
3340 // adjust section address based on alignment
3341 uint64_t alignment = 1 << curSection->fAlignment;
3342 address = ( (address+alignment-1) & (-alignment) );
3343
3344 // adjust file offset to match address
3345 if ( prevSection != NULL ) {
3346 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
3347 }
3348
3349 // update section info
3350 curSection->fFileOffset = fileOffset;
3351 curSection->setBaseAddress(address);
3352
3353 // keep track of trailing zero fill sections
3354 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
3355 firstZeroFillSection = curSection;
3356 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
3357 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
3358
3359 // update running pointers
3360 address += curSection->fSize;
3361 fileOffset += curSection->fSize;
3362
3363 // update segment info
3364 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
3365 curSegment->fSize = curSegment->fFileSize;
3366 prevSection = curSection;
3367 }
3368
3369 if ( fOptions.outputKind() == Options::kObjectFile ) {
3370 // don't page align .o files
3371 }
3372 else {
3373 // optimize trailing zero-fill sections to not occupy disk space
3374 if ( firstZeroFillSection != NULL ) {
3375 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
3376 fileOffset = firstZeroFillSection->fFileOffset;
3377 }
3378 // page align segment size
3379 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
3380 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
3381 if ( curSegment->fBaseAddress == nextContiguousAddress )
3382 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
3383 }
3384 }
3385
3386 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
3387 if ( haveFixedSegments ) {
3388 int segCount = fSegmentInfos.size();
3389
3390 for(int i=0; i < segCount; ++i) {
3391 SegmentInfo* segment1 = fSegmentInfos[i];
3392
3393 for(int j=0; j < segCount; ++j) {
3394 if ( i != j ) {
3395 SegmentInfo* segment2 = fSegmentInfos[j];
3396
3397 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
3398 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
3399 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3400 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3401 }
3402 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
3403 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
3404 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3405 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3406 }
3407 else {
3408 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3409 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3410 }
3411 }
3412 }
3413 }
3414 }
3415 }
3416
3417 template <typename A>
3418 void Writer<A>::adjustLinkEditSections()
3419 {
3420 // link edit content is always in last segment
3421 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
3422 unsigned int firstLinkEditSectionIndex = 0;
3423 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
3424 ++firstLinkEditSectionIndex;
3425
3426 const unsigned int sectionCount = lastSeg->fSections.size();
3427 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
3428 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
3429 for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
3430 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
3431 const unsigned int atomCount = atoms.size();
3432 uint64_t sectionOffset = 0;
3433 lastSeg->fSections[i]->fFileOffset = fileOffset;
3434 lastSeg->fSections[i]->setBaseAddress(address);
3435 for (unsigned int j=0; j < atomCount; ++j) {
3436 ObjectFile::Atom* atom = atoms[j];
3437 uint64_t alignment = 1 << atom->getAlignment();
3438 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3439 atom->setSectionOffset(sectionOffset);
3440 uint64_t size = atom->getSize();
3441 sectionOffset += size;
3442 if ( size > fLargestAtomSize )
3443 fLargestAtomSize = size;
3444 }
3445 lastSeg->fSections[i]->fSize = sectionOffset;
3446 fileOffset += sectionOffset;
3447 address += sectionOffset;
3448 }
3449 if ( fOptions.outputKind() == Options::kObjectFile ) {
3450 //lastSeg->fBaseAddress = 0;
3451 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
3452 //lastSeg->fFileOffset = 0;
3453 //lastSeg->fFileSize =
3454 }
3455 else {
3456 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
3457 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
3458 }
3459 }
3460
3461
3462 template <typename A>
3463 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
3464 {
3465 switch ( fWriter.fOptions.outputKind() ) {
3466 case Options::kDynamicExecutable:
3467 case Options::kStaticExecutable:
3468 return ObjectFile::Atom::scopeGlobal;
3469 case Options::kDynamicLibrary:
3470 case Options::kDynamicBundle:
3471 case Options::kDyld:
3472 case Options::kObjectFile:
3473 return ObjectFile::Atom::scopeLinkageUnit;
3474 }
3475 throw "unknown header type";
3476 }
3477
3478 template <typename A>
3479 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
3480 {
3481 switch ( fWriter.fOptions.outputKind() ) {
3482 case Options::kDynamicExecutable:
3483 case Options::kStaticExecutable:
3484 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
3485 case Options::kDynamicLibrary:
3486 case Options::kDynamicBundle:
3487 case Options::kDyld:
3488 return ObjectFile::Atom::kSymbolTableIn;
3489 case Options::kObjectFile:
3490 return ObjectFile::Atom::kSymbolTableNotIn;
3491 }
3492 throw "unknown header type";
3493 }
3494
3495 template <typename A>
3496 const char* MachHeaderAtom<A>::getName() const
3497 {
3498 switch ( fWriter.fOptions.outputKind() ) {
3499 case Options::kDynamicExecutable:
3500 case Options::kStaticExecutable:
3501 return "__mh_execute_header";
3502 case Options::kDynamicLibrary:
3503 return "__mh_dylib_header";
3504 case Options::kDynamicBundle:
3505 return "__mh_bundle_header";
3506 case Options::kObjectFile:
3507 return NULL;
3508 case Options::kDyld:
3509 return "__mh_dylinker_header";
3510 }
3511 throw "unknown header type";
3512 }
3513
3514 template <typename A>
3515 const char* MachHeaderAtom<A>::getDisplayName() const
3516 {
3517 switch ( fWriter.fOptions.outputKind() ) {
3518 case Options::kDynamicExecutable:
3519 case Options::kStaticExecutable:
3520 case Options::kDynamicLibrary:
3521 case Options::kDynamicBundle:
3522 case Options::kDyld:
3523 return this->getName();
3524 case Options::kObjectFile:
3525 return "mach header";
3526 }
3527 throw "unknown header type";
3528 }
3529
3530 template <typename A>
3531 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
3532 {
3533 // get file type
3534 uint32_t fileType = 0;
3535 switch ( fWriter.fOptions.outputKind() ) {
3536 case Options::kDynamicExecutable:
3537 case Options::kStaticExecutable:
3538 fileType = MH_EXECUTE;
3539 break;
3540 case Options::kDynamicLibrary:
3541 fileType = MH_DYLIB;
3542 break;
3543 case Options::kDynamicBundle:
3544 fileType = MH_BUNDLE;
3545 break;
3546 case Options::kObjectFile:
3547 fileType = MH_OBJECT;
3548 break;
3549 case Options::kDyld:
3550 fileType = MH_DYLINKER;
3551 break;
3552 }
3553
3554 // get flags
3555 uint32_t flags = 0;
3556 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
3557 if ( ! fWriter.fSeenFollowOnReferences )
3558 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
3559 }
3560 else {
3561 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
3562 flags |= MH_NOUNDEFS;
3563 }
3564 else {
3565 flags = MH_DYLDLINK;
3566 if ( fWriter.fOptions.bindAtLoad() )
3567 flags |= MH_BINDATLOAD;
3568 switch ( fWriter.fOptions.nameSpace() ) {
3569 case Options::kTwoLevelNameSpace:
3570 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
3571 break;
3572 case Options::kFlatNameSpace:
3573 break;
3574 case Options::kForceFlatNameSpace:
3575 flags |= MH_FORCE_FLAT;
3576 break;
3577 }
3578 if ( fWriter.fHasWeakExports )
3579 flags |= MH_WEAK_DEFINES;
3580 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
3581 flags |= MH_BINDS_TO_WEAK;
3582 }
3583 if ( fWriter.fOptions.hasExecutableStack() )
3584 flags |= MH_ALLOW_STACK_EXECUTION;
3585 }
3586
3587 // get commands info
3588 uint32_t commandsSize = 0;
3589 uint32_t commandsCount = 0;
3590
3591 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
3592 const unsigned int atomCount = loadCommandAtoms.size();
3593 for (unsigned int i=0; i < atomCount; ++i) {
3594 ObjectFile::Atom* atom = loadCommandAtoms[i];
3595 commandsSize += atom->getSize();
3596 // segment and symbol table atoms can contain more than one load command
3597 if ( atom == fWriter.fSegmentCommands )
3598 commandsCount += fWriter.fSegmentCommands->commandCount();
3599 else if ( atom == fWriter.fSymbolTableCommands )
3600 commandsCount += fWriter.fSymbolTableCommands->commandCount();
3601 else if ( atom->getSize() != 0)
3602 ++commandsCount;
3603 }
3604
3605 // fill out mach_header
3606 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
3607 setHeaderInfo(*mh);
3608 mh->set_filetype(fileType);
3609 mh->set_ncmds(commandsCount);
3610 mh->set_sizeofcmds(commandsSize);
3611 mh->set_flags(flags);
3612 }
3613
3614 template <>
3615 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
3616 {
3617 header.set_magic(MH_MAGIC);
3618 header.set_cputype(CPU_TYPE_POWERPC);
3619 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
3620 }
3621
3622 template <>
3623 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
3624 {
3625 header.set_magic(MH_MAGIC_64);
3626 header.set_cputype(CPU_TYPE_POWERPC64);
3627 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
3628 header.set_reserved(0);
3629 }
3630
3631 template <>
3632 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
3633 {
3634 header.set_magic(MH_MAGIC);
3635 header.set_cputype(CPU_TYPE_I386);
3636 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
3637 }
3638
3639
3640 template <typename A>
3641 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
3642 : WriterAtom<A>(writer, Segment::fgStackSegment)
3643 {
3644 if ( stackGrowsDown() )
3645 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
3646 else
3647 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
3648 }
3649
3650
3651 template <>
3652 bool CustomStackAtom<ppc>::stackGrowsDown()
3653 {
3654 return true;
3655 }
3656
3657 template <>
3658 bool CustomStackAtom<ppc64>::stackGrowsDown()
3659 {
3660 return true;
3661 }
3662
3663 template <>
3664 bool CustomStackAtom<x86>::stackGrowsDown()
3665 {
3666 return true;
3667 }
3668
3669
3670 template <typename A>
3671 void SegmentLoadCommandsAtom<A>::computeSize()
3672 {
3673 uint64_t size = 0;
3674 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
3675 const int segCount = segmentInfos.size();
3676 for(int i=0; i < segCount; ++i) {
3677 size += sizeof(macho_segment_command<P>);
3678 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
3679 const int sectionCount = sectionInfos.size();
3680 for(int j=0; j < sectionCount; ++j) {
3681 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
3682 size += sizeof(macho_section<P>);
3683 }
3684 }
3685 fSize = size;
3686 fCommandCount = segCount;
3687 }
3688
3689 template <>
3690 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
3691 {
3692 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
3693 }
3694
3695 template <>
3696 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
3697 {
3698 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
3699 }
3700
3701 template <>
3702 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
3703 {
3704 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
3705 }
3706
3707
3708
3709 template <typename A>
3710 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3711 {
3712 uint64_t size = this->getSize();
3713 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
3714 bzero(buffer, size);
3715 uint8_t* p = buffer;
3716 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
3717 const int segCount = segmentInfos.size();
3718 for(int i=0; i < segCount; ++i) {
3719 SegmentInfo* segInfo = segmentInfos[i];
3720 const int sectionCount = segInfo->fSections.size();
3721 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
3722 cmd->set_cmd(macho_segment_command<P>::CMD);
3723 cmd->set_segname(segInfo->fName);
3724 cmd->set_vmaddr(segInfo->fBaseAddress);
3725 cmd->set_vmsize(segInfo->fSize);
3726 cmd->set_fileoff(segInfo->fFileOffset);
3727 cmd->set_filesize(segInfo->fFileSize);
3728 cmd->set_maxprot(segInfo->fMaxProtection);
3729 cmd->set_initprot(segInfo->fInitProtection);
3730 // add sections array
3731 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
3732 unsigned int sectionsEmitted = 0;
3733 for (int j=0; j < sectionCount; ++j) {
3734 SectionInfo* sectInfo = segInfo->fSections[j];
3735 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
3736 macho_section<P>* sect = &sections[sectionsEmitted++];
3737 if ( oneSegment ) {
3738 // .o file segment does not cover load commands, so recalc at first real section
3739 if ( sectionsEmitted == 1 ) {
3740 cmd->set_vmaddr(sectInfo->getBaseAddress());
3741 cmd->set_fileoff(sectInfo->fFileOffset);
3742 }
3743 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
3744 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
3745 }
3746 sect->set_sectname(sectInfo->fSectionName);
3747 sect->set_segname(sectInfo->fSegmentName);
3748 sect->set_addr(sectInfo->getBaseAddress());
3749 sect->set_size(sectInfo->fSize);
3750 sect->set_offset(sectInfo->fFileOffset);
3751 sect->set_align(sectInfo->fAlignment);
3752 if ( sectInfo->fRelocCount != 0 ) {
3753 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
3754 sect->set_nreloc(sectInfo->fRelocCount);
3755 }
3756 if ( sectInfo->fAllZeroFill ) {
3757 sect->set_flags(S_ZEROFILL);
3758 sect->set_offset(0);
3759 }
3760 else if ( sectInfo->fAllLazyPointers ) {
3761 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
3762 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3763 }
3764 else if ( sectInfo->fAllNonLazyPointers ) {
3765 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
3766 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3767 }
3768 else if ( sectInfo->fAllStubs ) {
3769 sect->set_flags(S_SYMBOL_STUBS);
3770 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3771 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
3772 }
3773 else if ( sectInfo->fAllSelfModifyingStubs ) {
3774 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
3775 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
3776 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
3777 }
3778 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3779 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
3780 }
3781 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3782 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
3783 }
3784 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3785 sect->set_flags(S_COALESCED);
3786 }
3787 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3788 sect->set_flags(S_COALESCED);
3789 }
3790 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3791 sect->set_flags(S_COALESCED);
3792 }
3793 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
3794 sect->set_flags(S_INTERPOSING);
3795 }
3796 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3797 sect->set_flags(S_CSTRING_LITERALS);
3798 }
3799 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3800 sect->set_flags(S_4BYTE_LITERALS);
3801 }
3802 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
3803 sect->set_flags(S_8BYTE_LITERALS);
3804 }
3805 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
3806 sect->set_flags(S_LITERAL_POINTERS);
3807 }
3808 }
3809 }
3810 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
3811 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
3812 cmd->set_nsects(sectionsEmitted);
3813 }
3814 }
3815
3816
3817 template <typename A>
3818 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
3819 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
3820 {
3821 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
3822 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
3823 writer.fSymbolTableCommands = this;
3824 }
3825
3826 template <typename A>
3827 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
3828 {
3829 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable )
3830 return this->alignedSize(sizeof(macho_symtab_command<P>));
3831 else
3832 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
3833 }
3834
3835 template <typename A>
3836 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3837 {
3838 // build LC_DYSYMTAB command
3839 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
3840 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
3841 symbolTableCmd->set_cmd(LC_SYMTAB);
3842 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
3843 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
3844 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
3845 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
3846 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
3847
3848 // build LC_DYSYMTAB command
3849 if ( fWriter.fOptions.outputKind() != Options::kStaticExecutable ) {
3850 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
3851 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
3852 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
3853 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
3854 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
3855 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
3856 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
3857 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
3858 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
3859 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
3860 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
3861 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
3862 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
3863 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
3864 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
3865 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
3866 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
3867 }
3868 }
3869 }
3870
3871 template <typename A>
3872 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
3873 {
3874 return (fWriter.fOptions.outputKind() == Options::kStaticExecutable) ? 1 : 2;
3875 }
3876
3877 template <typename A>
3878 uint64_t DyldLoadCommandsAtom<A>::getSize() const
3879 {
3880 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
3881 }
3882
3883 template <typename A>
3884 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3885 {
3886 uint64_t size = this->getSize();
3887 bzero(buffer, size);
3888 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
3889 if ( fWriter.fOptions.outputKind() == Options::kDyld )
3890 cmd->set_cmd(LC_ID_DYLINKER);
3891 else
3892 cmd->set_cmd(LC_LOAD_DYLINKER);
3893 cmd->set_cmdsize(this->getSize());
3894 cmd->set_name_offset();
3895 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
3896 }
3897
3898 template <typename A>
3899 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
3900 {
3901 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
3902 }
3903
3904 template <typename A>
3905 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3906 {
3907 uint64_t size = this->getSize();
3908
3909 bzero(buffer, size);
3910 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
3911 cmd->set_cmd(LC_SUB_CLIENT);
3912 cmd->set_cmdsize(size);
3913 cmd->set_client_offset();
3914 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
3915
3916 }
3917
3918 template <typename A>
3919 uint64_t DylibLoadCommandsAtom<A>::getSize() const
3920 {
3921 const char* path = fInfo.reader->getInstallPath();
3922 if ( fInfo.options.fInstallPathOverride != NULL )
3923 path = fInfo.options.fInstallPathOverride;
3924 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
3925 }
3926
3927 template <typename A>
3928 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3929 {
3930 uint64_t size = this->getSize();
3931 bzero(buffer, size);
3932 const char* path = fInfo.reader->getInstallPath();
3933 if ( fInfo.options.fInstallPathOverride != NULL )
3934 path = fInfo.options.fInstallPathOverride;
3935 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
3936 if ( fInfo.options.fWeakImport )
3937 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
3938 else
3939 cmd->set_cmd(LC_LOAD_DYLIB);
3940 cmd->set_cmdsize(this->getSize());
3941 cmd->set_timestamp(fInfo.reader->getTimestamp());
3942 cmd->set_current_version(fInfo.reader->getCurrentVersion());
3943 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
3944 cmd->set_name_offset();
3945 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
3946 }
3947
3948
3949
3950 template <typename A>
3951 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
3952 {
3953 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
3954 }
3955
3956 template <typename A>
3957 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3958 {
3959 struct timeval currentTime = { 0 , 0 };
3960 gettimeofday(&currentTime, NULL);
3961 time_t timestamp = currentTime.tv_sec;
3962 uint64_t size = this->getSize();
3963 bzero(buffer, size);
3964 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
3965 cmd->set_cmd(LC_ID_DYLIB);
3966 cmd->set_cmdsize(this->getSize());
3967 cmd->set_name_offset();
3968 cmd->set_timestamp(timestamp);
3969 cmd->set_current_version(fWriter.fOptions.currentVersion());
3970 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
3971 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
3972 }
3973
3974
3975 template <typename A>
3976 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3977 {
3978 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
3979 bzero(buffer, sizeof(macho_routines_command<P>));
3980 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
3981 cmd->set_cmd(macho_routines_command<P>::CMD);
3982 cmd->set_cmdsize(this->getSize());
3983 cmd->set_init_address(initAddr);
3984 }
3985
3986
3987 template <typename A>
3988 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
3989 {
3990 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
3991 }
3992
3993 template <typename A>
3994 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
3995 {
3996 uint64_t size = this->getSize();
3997 bzero(buffer, size);
3998 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
3999 cmd->set_cmd(LC_SUB_UMBRELLA);
4000 cmd->set_cmdsize(this->getSize());
4001 cmd->set_sub_umbrella_offset();
4002 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
4003 }
4004
4005 template <typename A>
4006 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
4007 {
4008 if (fEmit) {
4009 uint64_t size = this->getSize();
4010 bzero(buffer, size);
4011 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
4012 cmd->set_cmd(LC_UUID);
4013 cmd->set_cmdsize(this->getSize());
4014 cmd->set_uuid((uint8_t*)fUUID);
4015 }
4016 }
4017
4018 template <typename A>
4019 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
4020 {
4021 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
4022 }
4023
4024 template <typename A>
4025 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4026 {
4027 uint64_t size = this->getSize();
4028 bzero(buffer, size);
4029 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
4030 cmd->set_cmd(LC_SUB_LIBRARY);
4031 cmd->set_cmdsize(this->getSize());
4032 cmd->set_sub_library_offset();
4033 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
4034 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
4035 }
4036
4037 template <typename A>
4038 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
4039 {
4040 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
4041 }
4042
4043 template <typename A>
4044 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4045 {
4046 uint64_t size = this->getSize();
4047 bzero(buffer, size);
4048 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
4049 cmd->set_cmd(LC_SUB_FRAMEWORK);
4050 cmd->set_cmdsize(this->getSize());
4051 cmd->set_umbrella_offset();
4052 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
4053 }
4054
4055 template <>
4056 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
4057 {
4058 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
4059 }
4060
4061 template <>
4062 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
4063 {
4064 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
4065 }
4066
4067 template <>
4068 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
4069 {
4070 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
4071 }
4072
4073
4074 template <>
4075 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4076 {
4077 uint64_t size = this->getSize();
4078 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4079 bzero(buffer, size);
4080 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
4081 cmd->set_cmd(LC_UNIXTHREAD);
4082 cmd->set_cmdsize(size);
4083 cmd->set_flavor(1); // PPC_THREAD_STATE
4084 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
4085 cmd->set_thread_register(0, start);
4086 if ( fWriter.fOptions.hasCustomStack() )
4087 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
4088 }
4089
4090
4091 template <>
4092 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4093 {
4094 uint64_t size = this->getSize();
4095 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4096 bzero(buffer, size);
4097 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
4098 cmd->set_cmd(LC_UNIXTHREAD);
4099 cmd->set_cmdsize(size);
4100 cmd->set_flavor(5); // PPC_THREAD_STATE64
4101 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
4102 cmd->set_thread_register(0, start);
4103 if ( fWriter.fOptions.hasCustomStack() )
4104 cmd->set_thread_register(6, fWriter.fOptions.customStackAddr()); // r1
4105 }
4106
4107 template <>
4108 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
4109 {
4110 uint64_t size = this->getSize();
4111 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4112 bzero(buffer, size);
4113 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
4114 cmd->set_cmd(LC_UNIXTHREAD);
4115 cmd->set_cmdsize(size);
4116 cmd->set_flavor(1); // i386_THREAD_STATE
4117 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
4118 cmd->set_thread_register(10, start);
4119 if ( fWriter.fOptions.hasCustomStack() )
4120 cmd->set_thread_register(15, fWriter.fOptions.customStackAddr()); // uesp
4121 }
4122
4123
4124
4125
4126 template <typename A>
4127 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
4128 {
4129 bzero(buffer, fSize);
4130 }
4131
4132 template <typename A>
4133 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
4134 {
4135 fSize = newSize;
4136 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
4137 if ( fWriter.fLargestAtomSize < newSize )
4138 fWriter.fLargestAtomSize = newSize;
4139 }
4140
4141 template <typename A>
4142 uint64_t LinkEditAtom<A>::getFileOffset() const
4143 {
4144 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
4145 }
4146
4147
4148 template <typename A>
4149 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
4150 {
4151 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
4152 }
4153
4154 template <typename A>
4155 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4156 {
4157 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
4158 }
4159
4160
4161 template <typename A>
4162 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
4163 {
4164 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
4165 }
4166
4167 template <typename A>
4168 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4169 {
4170 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
4171 }
4172
4173
4174
4175 template <typename A>
4176 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
4177 {
4178 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
4179 }
4180
4181 template <typename A>
4182 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4183 {
4184 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
4185 }
4186
4187 template <typename A>
4188 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
4189 {
4190 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
4191 }
4192
4193 template <typename A>
4194 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4195 {
4196 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
4197 }
4198
4199
4200
4201 template <typename A>
4202 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
4203 {
4204 return fTable.size() * sizeof(uint32_t);
4205 }
4206
4207 template <typename A>
4208 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4209 {
4210 uint64_t size = this->getSize();
4211 bzero(buffer, size);
4212 const uint32_t indirectTableSize = fTable.size();
4213 uint32_t* indirectTable = (uint32_t*)buffer;
4214 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
4215 if ( it->indirectIndex < indirectTableSize ) {
4216 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
4217 }
4218 else {
4219 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
4220 }
4221 }
4222 }
4223
4224
4225
4226 template <typename A>
4227 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
4228 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
4229 {
4230 fCurrentBuffer = new char[kBufferSize];
4231 // burn first byte of string pool (so zero is never a valid string offset)
4232 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
4233 // make offset 1 always point to an empty string
4234 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
4235 }
4236
4237 template <typename A>
4238 uint64_t StringsLinkEditAtom<A>::getSize() const
4239 {
4240 return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4241 }
4242
4243 template <typename A>
4244 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4245 {
4246 uint64_t offset = 0;
4247 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
4248 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
4249 offset += kBufferSize;
4250 }
4251 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
4252 }
4253
4254 template <typename A>
4255 int32_t StringsLinkEditAtom<A>::add(const char* name)
4256 {
4257 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4258 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
4259 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
4260 fCurrentBufferUsed += lenNeeded;
4261 }
4262 else {
4263 int copied = kBufferSize-fCurrentBufferUsed-1;
4264 // change trailing '\0' that strlcpy added to real char
4265 fCurrentBuffer[kBufferSize-1] = name[copied];
4266 // alloc next buffer
4267 fFullBuffers.push_back(fCurrentBuffer);
4268 fCurrentBuffer = new char[kBufferSize];
4269 fCurrentBufferUsed = 0;
4270 // append rest of string
4271 this->add(&name[copied+1]);
4272 }
4273 return offset;
4274 }
4275
4276
4277 template <typename A>
4278 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
4279 {
4280 StringToOffset::iterator pos = fUniqueStrings.find(name);
4281 if ( pos != fUniqueStrings.end() ) {
4282 return pos->second;
4283 }
4284 else {
4285 int32_t offset = this->add(name);
4286 fUniqueStrings[name] = offset;
4287 return offset;
4288 }
4289 }
4290
4291
4292 template <typename A>
4293 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
4294 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
4295 {
4296 char* buf = new char[strlen(name)+32];
4297 if ( targetOffset == 0 ) {
4298 if ( islandRegion == 0 )
4299 sprintf(buf, "%s$island", name);
4300 else
4301 sprintf(buf, "%s$island_%d", name, islandRegion);
4302 }
4303 else {
4304 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
4305 }
4306 fName = buf;
4307 }
4308
4309
4310 template <>
4311 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4312 {
4313 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4314 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4315 OSWriteBigInt32(buffer, 0, branchInstruction);
4316 }
4317
4318 template <>
4319 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4320 {
4321 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4322 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4323 OSWriteBigInt32(buffer, 0, branchInstruction);
4324 }
4325
4326 template <>
4327 uint64_t BranchIslandAtom<ppc>::getSize() const
4328 {
4329 return 4;
4330 }
4331
4332 template <>
4333 uint64_t BranchIslandAtom<ppc64>::getSize() const
4334 {
4335 return 4;
4336 }
4337
4338
4339 template <>
4340 bool StubAtom<ppc64>::pic() const
4341 {
4342 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
4343 // This usually only happens when a large zero-page is requested
4344 switch ( fWriter.fOptions.outputKind() ) {
4345 case Options::kDynamicExecutable:
4346 return (fWriter.fOptions.zeroPageSize() > 4096);
4347 case Options::kDynamicLibrary:
4348 case Options::kDynamicBundle:
4349 return true;
4350 case Options::kObjectFile:
4351 case Options::kDyld:
4352 case Options::kStaticExecutable:
4353 break;
4354 }
4355 throw "internal ld64 error: file type does not use stubs";
4356 }
4357
4358 template <>
4359 bool StubAtom<ppc>::pic() const
4360 {
4361 return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
4362 }
4363
4364
4365 template <>
4366 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
4367 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4368 {
4369 writer.fAllSynthesizedStubs.push_back(this);
4370
4371 LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
4372 if ( pic() ) {
4373 // picbase is 8 bytes into atom
4374 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, NULL, 8));
4375 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, NULL, 8));
4376 }
4377 else {
4378 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
4379 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
4380 }
4381 }
4382
4383 template <>
4384 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
4385 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4386 {
4387 writer.fAllSynthesizedStubs.push_back(this);
4388
4389 LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
4390 if ( pic() ) {
4391 // picbase is 8 bytes into atom
4392 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, NULL, 8));
4393 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, NULL, 8));
4394 }
4395 else {
4396 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
4397 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
4398 }
4399 }
4400
4401 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
4402 template <>
4403 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
4404 : WriterAtom<x86>(writer, Segment::fgImportSegment), fName(stubName(target.getName())), fTarget(target)
4405 {
4406 writer.fAllSynthesizedStubs.push_back(this);
4407 }
4408
4409
4410 template <typename A>
4411 const char* StubAtom<A>::stubName(const char* name)
4412 {
4413 char* buf;
4414 asprintf(&buf, "%s$stub", name);
4415 return buf;
4416 }
4417
4418 template <>
4419 uint64_t StubAtom<ppc>::getSize() const
4420 {
4421 return ( pic() ? 32 : 16 );
4422 }
4423
4424 template <>
4425 uint64_t StubAtom<ppc64>::getSize() const
4426 {
4427 return ( pic() ? 32 : 16 );
4428 }
4429
4430 template <>
4431 uint64_t StubAtom<x86>::getSize() const
4432 {
4433 return 5;
4434 }
4435
4436
4437 template <>
4438 uint8_t StubAtom<x86>::getAlignment() const
4439 {
4440 // special case x86 fast stubs to be byte aligned
4441 return 0;
4442 }
4443
4444 template <>
4445 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4446 {
4447 if ( pic() ) {
4448 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
4449 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
4450 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
4451 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
4452 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
4453 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
4454 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
4455 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
4456 }
4457 else {
4458 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
4459 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
4460 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
4461 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
4462 }
4463 }
4464
4465 template <>
4466 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4467 {
4468 if ( pic() ) {
4469 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
4470 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
4471 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
4472 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
4473 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
4474 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
4475 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
4476 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
4477 }
4478 else {
4479 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
4480 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
4481 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
4482 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
4483 }
4484 }
4485
4486 template <>
4487 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
4488 {
4489 buffer[0] = 0xF4;
4490 buffer[1] = 0xF4;
4491 buffer[2] = 0xF4;
4492 buffer[3] = 0xF4;
4493 buffer[4] = 0xF4;
4494 }
4495
4496
4497 template <>
4498 const char* StubAtom<ppc>::getSectionName() const
4499 {
4500 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
4501 }
4502
4503 template <>
4504 const char* StubAtom<ppc64>::getSectionName() const
4505 {
4506 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
4507 }
4508
4509 template <>
4510 const char* StubAtom<x86>::getSectionName() const
4511 {
4512 return "__jump_table";
4513 }
4514
4515
4516
4517
4518
4519 template <typename A>
4520 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
4521 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
4522 {
4523 writer.fAllSynthesizedLazyPointers.push_back(this);
4524
4525 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
4526 }
4527
4528
4529
4530 template <typename A>
4531 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
4532 {
4533 char* buf;
4534 asprintf(&buf, "%s$lazy_pointer", name);
4535 return buf;
4536 }
4537
4538 template <typename A>
4539 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
4540 {
4541 bzero(buffer, getSize());
4542 }
4543
4544
4545 template <typename A>
4546 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
4547 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
4548 {
4549 writer.fAllSynthesizedNonLazyPointers.push_back(this);
4550
4551 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
4552 }
4553
4554 template <typename A>
4555 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
4556 {
4557 char* buf;
4558 asprintf(&buf, "%s$non_lazy_pointer", name);
4559 return buf;
4560 }
4561
4562 template <typename A>
4563 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
4564 {
4565 bzero(buffer, getSize());
4566 }
4567
4568
4569
4570 }; // namespace executable
4571 }; // namespace mach_o
4572
4573
4574 #endif // __EXECUTABLE_MACH_O__