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