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