]> git.saurik.com Git - apple/ld64.git/blob - src/MachOWriterExecutable.hpp
70798a6912f23492d886e7667b4fdd1158a8888a
[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 case x86_64::kPCRel32_1:
1709 case x86_64::kPCRel32_2:
1710 case x86_64::kPCRel32_4:
1711 reloc1.set_r_address(address);
1712 reloc1.set_r_symbolnum(symbolIndex);
1713 reloc1.set_r_pcrel(true);
1714 reloc1.set_r_length(2);
1715 reloc1.set_r_extern(external);
1716 reloc1.set_r_type(X86_64_RELOC_SIGNED);
1717 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1718 return 1;
1719
1720 case x86_64::kPCRel32GOT:
1721 case x86_64::kPCRel32GOTWeakImport:
1722 reloc1.set_r_address(address);
1723 reloc1.set_r_symbolnum(symbolIndex);
1724 reloc1.set_r_pcrel(true);
1725 reloc1.set_r_length(2);
1726 reloc1.set_r_extern(external);
1727 reloc1.set_r_type(X86_64_RELOC_GOT);
1728 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1729 return 1;
1730
1731 case x86_64::kPCRel32GOTLoad:
1732 case x86_64::kPCRel32GOTLoadWeakImport:
1733 reloc1.set_r_address(address);
1734 reloc1.set_r_symbolnum(symbolIndex);
1735 reloc1.set_r_pcrel(true);
1736 reloc1.set_r_length(2);
1737 reloc1.set_r_extern(external);
1738 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
1739 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1740 return 1;
1741 }
1742 return 0;
1743 }
1744
1745 template <>
1746 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1747 {
1748 ObjectFile::Atom& target = ref->getTarget();
1749 bool isExtern = false;
1750 switch ( target.getDefinitionKind() ) {
1751 case ObjectFile::Atom::kRegularDefinition:
1752 isExtern = false;
1753 break;
1754 case ObjectFile::Atom::kWeakDefinition:
1755 case ObjectFile::Atom::kTentativeDefinition:
1756 case ObjectFile::Atom::kExternalDefinition:
1757 case ObjectFile::Atom::kExternalWeakDefinition:
1758 isExtern = shouldExport(target);
1759 break;
1760 }
1761 uint32_t symbolIndex = 0;
1762 if ( isExtern )
1763 symbolIndex = this->symbolIndex(target);
1764 uint32_t sectionNum = target.getSection()->getIndex();
1765 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1766 macho_relocation_info<P> reloc1;
1767 macho_relocation_info<P> reloc2;
1768 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1769 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1770 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
1771
1772 switch ( kind ) {
1773 case x86::kNoFixUp:
1774 case x86::kFollowOn:
1775 return 0;
1776
1777 case x86::kPointer:
1778 case x86::kPointerWeakImport:
1779 case x86::kAbsolute32:
1780 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1781 // use scattered reloc is target offset is non-zero
1782 sreloc1->set_r_scattered(true);
1783 sreloc1->set_r_pcrel(false);
1784 sreloc1->set_r_length(2);
1785 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1786 sreloc1->set_r_address(address);
1787 sreloc1->set_r_value(target.getAddress());
1788 }
1789 else {
1790 reloc1.set_r_address(address);
1791 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1792 reloc1.set_r_pcrel(false);
1793 reloc1.set_r_length(2);
1794 reloc1.set_r_extern(isExtern);
1795 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1796 }
1797 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1798 return 1;
1799
1800 case x86::kPointerDiff:
1801 {
1802 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1803 sreloc1->set_r_scattered(true);
1804 sreloc1->set_r_pcrel(false);
1805 sreloc1->set_r_length(2);
1806 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
1807 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
1808 else
1809 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
1810 sreloc1->set_r_address(address);
1811 sreloc1->set_r_value(target.getAddress());
1812 sreloc2->set_r_scattered(true);
1813 sreloc2->set_r_pcrel(false);
1814 sreloc2->set_r_length(2);
1815 sreloc2->set_r_type(PPC_RELOC_PAIR);
1816 sreloc2->set_r_address(0);
1817 sreloc2->set_r_value(fromAddr);
1818 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1819 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1820 return 2;
1821 }
1822
1823 case x86::kPCRel32WeakImport:
1824 case x86::kPCRel32:
1825 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
1826 // use scattered reloc is target offset is non-zero
1827 sreloc1->set_r_scattered(true);
1828 sreloc1->set_r_pcrel(true);
1829 sreloc1->set_r_length(2);
1830 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1831 sreloc1->set_r_address(address);
1832 sreloc1->set_r_value(target.getAddress());
1833 }
1834 else {
1835 reloc1.set_r_address(address);
1836 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
1837 reloc1.set_r_pcrel(true);
1838 reloc1.set_r_length(2);
1839 reloc1.set_r_extern(isExtern);
1840 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1841 }
1842 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1843 return 1;
1844
1845 }
1846 return 0;
1847 }
1848
1849
1850
1851 template <>
1852 uint8_t Writer<ppc>::getRelocPointerSize()
1853 {
1854 return 2;
1855 }
1856
1857 template <>
1858 uint8_t Writer<ppc64>::getRelocPointerSize()
1859 {
1860 return 3;
1861 }
1862
1863 template <>
1864 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1865 {
1866 return addObjectRelocs_powerpc(atom, ref);
1867 }
1868
1869 template <>
1870 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1871 {
1872 return addObjectRelocs_powerpc(atom, ref);
1873 }
1874
1875 //
1876 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
1877 // they use a common addObjectRelocs_powerpc() method.
1878 //
1879 template <typename A>
1880 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1881 {
1882 ObjectFile::Atom& target = ref->getTarget();
1883 bool isExtern = false;
1884 switch ( target.getDefinitionKind() ) {
1885 case ObjectFile::Atom::kRegularDefinition:
1886 isExtern = false;
1887 break;
1888 case ObjectFile::Atom::kWeakDefinition:
1889 case ObjectFile::Atom::kTentativeDefinition:
1890 case ObjectFile::Atom::kExternalDefinition:
1891 case ObjectFile::Atom::kExternalWeakDefinition:
1892 isExtern = shouldExport(target);
1893 break;
1894 }
1895
1896 uint32_t symbolIndex = 0;
1897 if ( isExtern )
1898 symbolIndex = this->symbolIndex(target);
1899 uint32_t sectionNum = target.getSection()->getIndex();
1900 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1901 macho_relocation_info<P> reloc1;
1902 macho_relocation_info<P> reloc2;
1903 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1904 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1905 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
1906
1907 switch ( kind ) {
1908 case A::kNoFixUp:
1909 case A::kFollowOn:
1910 return 0;
1911
1912 case A::kPointer:
1913 case A::kPointerWeakImport:
1914 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
1915 // use scattered reloc is target offset is outside target
1916 sreloc1->set_r_scattered(true);
1917 sreloc1->set_r_pcrel(false);
1918 sreloc1->set_r_length(getRelocPointerSize());
1919 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1920 sreloc1->set_r_address(address);
1921 sreloc1->set_r_value(target.getAddress());
1922 }
1923 else {
1924 reloc1.set_r_address(address);
1925 if ( isExtern )
1926 reloc1.set_r_symbolnum(symbolIndex);
1927 else
1928 reloc1.set_r_symbolnum(sectionNum);
1929 reloc1.set_r_pcrel(false);
1930 reloc1.set_r_length(getRelocPointerSize());
1931 reloc1.set_r_extern(isExtern);
1932 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1933 }
1934 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1935 return 1;
1936
1937 case A::kPointerDiff32:
1938 case A::kPointerDiff64:
1939 {
1940 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
1941 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1942 sreloc1->set_r_scattered(true);
1943 sreloc1->set_r_pcrel(false);
1944 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1945 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
1946 sreloc1->set_r_address(address);
1947 sreloc1->set_r_value(toAddr);
1948 sreloc2->set_r_scattered(true);
1949 sreloc2->set_r_pcrel(false);
1950 sreloc2->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
1951 sreloc2->set_r_type(PPC_RELOC_PAIR);
1952 sreloc2->set_r_address(0);
1953 sreloc2->set_r_value(fromAddr);
1954 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
1955 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1956 return 2;
1957 }
1958
1959 case A::kBranch24WeakImport:
1960 case A::kBranch24:
1961 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1962 reloc1.set_r_address(address);
1963 if ( isExtern )
1964 reloc1.set_r_symbolnum(symbolIndex);
1965 else
1966 reloc1.set_r_symbolnum(sectionNum);
1967 reloc1.set_r_pcrel(true);
1968 reloc1.set_r_length(2);
1969 reloc1.set_r_type(PPC_RELOC_BR24);
1970 reloc1.set_r_extern(isExtern);
1971 }
1972 else {
1973 sreloc1->set_r_scattered(true);
1974 sreloc1->set_r_pcrel(true);
1975 sreloc1->set_r_length(2);
1976 sreloc1->set_r_type(PPC_RELOC_BR24);
1977 sreloc1->set_r_address(address);
1978 sreloc1->set_r_value(target.getAddress());
1979 }
1980 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
1981 return 1;
1982
1983 case A::kBranch14:
1984 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1985 reloc1.set_r_address(address);
1986 if ( isExtern )
1987 reloc1.set_r_symbolnum(symbolIndex);
1988 else
1989 reloc1.set_r_symbolnum(sectionNum);
1990 reloc1.set_r_pcrel(true);
1991 reloc1.set_r_length(2);
1992 reloc1.set_r_type(PPC_RELOC_BR14);
1993 reloc1.set_r_extern(isExtern);
1994 }
1995 else {
1996 sreloc1->set_r_scattered(true);
1997 sreloc1->set_r_pcrel(true);
1998 sreloc1->set_r_length(2);
1999 sreloc1->set_r_type(PPC_RELOC_BR14);
2000 sreloc1->set_r_address(address);
2001 sreloc1->set_r_value(target.getAddress());
2002 }
2003 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2004 return 1;
2005
2006 case A::kPICBaseLow16:
2007 case A::kPICBaseLow14:
2008 {
2009 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2010 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2011 sreloc1->set_r_scattered(true);
2012 sreloc1->set_r_pcrel(false);
2013 sreloc1->set_r_length(2);
2014 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
2015 sreloc1->set_r_address(address);
2016 sreloc1->set_r_value(target.getAddress());
2017 sreloc2->set_r_scattered(true);
2018 sreloc2->set_r_pcrel(false);
2019 sreloc2->set_r_length(2);
2020 sreloc2->set_r_type(PPC_RELOC_PAIR);
2021 sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
2022 sreloc2->set_r_value(fromAddr);
2023 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2024 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2025 return 2;
2026 }
2027
2028 case A::kPICBaseHigh16:
2029 {
2030 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2031 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2032 sreloc1->set_r_scattered(true);
2033 sreloc1->set_r_pcrel(false);
2034 sreloc1->set_r_length(2);
2035 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
2036 sreloc1->set_r_address(address);
2037 sreloc1->set_r_value(target.getAddress());
2038 sreloc2->set_r_scattered(true);
2039 sreloc2->set_r_pcrel(false);
2040 sreloc2->set_r_length(2);
2041 sreloc2->set_r_type(PPC_RELOC_PAIR);
2042 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
2043 sreloc2->set_r_value(fromAddr);
2044 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2045 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2046 return 2;
2047 }
2048
2049 case A::kAbsLow14:
2050 case A::kAbsLow16:
2051 {
2052 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2053 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2054 reloc1.set_r_address(address);
2055 if ( isExtern )
2056 reloc1.set_r_symbolnum(symbolIndex);
2057 else
2058 reloc1.set_r_symbolnum(sectionNum);
2059 reloc1.set_r_pcrel(false);
2060 reloc1.set_r_length(2);
2061 reloc1.set_r_extern(isExtern);
2062 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2063 }
2064 else {
2065 sreloc1->set_r_scattered(true);
2066 sreloc1->set_r_pcrel(false);
2067 sreloc1->set_r_length(2);
2068 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2069 sreloc1->set_r_address(address);
2070 sreloc1->set_r_value(target.getAddress());
2071 }
2072 if ( isExtern )
2073 reloc2.set_r_address(ref->getTargetOffset() >> 16);
2074 else
2075 reloc2.set_r_address(toAddr >> 16);
2076 reloc2.set_r_symbolnum(0);
2077 reloc2.set_r_pcrel(false);
2078 reloc2.set_r_length(2);
2079 reloc2.set_r_extern(false);
2080 reloc2.set_r_type(PPC_RELOC_PAIR);
2081 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2082 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2083 return 2;
2084 }
2085
2086 case A::kAbsHigh16:
2087 {
2088 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2089 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2090 reloc1.set_r_address(address);
2091 if ( isExtern )
2092 reloc1.set_r_symbolnum(symbolIndex);
2093 else
2094 reloc1.set_r_symbolnum(sectionNum);
2095 reloc1.set_r_pcrel(false);
2096 reloc1.set_r_length(2);
2097 reloc1.set_r_extern(isExtern);
2098 reloc1.set_r_type(PPC_RELOC_HI16);
2099 }
2100 else {
2101 sreloc1->set_r_scattered(true);
2102 sreloc1->set_r_pcrel(false);
2103 sreloc1->set_r_length(2);
2104 sreloc1->set_r_type(PPC_RELOC_HI16);
2105 sreloc1->set_r_address(address);
2106 sreloc1->set_r_value(target.getAddress());
2107 }
2108 if ( isExtern )
2109 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2110 else
2111 reloc2.set_r_address(toAddr & 0xFFFF);
2112 reloc2.set_r_symbolnum(0);
2113 reloc2.set_r_pcrel(false);
2114 reloc2.set_r_length(2);
2115 reloc2.set_r_extern(false);
2116 reloc2.set_r_type(PPC_RELOC_PAIR);
2117 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2118 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2119 return 2;
2120 }
2121
2122 case A::kAbsHigh16AddLow:
2123 {
2124 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2125 uint32_t overflow = 0;
2126 if ( (toAddr & 0x00008000) != 0 )
2127 overflow = 0x10000;
2128 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2129 reloc1.set_r_address(address);
2130 if ( isExtern )
2131 reloc1.set_r_symbolnum(symbolIndex);
2132 else
2133 reloc1.set_r_symbolnum(sectionNum);
2134 reloc1.set_r_pcrel(false);
2135 reloc1.set_r_length(2);
2136 reloc1.set_r_extern(isExtern);
2137 reloc1.set_r_type(PPC_RELOC_HA16);
2138 }
2139 else {
2140 sreloc1->set_r_scattered(true);
2141 sreloc1->set_r_pcrel(false);
2142 sreloc1->set_r_length(2);
2143 sreloc1->set_r_type(PPC_RELOC_HA16);
2144 sreloc1->set_r_address(address);
2145 sreloc1->set_r_value(target.getAddress());
2146 }
2147 if ( isExtern )
2148 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2149 else
2150 reloc2.set_r_address(toAddr & 0xFFFF);
2151 reloc2.set_r_symbolnum(0);
2152 reloc2.set_r_pcrel(false);
2153 reloc2.set_r_length(2);
2154 reloc2.set_r_extern(false);
2155 reloc2.set_r_type(PPC_RELOC_PAIR);
2156 fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
2157 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2158 return 2;
2159 }
2160
2161 }
2162 return 0;
2163 }
2164
2165
2166 template <typename A>
2167 void Writer<A>::buildObjectFileFixups()
2168 {
2169 uint32_t relocIndex = 0;
2170 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2171 const int segCount = segmentInfos.size();
2172 for(int i=0; i < segCount; ++i) {
2173 SegmentInfo* curSegment = segmentInfos[i];
2174 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2175 const int sectionCount = sectionInfos.size();
2176 for(int j=0; j < sectionCount; ++j) {
2177 SectionInfo* curSection = sectionInfos[j];
2178 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
2179 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2180 if ( ! curSection->fAllZeroFill ) {
2181 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
2182 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2183 curSection->fRelocOffset = relocIndex;
2184 const int atomCount = sectionAtoms.size();
2185 for (int k=0; k < atomCount; ++k) {
2186 ObjectFile::Atom* atom = sectionAtoms[k];
2187 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
2188 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2189 const int refCount = refs.size();
2190 for (int l=0; l < refCount; ++l) {
2191 ObjectFile::Reference* ref = refs[l];
2192 if ( ref->getKind() == A::kFollowOn )
2193 fSeenFollowOnReferences = true;
2194 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
2195 uint32_t offsetInSection = atom->getSectionOffset();
2196 uint32_t indexInSection = offsetInSection / atom->getSize();
2197 uint32_t undefinedSymbolIndex;
2198 if ( curSection->fAllStubs ) {
2199 ObjectFile::Atom& stubTarget =ref->getTarget();
2200 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
2201 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
2202 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
2203 }
2204 else {
2205 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table
2206 if ( curSection->fAllNonLazyPointers && (ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) )
2207 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2208 else
2209 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
2210 }
2211 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2212 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2213 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
2214 fIndirectTableAtom->fTable.push_back(entry);
2215 if ( curSection->fAllLazyPointers ) {
2216 ObjectFile::Atom& target = ref->getTarget();
2217 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2218 if ( &fromTarget == NULL ) {
2219 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
2220 }
2221 else {
2222 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
2223 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
2224 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
2225 macho_relocation_info<P> reloc1;
2226 reloc1.set_r_address(atom->getSectionOffset());
2227 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
2228 reloc1.set_r_pcrel(false);
2229 reloc1.set_r_length();
2230 reloc1.set_r_extern(isExtern);
2231 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2232 fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
2233 ++relocIndex;
2234 }
2235 }
2236 else if ( curSection->fAllStubs ) {
2237 relocIndex += this->addObjectRelocs(atom, ref);
2238 }
2239 }
2240 else if ( ref->getKind() != A::kNoFixUp ) {
2241 relocIndex += this->addObjectRelocs(atom, ref);
2242 }
2243 }
2244 }
2245 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
2246 }
2247 }
2248 }
2249
2250 // now reverse reloc entries
2251 for(int i=0; i < segCount; ++i) {
2252 SegmentInfo* curSegment = segmentInfos[i];
2253 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2254 const int sectionCount = sectionInfos.size();
2255 for(int j=0; j < sectionCount; ++j) {
2256 SectionInfo* curSection = sectionInfos[j];
2257 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
2258 }
2259 }
2260
2261 }
2262
2263 template <>
2264 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2265 {
2266 switch ( ref.getKind() ) {
2267 case ppc::kAbsLow16:
2268 case ppc::kAbsLow14:
2269 case ppc::kAbsHigh16:
2270 case ppc::kAbsHigh16AddLow:
2271 if ( slideable )
2272 return true;
2273 }
2274 return false;
2275 }
2276
2277
2278 template <>
2279 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2280 {
2281 switch ( ref.getKind() ) {
2282 case ppc::kAbsLow16:
2283 case ppc::kAbsLow14:
2284 case ppc::kAbsHigh16:
2285 case ppc::kAbsHigh16AddLow:
2286 if ( slideable )
2287 return true;
2288 }
2289 return false;
2290 }
2291
2292 template <>
2293 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2294 {
2295 if ( ref.getKind() == x86::kAbsolute32 ) {
2296 switch ( ref.getTarget().getDefinitionKind() ) {
2297 case ObjectFile::Atom::kTentativeDefinition:
2298 case ObjectFile::Atom::kRegularDefinition:
2299 // illegal in dylibs/bundles, until we support TEXT relocs
2300 return slideable;
2301 case ObjectFile::Atom::kWeakDefinition:
2302 // illegal if an exported weak symbol, until we support TEXT relocs
2303 return this->shouldExport(ref.getTarget());
2304 case ObjectFile::Atom::kExternalDefinition:
2305 case ObjectFile::Atom::kExternalWeakDefinition:
2306 // illegal until we support TEXT relocs
2307 return true;
2308 }
2309 }
2310 return false;
2311 }
2312
2313 template <>
2314 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
2315 {
2316 return false;
2317 }
2318
2319
2320 template <typename A>
2321 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
2322 {
2323 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2324
2325 switch ( target.getDefinitionKind() ) {
2326 case ObjectFile::Atom::kTentativeDefinition:
2327 case ObjectFile::Atom::kRegularDefinition:
2328 // for flat-namespace or interposable two-level-namespace
2329 // all references to exported symbols get indirected
2330 if ( this->shouldExport(target) &&
2331 ((fOptions.nameSpace() == Options::kFlatNameSpace)
2332 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
2333 || fOptions.interposable()) )
2334 return kRelocExternal;
2335 else if ( slideable )
2336 return kRelocInternal;
2337 else
2338 return kRelocNone;
2339 case ObjectFile::Atom::kWeakDefinition:
2340 // all calls to global weak definitions get indirected
2341 if ( this->shouldExport(target) )
2342 return kRelocExternal;
2343 else if ( slideable )
2344 return kRelocInternal;
2345 else
2346 return kRelocNone;
2347 case ObjectFile::Atom::kExternalDefinition:
2348 case ObjectFile::Atom::kExternalWeakDefinition:
2349 return kRelocExternal;
2350 }
2351 return kRelocNone;
2352 }
2353
2354 template <typename A>
2355 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
2356 {
2357 // for 32-bit architectures, the r_address field in relocs
2358 // for final linked images is the offset from the base address
2359 uint64_t result = address - fOptions.baseAddress();
2360 if ( result > 0x7FFFFFFF ) {
2361 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
2362 atom->getDisplayName(), atom->getFile()->getPath());
2363 }
2364 return result;
2365 }
2366
2367 template <>
2368 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
2369 {
2370 // for x86_64, the r_address field in relocs for final linked images
2371 // is the offset from the start address of the first writable segment
2372 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
2373 if ( result > 0xFFFFFFFF ) {
2374 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
2375 atom->getDisplayName(), atom->getFile()->getPath());
2376 }
2377 return result;
2378 }
2379
2380 template <>
2381 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
2382 {
2383 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
2384 // the 10.5 dyld, iterprets the r_address as:
2385 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
2386 // 2) an offset from the base address of the first writable segment
2387 // For dyld, r_address is always the offset from the base address
2388 uint64_t result;
2389 bool badFor10_4 = false;
2390 if ( fWritableSegmentPastFirst4GB ) {
2391 if ( fOptions.macosxVersionMin() < Options::k10_5 )
2392 badFor10_4 = true;
2393 result = address - fFirstWritableSegment->fBaseAddress;
2394 if ( result > 0xFFFFFFFF ) {
2395 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
2396 atom->getDisplayName(), atom->getFile()->getPath());
2397 }
2398 }
2399 else {
2400 result = address - fOptions.baseAddress();
2401 if ( (fOptions.macosxVersionMin() < Options::k10_5) && (result > 0x7FFFFFFF) )
2402 badFor10_4 = true;
2403 }
2404 if ( badFor10_4 ) {
2405 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",
2406 atom->getDisplayName(), atom->getFile()->getPath());
2407 }
2408 return result;
2409 }
2410
2411
2412 template <typename A>
2413 void Writer<A>::buildExecutableFixups()
2414 {
2415 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
2416 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
2417 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2418 const int segCount = segmentInfos.size();
2419 for(int i=0; i < segCount; ++i) {
2420 SegmentInfo* curSegment = segmentInfos[i];
2421 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2422 const int sectionCount = sectionInfos.size();
2423 for(int j=0; j < sectionCount; ++j) {
2424 SectionInfo* curSection = sectionInfos[j];
2425 //fprintf(stderr, "starting section %p\n", curSection->fSectionName);
2426 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2427 if ( ! curSection->fAllZeroFill ) {
2428 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
2429 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
2430 const int atomCount = sectionAtoms.size();
2431 for (int k=0; k < atomCount; ++k) {
2432 ObjectFile::Atom* atom = sectionAtoms[k];
2433 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
2434 const int refCount = refs.size();
2435 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
2436 for (int l=0; l < refCount; ++l) {
2437 ObjectFile::Reference* ref = refs[l];
2438 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
2439 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
2440 if ( atom->getSize() != sizeof(pint_t) ) {
2441 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
2442 }
2443 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
2444 if ( curSection->fAllLazyPointers ) {
2445 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
2446 }
2447 uint32_t offsetInSection = atom->getSectionOffset();
2448 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
2449 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
2450 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
2451 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
2452 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2453 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2454 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
2455 fIndirectTableAtom->fTable.push_back(entry);
2456 if ( slideable && curSection->fAllLazyPointers ) {
2457 // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
2458 macho_relocation_info<P> pblaReloc;
2459 uint32_t sectionNum = 1;
2460 if ( fDyldHelper != NULL )
2461 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
2462 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
2463 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
2464 pblaReloc.set_r_symbolnum(sectionNum);
2465 pblaReloc.set_r_pcrel(false);
2466 pblaReloc.set_r_length();
2467 pblaReloc.set_r_extern(false);
2468 pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
2469 fInternalRelocs.push_back(pblaReloc);
2470 }
2471 }
2472 else if ( ref->getKind() == A::kPointer ) {
2473 if ( slideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
2474 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
2475 atom->getDisplayName(), atom->getFile()->getPath());
2476 }
2477 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
2478 case kRelocNone:
2479 // no reloc needed
2480 break;
2481 case kRelocInternal:
2482 {
2483 macho_relocation_info<P> internalReloc;
2484 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
2485 uint32_t sectionNum = sectInfo->getIndex();
2486 // special case _mh_dylib_header and friends which are not in any real section
2487 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
2488 sectionNum = 1;
2489 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
2490 internalReloc.set_r_symbolnum(sectionNum);
2491 internalReloc.set_r_pcrel(false);
2492 internalReloc.set_r_length();
2493 internalReloc.set_r_extern(false);
2494 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2495 fInternalRelocs.push_back(internalReloc);
2496 }
2497 break;
2498 case kRelocExternal:
2499 {
2500 macho_relocation_info<P> externalReloc;
2501 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
2502 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
2503 externalReloc.set_r_pcrel(false);
2504 externalReloc.set_r_length();
2505 externalReloc.set_r_extern(true);
2506 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
2507 fExternalRelocs.push_back(externalReloc);
2508 }
2509 break;
2510 }
2511 }
2512 else if ( this->illegalRelocInFinalLinkedImage(*ref, slideable) ) {
2513 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
2514 }
2515 }
2516 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
2517 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
2518 uint32_t undefinedSymbolIndex = this->symbolIndex(*stubTarget);
2519 uint32_t offsetInSection = atom->getSectionOffset();
2520 uint32_t indexInSection = offsetInSection / atom->getSize();
2521 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
2522 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
2523 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
2524 fIndirectTableAtom->fTable.push_back(entry);
2525 }
2526 }
2527 }
2528 }
2529 }
2530 }
2531
2532
2533 template <>
2534 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
2535 {
2536 uint32_t ppcNop;
2537 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2538 for (uint32_t p=from; p < to; p += 4)
2539 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2540 }
2541
2542 template <>
2543 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
2544 {
2545 uint32_t ppcNop;
2546 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
2547 for (uint32_t p=from; p < to; p += 4)
2548 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
2549 }
2550
2551 template <>
2552 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
2553 {
2554 uint8_t x86Nop = 0x90;
2555 for (uint32_t p=from; p < to; ++p)
2556 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
2557 }
2558
2559 template <>
2560 void Writer<x86_64>::writeNoOps(uint32_t from, uint32_t to)
2561 {
2562 uint8_t x86Nop = 0x90;
2563 for (uint32_t p=from; p < to; ++p)
2564 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
2565 }
2566
2567 template <typename A>
2568 uint64_t Writer<A>::writeAtoms()
2569 {
2570 uint32_t end = 0;
2571 uint8_t* buffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
2572 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2573 const int segCount = segmentInfos.size();
2574 for(int i=0; i < segCount; ++i) {
2575 SegmentInfo* curSegment = segmentInfos[i];
2576 bool isTextSeg = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
2577 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2578 const int sectionCount = sectionInfos.size();
2579 for(int j=0; j < sectionCount; ++j) {
2580 SectionInfo* curSection = sectionInfos[j];
2581 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
2582 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
2583 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
2584 if ( ! curSection->fAllZeroFill ) {
2585 const int atomCount = sectionAtoms.size();
2586 end = curSection->fFileOffset;
2587 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
2588 for (int k=0; k < atomCount; ++k) {
2589 ObjectFile::Atom* atom = sectionAtoms[k];
2590 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
2591 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) ) {
2592 uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
2593 if ( offset != end ) {
2594 if ( needsNops ) {
2595 // fill gaps with no-ops
2596 writeNoOps(end, offset);
2597 }
2598 else {
2599 // zero fill gaps
2600 if ( (offset-end) == 4 ) {
2601 uint32_t zero = 0;
2602 ::pwrite(fFileDescriptor, &zero, 4, end);
2603 }
2604 else {
2605 uint8_t zero = 0x00;
2606 for (uint32_t p=end; p < offset; ++p)
2607 ::pwrite(fFileDescriptor, &zero, 1, p);
2608 }
2609 }
2610 }
2611 uint64_t atomSize = atom->getSize();
2612 if ( atomSize > fLargestAtomSize ) {
2613 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
2614 atom->getDisplayName(), atomSize, fLargestAtomSize);
2615 }
2616 end = offset+atomSize;
2617 // copy raw bytes
2618 atom->copyRawContent(buffer);
2619 // apply any fix-ups
2620 try {
2621 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2622 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
2623 ObjectFile::Reference* ref = *it;
2624 if ( fOptions.outputKind() == Options::kObjectFile ) {
2625 // doing ld -r
2626 // skip fix-ups for undefined targets
2627 if ( &(ref->getTarget()) != NULL )
2628 this->fixUpReferenceRelocatable(ref, atom, buffer);
2629 }
2630 else {
2631 // producing final linked image
2632 this->fixUpReferenceFinal(ref, atom, buffer);
2633 }
2634 }
2635 }
2636 catch (const char* msg) {
2637 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
2638 }
2639 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
2640 // offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
2641 // write out
2642 ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
2643 }
2644 }
2645 }
2646 }
2647 }
2648 delete [] buffer;
2649 close(fFileDescriptor);
2650 return end;
2651 }
2652
2653
2654 template <>
2655 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2656 {
2657 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2658 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2659 int64_t displacement;
2660 switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
2661 case x86::kNoFixUp:
2662 case x86::kFollowOn:
2663 // do nothing
2664 break;
2665 case x86::kPointerWeakImport:
2666 case x86::kPointer:
2667 {
2668 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
2669 // external realocation ==> pointer contains addend
2670 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2671 }
2672 else {
2673 // pointer contains target address
2674 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2675 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2676 }
2677 }
2678 break;
2679 case x86::kPointerDiff:
2680 LittleEndian::set32(*fixUp,
2681 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2682 break;
2683 case x86::kPCRel32WeakImport:
2684 case x86::kPCRel32:
2685 displacement = 0;
2686 switch ( ref->getTarget().getDefinitionKind() ) {
2687 case ObjectFile::Atom::kRegularDefinition:
2688 case ObjectFile::Atom::kWeakDefinition:
2689 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2690 break;
2691 case ObjectFile::Atom::kExternalDefinition:
2692 case ObjectFile::Atom::kExternalWeakDefinition:
2693 throw "codegen problem, can't use rel32 to external symbol";
2694 case ObjectFile::Atom::kTentativeDefinition:
2695 displacement = 0;
2696 break;
2697 }
2698 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2699 //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());
2700 throw "rel32 out of range";
2701 }
2702 LittleEndian::set32(*fixUp, (int32_t)displacement);
2703 break;
2704 case x86::kAbsolute32:
2705 switch ( ref->getTarget().getDefinitionKind() ) {
2706 case ObjectFile::Atom::kRegularDefinition:
2707 case ObjectFile::Atom::kWeakDefinition:
2708 case ObjectFile::Atom::kTentativeDefinition:
2709 // pointer contains target address
2710 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2711 break;
2712 case ObjectFile::Atom::kExternalDefinition:
2713 case ObjectFile::Atom::kExternalWeakDefinition:
2714 // external realocation ==> pointer contains addend
2715 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2716 break;
2717 }
2718 break;
2719 }
2720 }
2721
2722 template <>
2723 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2724 {
2725 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2726 bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2727 && shouldExport(ref->getTarget()) );
2728 switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
2729 case x86::kNoFixUp:
2730 case x86::kFollowOn:
2731 // do nothing
2732 break;
2733 case x86::kPointer:
2734 case x86::kPointerWeakImport:
2735 case x86::kAbsolute32:
2736 {
2737 if ( isExternal ) {
2738 // external realocation ==> pointer contains addend
2739 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2740 }
2741 else {
2742 // internal relocation
2743 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
2744 // pointer contains target address
2745 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2746 }
2747 else {
2748 // pointer contains addend
2749 LittleEndian::set32(*fixUp, ref->getTargetOffset());
2750 }
2751 }
2752 }
2753 break;
2754 case x86::kPointerDiff:
2755 LittleEndian::set32(*fixUp,
2756 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2757 break;
2758 case x86::kPCRel32:
2759 case x86::kPCRel32WeakImport:
2760 int64_t displacement = 0;
2761 if ( isExternal )
2762 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2763 else
2764 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2765 const int64_t bl_twoGigLimit = 0x7FFFFFFF;
2766 if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) {
2767 //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());
2768 throw "rel32 out of range";
2769 }
2770 LittleEndian::set32(*fixUp, (int32_t)displacement);
2771 break;
2772 }
2773 }
2774
2775 template <>
2776 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2777 {
2778 const int64_t twoGigLimit = 0x7FFFFFFF;
2779 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
2780 int64_t displacement = 0;
2781 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
2782 case x86_64::kNoFixUp:
2783 case x86_64::kFollowOn:
2784 // do nothing
2785 break;
2786 case x86_64::kPointerWeakImport:
2787 case x86_64::kPointer:
2788 {
2789 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
2790 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
2791 // external realocation ==> pointer contains addend
2792 LittleEndian::set64(*fixUp, ref->getTargetOffset());
2793 }
2794 else {
2795 // internal relocation
2796 // pointer contains target address
2797 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
2798 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2799 }
2800 }
2801 break;
2802 case x86_64::kPointerDiff32:
2803 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
2804 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
2805 throw "32-bit pointer difference out of range";
2806 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
2807 break;
2808 case x86_64::kPointerDiff:
2809 LittleEndian::set64(*fixUp,
2810 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
2811 break;
2812 case x86_64::kBranchPCRel32WeakImport:
2813 case x86_64::kBranchPCRel32:
2814 case x86_64::kPCRel32:
2815 case x86_64::kPCRel32_1:
2816 case x86_64::kPCRel32_2:
2817 case x86_64::kPCRel32_4:
2818 case x86_64::kPCRel32GOT:
2819 case x86_64::kPCRel32GOTWeakImport:
2820 case x86_64::kPCRel32GOTLoad:
2821 case x86_64::kPCRel32GOTLoadWeakImport:
2822 switch ( ref->getTarget().getDefinitionKind() ) {
2823 case ObjectFile::Atom::kRegularDefinition:
2824 case ObjectFile::Atom::kWeakDefinition:
2825 case ObjectFile::Atom::kTentativeDefinition:
2826 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2827 break;
2828 case ObjectFile::Atom::kExternalDefinition:
2829 case ObjectFile::Atom::kExternalWeakDefinition:
2830 throw "codegen problem, can't use rel32 to external symbol";
2831 break;
2832 }
2833 switch ( ref->getKind() ) {
2834 case x86_64::kPCRel32_1:
2835 displacement -= 1;
2836 break;
2837 case x86_64::kPCRel32_2:
2838 displacement -= 2;
2839 break;
2840 case x86_64::kPCRel32_4:
2841 displacement -= 4;
2842 break;
2843 }
2844 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
2845 //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());
2846 throw "rel32 out of range";
2847 }
2848 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
2849 break;
2850 }
2851 }
2852
2853 template <>
2854 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2855 {
2856 const int64_t twoGigLimit = 0x7FFFFFFF;
2857 bool external = (ref->getTarget().getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2858 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
2859 int64_t displacement = 0;
2860 int32_t temp32;
2861 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
2862 case x86_64::kNoFixUp:
2863 case x86_64::kFollowOn:
2864 // do nothing
2865 break;
2866 case x86_64::kPointer:
2867 case x86_64::kPointerWeakImport:
2868 {
2869 if ( external ) {
2870 // external realocation ==> pointer contains addend
2871 LittleEndian::set64(*fixUp, ref->getTargetOffset());
2872 }
2873 else {
2874 // internal relocation ==> pointer contains target address
2875 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
2876 }
2877 }
2878 break;
2879 case x86_64::kPointerDiff32:
2880 // addend in content
2881 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
2882 break;
2883 case x86_64::kPointerDiff:
2884 // addend in content
2885 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
2886 break;
2887 case x86_64::kBranchPCRel32:
2888 case x86_64::kBranchPCRel32WeakImport:
2889 case x86_64::kPCRel32:
2890 case x86_64::kPCRel32_1:
2891 case x86_64::kPCRel32_2:
2892 case x86_64::kPCRel32_4:
2893 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
2894 temp32 = ref->getTargetOffset();
2895 if ( external ) {
2896 // extern relocation contains addend
2897 displacement = temp32;
2898 }
2899 else {
2900 // internal relocations contain delta to target address
2901 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
2902 }
2903 switch ( ref->getKind() ) {
2904 case x86_64::kPCRel32_1:
2905 displacement -= 1;
2906 break;
2907 case x86_64::kPCRel32_2:
2908 displacement -= 2;
2909 break;
2910 case x86_64::kPCRel32_4:
2911 displacement -= 4;
2912 break;
2913 }
2914 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
2915 //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());
2916 throw "rel32 out of range";
2917 }
2918 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
2919 break;
2920 case x86_64::kPCRel32GOT:
2921 case x86_64::kPCRel32GOTLoad:
2922 case x86_64::kPCRel32GOTWeakImport:
2923 case x86_64::kPCRel32GOTLoadWeakImport:
2924 // contains addend (usually zero)
2925 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
2926 break;
2927 }
2928 }
2929
2930 template <>
2931 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2932 {
2933 fixUpReference_powerpc(ref, inAtom, buffer, true);
2934 }
2935
2936 template <>
2937 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2938 {
2939 fixUpReference_powerpc(ref, inAtom, buffer, true);
2940 }
2941
2942 template <>
2943 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2944 {
2945 fixUpReference_powerpc(ref, inAtom, buffer, false);
2946 }
2947
2948 template <>
2949 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
2950 {
2951 fixUpReference_powerpc(ref, inAtom, buffer, false);
2952 }
2953
2954 //
2955 // ppc and ppc64 are mostly the same, so they share a template specialzation
2956 //
2957 template <typename A>
2958 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
2959 {
2960 uint32_t instruction;
2961 uint32_t newInstruction;
2962 int64_t displacement;
2963 uint64_t targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
2964 uint64_t picBaseAddr;
2965 uint16_t instructionLowHalf;
2966 uint16_t instructionHighHalf;
2967 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
2968 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
2969 bool relocateableExternal;
2970
2971 if ( finalLinkedImage )
2972 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
2973 else
2974 relocateableExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
2975 && shouldExport(ref->getTarget()) );
2976
2977 const int64_t picbase_twoGigLimit = 0x80000000;
2978
2979 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
2980 case A::kNoFixUp:
2981 case A::kFollowOn:
2982 // do nothing
2983 break;
2984 case A::kPointerWeakImport:
2985 case A::kPointer:
2986 {
2987 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
2988 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
2989 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
2990 if ( fDyldHelper == NULL )
2991 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2992 P::setP(*fixUpPointer, fDyldHelper->getAddress());
2993 }
2994 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
2995 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
2996 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
2997 P::setP(*fixUpPointer, targetAddr);
2998 else
2999 P::setP(*fixUpPointer, 0);
3000 }
3001 else if ( relocateableExternal ) {
3002 // external realocation ==> pointer contains addend
3003 P::setP(*fixUpPointer, ref->getTargetOffset());
3004 }
3005 else {
3006 // internal relocation
3007 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
3008 // pointer contains target address
3009 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
3010 P::setP(*fixUpPointer, targetAddr);
3011 }
3012 else {
3013 // pointer contains addend
3014 P::setP(*fixUpPointer, ref->getTargetOffset());
3015 }
3016 }
3017 }
3018 break;
3019 case A::kPointerDiff64:
3020 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
3021 break;
3022 case A::kPointerDiff32:
3023 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
3024 break;
3025 case A::kBranch24WeakImport:
3026 case A::kBranch24:
3027 {
3028 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
3029 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
3030 if ( relocateableExternal ) {
3031 // doing "ld -r" to an external symbol
3032 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
3033 displacement -= ref->getTarget().getAddress();
3034 }
3035 else {
3036 const int64_t bl_eightMegLimit = 0x00FFFFFF;
3037 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
3038 //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());
3039 throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s",
3040 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
3041 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
3042 }
3043 }
3044 instruction = BigEndian::get32(*fixUp);
3045 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
3046 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
3047 BigEndian::set32(*fixUp, newInstruction);
3048 }
3049 break;
3050 case A::kBranch14:
3051 {
3052 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
3053 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
3054 if ( relocateableExternal ) {
3055 // doing "ld -r" to an external symbol
3056 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
3057 displacement -= ref->getTarget().getAddress();
3058 }
3059 else {
3060 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
3061 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
3062 //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());
3063 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
3064 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
3065 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
3066 }
3067 }
3068 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
3069 instruction = BigEndian::get32(*fixUp);
3070 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
3071 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
3072 BigEndian::set32(*fixUp, newInstruction);
3073 }
3074 break;
3075 case A::kPICBaseLow16:
3076 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
3077 displacement = targetAddr - picBaseAddr;
3078 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
3079 throw "32-bit pic-base out of range";
3080 instructionLowHalf = (displacement & 0xFFFF);
3081 instruction = BigEndian::get32(*fixUp);
3082 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
3083 BigEndian::set32(*fixUp, newInstruction);
3084 break;
3085 case A::kPICBaseLow14:
3086 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
3087 displacement = targetAddr - picBaseAddr;
3088 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
3089 throw "32-bit pic-base out of range";
3090 if ( (displacement & 0x3) != 0 )
3091 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
3092 instructionLowHalf = (displacement & 0xFFFC);
3093 instruction = BigEndian::get32(*fixUp);
3094 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
3095 BigEndian::set32(*fixUp, newInstruction);
3096 break;
3097 case A::kPICBaseHigh16:
3098 picBaseAddr = inAtom->getAddress() + ref->getFromTargetOffset();
3099 displacement = targetAddr - picBaseAddr;
3100 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
3101 throw "32-bit pic-base out of range";
3102 instructionLowHalf = displacement >> 16;
3103 if ( (displacement & 0x00008000) != 0 )
3104 ++instructionLowHalf;
3105 instruction = BigEndian::get32(*fixUp);
3106 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
3107 BigEndian::set32(*fixUp, newInstruction);
3108 break;
3109 case A::kAbsLow16:
3110 if ( relocateableExternal )
3111 targetAddr -= ref->getTarget().getAddress();
3112 instructionLowHalf = (targetAddr & 0xFFFF);
3113 instruction = BigEndian::get32(*fixUp);
3114 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
3115 BigEndian::set32(*fixUp, newInstruction);
3116 break;
3117 case A::kAbsLow14:
3118 if ( relocateableExternal )
3119 targetAddr -= ref->getTarget().getAddress();
3120 if ( (targetAddr & 0x3) != 0 )
3121 throw "bad address for absolute lo14 instruction fix-up";
3122 instructionLowHalf = (targetAddr & 0xFFFF);
3123 instruction = BigEndian::get32(*fixUp);
3124 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
3125 BigEndian::set32(*fixUp, newInstruction);
3126 break;
3127 case A::kAbsHigh16:
3128 if ( relocateableExternal )
3129 targetAddr -= ref->getTarget().getAddress();
3130 instructionHighHalf = (targetAddr >> 16);
3131 instruction = BigEndian::get32(*fixUp);
3132 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
3133 BigEndian::set32(*fixUp, newInstruction);
3134 break;
3135 case A::kAbsHigh16AddLow:
3136 if ( relocateableExternal )
3137 targetAddr -= ref->getTarget().getAddress();
3138 if ( targetAddr & 0x00008000 )
3139 targetAddr += 0x00010000;
3140 instruction = BigEndian::get32(*fixUp);
3141 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
3142 BigEndian::set32(*fixUp, newInstruction);
3143 break;
3144 }
3145 }
3146
3147 template <>
3148 bool Writer<ppc>::stubableReferenceKind(uint8_t kind)
3149 {
3150 return (kind == ppc::kBranch24 || kind == ppc::kBranch24WeakImport);
3151 }
3152
3153 template <>
3154 bool Writer<ppc64>::stubableReferenceKind(uint8_t kind)
3155 {
3156 return (kind == ppc64::kBranch24 || kind == ppc64::kBranch24WeakImport);
3157 }
3158
3159 template <>
3160 bool Writer<x86>::stubableReferenceKind(uint8_t kind)
3161 {
3162 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
3163 }
3164
3165 template <>
3166 bool Writer<x86_64>::stubableReferenceKind(uint8_t kind)
3167 {
3168 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
3169 }
3170
3171 template <>
3172 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
3173 {
3174 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
3175 }
3176
3177 template <>
3178 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
3179 {
3180 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
3181 }
3182
3183 template <>
3184 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
3185 {
3186 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
3187 }
3188
3189 template <>
3190 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
3191 {
3192 switch ( kind ) {
3193 case x86_64::kPointerWeakImport:
3194 case x86_64::kBranchPCRel32WeakImport:
3195 case x86_64::kPCRel32GOTWeakImport:
3196 case x86_64::kPCRel32GOTLoadWeakImport:
3197 return true;
3198 }
3199 return false;
3200 }
3201
3202
3203 template <>
3204 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
3205 {
3206 return false;
3207 }
3208
3209 template <>
3210 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
3211 {
3212 return false;
3213 }
3214
3215 template <>
3216 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
3217 {
3218 return false;
3219 }
3220
3221 template <>
3222 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
3223 {
3224 switch ( kind ) {
3225 case x86_64::kPCRel32GOT:
3226 case x86_64::kPCRel32GOTWeakImport:
3227 case x86_64::kPCRel32GOTLoad:
3228 case x86_64::kPCRel32GOTLoadWeakImport:
3229 return true;
3230 }
3231 return false;
3232 }
3233
3234 template <typename A>
3235 void Writer<A>::scanForAbsoluteReferences()
3236 {
3237 // do nothing
3238 }
3239
3240 // for ppc64 look for any -mdynamic-no-pic codegen
3241 template <>
3242 void Writer<ppc64>::scanForAbsoluteReferences()
3243 {
3244 // only do this for main executable
3245 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
3246 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3247 ObjectFile::Atom* atom = *it;
3248 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3249 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3250 ObjectFile::Reference* ref = *rit;
3251 switch (ref->getKind()) {
3252 case ppc64::kAbsLow16:
3253 case ppc64::kAbsLow14:
3254 case ppc64::kAbsHigh16:
3255 case ppc64::kAbsHigh16AddLow:
3256 //fprintf(stderr, "found -mdyanmic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
3257 // shrink page-zero and add pad segment to compensate
3258 fPadSegmentInfo = new SegmentInfo();
3259 strcpy(fPadSegmentInfo->fName, "__4BGFILL");
3260 fPageZeroAtom->setSize(0x1000);
3261 return;
3262 }
3263 }
3264 }
3265 }
3266 }
3267
3268
3269 template <typename A>
3270 void Writer<A>::synthesizeStubs()
3271 {
3272 switch ( fOptions.outputKind() ) {
3273 case Options::kStaticExecutable:
3274 case Options::kObjectFile:
3275 // these output kinds never have stubs
3276 return;
3277 case Options::kDyld:
3278 case Options::kDynamicLibrary:
3279 case Options::kDynamicBundle:
3280 case Options::kDynamicExecutable:
3281 // try to synthesize stubs for these
3282 break;
3283 }
3284
3285 // walk every atom and reference
3286 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3287 ObjectFile::Atom* atom = *it;
3288 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3289 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3290 ObjectFile::Reference* ref = *rit;
3291 ObjectFile::Atom& target = ref->getTarget();
3292 // build map of which symbols need weak importing
3293 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3294 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
3295 bool weakImport = this->weakImportReferenceKind(ref->getKind());
3296 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
3297 if ( pos == fWeakImportMap.end() ) {
3298 // target not in fWeakImportMap, so add
3299 fWeakImportMap[&target] = weakImport;
3300 }
3301 else {
3302 // target in fWeakImportMap, check for weakness mismatch
3303 if ( pos->second != weakImport ) {
3304 // found mismatch
3305 switch ( fOptions.weakReferenceMismatchTreatment() ) {
3306 case Options::kWeakReferenceMismatchError:
3307 throwf("mismatching weak references for symbol: %s", target.getName());
3308 case Options::kWeakReferenceMismatchWeak:
3309 pos->second = true;
3310 break;
3311 case Options::kWeakReferenceMismatchNonWeak:
3312 pos->second = false;
3313 break;
3314 }
3315 }
3316 }
3317 }
3318 // create stubs as needed
3319 if ( this->stubableReferenceKind(ref->getKind())
3320 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
3321 ObjectFile::Atom* stub = NULL;
3322 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
3323 if ( pos == fStubsMap.end() ) {
3324 stub = new StubAtom<A>(*this, target);
3325 fStubsMap[&target] = stub;
3326 }
3327 else {
3328 stub = pos->second;
3329 }
3330 // alter reference to use stub instead
3331 ref->setTarget(*stub, 0);
3332 }
3333 // create GOT slots (non-lazy pointers) as needed
3334 else if ( this->GOTReferenceKind(ref->getKind()) ) {
3335 ObjectFile::Atom* nlp = NULL;
3336 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
3337 if ( pos == fGOTMap.end() ) {
3338 nlp = new NonLazyPointerAtom<A>(*this, target);
3339 fGOTMap[&target] = nlp;
3340 }
3341 else {
3342 nlp = pos->second;
3343 }
3344 // alter reference to use non lazy pointer instead
3345 ref->setTarget(*nlp, ref->getTargetOffset());
3346 }
3347 }
3348 }
3349
3350 // sort stubs
3351
3352 // sort lazy pointers
3353
3354 // add stubs to fAllAtoms
3355 if ( fAllSynthesizedStubs.size() != 0 ) {
3356 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
3357 std::vector<ObjectFile::Atom*> mergedStubs;
3358 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
3359 // when we have stubs and helpers, insert both into fAllAtoms
3360 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
3361 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
3362 stubs = &mergedStubs;
3363 }
3364 ObjectFile::Section* curSection = NULL;
3365 ObjectFile::Atom* prevAtom = NULL;
3366 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3367 ObjectFile::Atom* atom = *it;
3368 ObjectFile::Section* nextSection = atom->getSection();
3369 if ( nextSection != curSection ) {
3370 // HACK HACK for i386 where stubs are not in _TEXT segment
3371 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
3372 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
3373 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
3374 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
3375 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
3376 break;
3377 }
3378 }
3379 else {
3380 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
3381 // found end of __text section, insert stubs here
3382 fAllAtoms->insert(it, stubs->begin(), stubs->end());
3383 break;
3384 }
3385 }
3386 curSection = nextSection;
3387 }
3388 prevAtom = atom;
3389 }
3390 }
3391
3392
3393 // add lazy pointers to fAllAtoms
3394 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
3395 ObjectFile::Section* curSection = NULL;
3396 ObjectFile::Atom* prevAtom = NULL;
3397 bool inserted = false;
3398 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3399 ObjectFile::Atom* atom = *it;
3400 ObjectFile::Section* nextSection = atom->getSection();
3401 if ( nextSection != curSection ) {
3402 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
3403 // found end of __dyld section, insert lazy pointers here
3404 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
3405 inserted = true;
3406 break;
3407 }
3408 curSection = nextSection;
3409 }
3410 prevAtom = atom;
3411 }
3412 if ( !inserted ) {
3413 throw "can't insert lazy pointers, __dyld section not found";
3414 }
3415 }
3416
3417 // add non-lazy pointers to fAllAtoms
3418 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
3419 ObjectFile::Section* curSection = NULL;
3420 ObjectFile::Atom* prevAtom = NULL;
3421 bool inserted = false;
3422 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3423 ObjectFile::Atom* atom = *it;
3424 ObjectFile::Section* nextSection = atom->getSection();
3425 if ( nextSection != curSection ) {
3426 if ( (prevAtom != NULL)
3427 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
3428 || ((fOptions.outputKind() == Options::kDyld) && (strcmp(prevAtom->getSectionName(), "__data") == 0))) ) {
3429 // found end of __dyld section, insert lazy pointers here
3430 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
3431 inserted = true;
3432 break;
3433 }
3434 curSection = nextSection;
3435 }
3436 prevAtom = atom;
3437 }
3438 if ( !inserted ) {
3439 throw "can't insert non-lazy pointers, __dyld section not found";
3440 }
3441 }
3442 }
3443
3444
3445 template <typename A>
3446 void Writer<A>::partitionIntoSections()
3447 {
3448 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
3449
3450 // for every atom, set its sectionInfo object and section offset
3451 // build up fSegmentInfos along the way
3452 ObjectFile::Section* curSection = NULL;
3453 SectionInfo* currentSectionInfo = NULL;
3454 SegmentInfo* currentSegmentInfo = NULL;
3455 unsigned int sectionIndex = 1;
3456 fSegmentInfos.reserve(8);
3457 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
3458 ObjectFile::Atom* atom = (*fAllAtoms)[i];
3459 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
3460 if ( oneSegmentCommand ) {
3461 if ( currentSegmentInfo == NULL ) {
3462 currentSegmentInfo = new SegmentInfo();
3463 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
3464 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
3465 this->fSegmentInfos.push_back(currentSegmentInfo);
3466 }
3467 currentSectionInfo = new SectionInfo();
3468 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
3469 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
3470 currentSectionInfo->fAlignment = atom->getAlignment();
3471 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
3472 currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') ||
3473 (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) && !fOptions.makeTentativeDefinitionsReal() );
3474 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
3475 currentSectionInfo->setIndex(sectionIndex++);
3476 currentSegmentInfo->fSections.push_back(currentSectionInfo);
3477 }
3478 else {
3479 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
3480 currentSegmentInfo = new SegmentInfo();
3481 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
3482 uint32_t initprot = 0;
3483 if ( atom->getSegment().isContentReadable() )
3484 initprot |= VM_PROT_READ;
3485 if ( atom->getSegment().isContentWritable() )
3486 initprot |= VM_PROT_WRITE;
3487 if ( atom->getSegment().isContentExecutable() )
3488 initprot |= VM_PROT_EXECUTE;
3489 currentSegmentInfo->fInitProtection = initprot;
3490 if ( initprot == 0 )
3491 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
3492 else
3493 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
3494 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
3495 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
3496 this->fSegmentInfos.push_back(currentSegmentInfo);
3497 }
3498 currentSectionInfo = new SectionInfo();
3499 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
3500 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
3501 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
3502 currentSectionInfo->fAlignment = atom->getAlignment();
3503 // check for -sectalign override
3504 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
3505 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
3506 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
3507 currentSectionInfo->fAlignment = it->alignment;
3508 }
3509 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
3510 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
3511 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
3512 currentSectionInfo->setIndex(sectionIndex++);
3513 currentSegmentInfo->fSections.push_back(currentSectionInfo);
3514 }
3515 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
3516 fLoadCommandsSection = currentSectionInfo;
3517 fLoadCommandsSegment = currentSegmentInfo;
3518 }
3519 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
3520 currentSectionInfo->fAllLazyPointers = true;
3521 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
3522 currentSectionInfo->fAllLazyPointers = true;
3523 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
3524 currentSectionInfo->fAllNonLazyPointers = true;
3525 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
3526 currentSectionInfo->fAllNonLazyPointers = true;
3527 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
3528 currentSectionInfo->fAllStubs = true;
3529 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
3530 currentSectionInfo->fAllStubs = true;
3531 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
3532 currentSectionInfo->fAllStubs = true;
3533 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
3534 currentSectionInfo->fAllStubs = true;
3535 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) )
3536 currentSectionInfo->fAllSelfModifyingStubs = true;
3537 curSection = atom->getSection();
3538 }
3539 // any non-zero fill atoms make whole section marked not-zero-fill
3540 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
3541 currentSectionInfo->fAllZeroFill = false;
3542 // change section object to be Writer's SectionInfo object
3543 atom->setSection(currentSectionInfo);
3544 // section alignment is that of a contained atom with the greatest alignment
3545 uint8_t atomAlign = atom->getAlignment();
3546 if ( currentSectionInfo->fAlignment < atomAlign )
3547 currentSectionInfo->fAlignment = atomAlign;
3548 // calculate section offset for this atom
3549 uint64_t offset = currentSectionInfo->fSize;
3550 uint64_t alignment = 1 << atomAlign;
3551 offset = ( (offset+alignment-1) & (-alignment) );
3552 atom->setSectionOffset(offset);
3553 uint64_t curAtomSize = atom->getSize();
3554 currentSectionInfo->fSize = offset + curAtomSize;
3555 // add atom to section vector
3556 currentSectionInfo->fAtoms.push_back(atom);
3557 // update largest size
3558 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
3559 fLargestAtomSize = curAtomSize;
3560 }
3561 }
3562
3563
3564 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
3565 class TargetAndOffsetComparor
3566 {
3567 public:
3568 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
3569 {
3570 if ( left.atom != right.atom )
3571 return ( left.atom < right.atom );
3572 return ( left.offset < right.offset );
3573 }
3574 };
3575
3576 template <>
3577 bool Writer<ppc>::addBranchIslands()
3578 {
3579 return this->addPPCBranchIslands();
3580 }
3581
3582 template <>
3583 bool Writer<ppc64>::addBranchIslands()
3584 {
3585 return this->addPPCBranchIslands();
3586 }
3587
3588 template <>
3589 bool Writer<x86>::addBranchIslands()
3590 {
3591 // x86 branches can reach entire 4G address space, so no need for branch islands
3592 return false;
3593 }
3594
3595 template <>
3596 bool Writer<x86_64>::addBranchIslands()
3597 {
3598 // x86 branches can reach entire 4G size of largest image
3599 return false;
3600 }
3601
3602 template <>
3603 inline uint8_t Writer<ppc>::branch24Reference()
3604 {
3605 return ppc::kBranch24;
3606 }
3607
3608 template <>
3609 inline uint8_t Writer<ppc64>::branch24Reference()
3610 {
3611 return ppc64::kBranch24;
3612 }
3613
3614 //
3615 // PowerPC can do PC relative branches as far as +/-16MB.
3616 // If a branch target is >16MB then we insert one or more
3617 // "branch islands" between the branch and its target that
3618 // allows island hoping to the target.
3619 //
3620 // Branch Island Algorithm
3621 //
3622 // If the __TEXT segment < 16MB, then no branch islands needed
3623 // Otherwise, every 15MB into the __TEXT segment is region is
3624 // added which can contain branch islands. Every out of range
3625 // bl instruction is checked. If it crosses a region, an island
3626 // is added to that region with the same target and the bl is
3627 // adjusted to target the island instead.
3628 //
3629 // In theory, if too many islands are added to one region, it
3630 // could grow the __TEXT enough that other previously in-range
3631 // bl branches could be pushed out of range. We reduce the
3632 // probability this could happen by placing the ranges every
3633 // 15MB which means the region would have to be 1MB (256K islands)
3634 // before any branches could be pushed out of range.
3635 //
3636 template <typename A>
3637 bool Writer<A>::addPPCBranchIslands()
3638 {
3639 bool result = false;
3640 // Can only possibly need branch islands if __TEXT segment > 16M
3641 if ( fLoadCommandsSegment->fSize > 16000000 ) {
3642 //fprintf(stderr, "ld64: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
3643 const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
3644 SectionInfo* textSection = NULL;
3645 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
3646 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
3647 textSection = *it;
3648 //fprintf(stderr, "ld64: checking for branch islands, __text section size=%llu\n", textSection->fSize);
3649 break;
3650 }
3651 }
3652 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
3653 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
3654 AtomToIsland regionsMap[kIslandRegionsCount];
3655 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
3656 unsigned int islandCount = 0;
3657
3658 // create islands for branch references that are out of range
3659 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3660 ObjectFile::Atom* atom = *it;
3661 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3662 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3663 ObjectFile::Reference* ref = *rit;
3664 if ( ref->getKind() == this->branch24Reference() ) {
3665 ObjectFile::Atom& target = ref->getTarget();
3666 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
3667 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
3668 int64_t displacement = dstAddr - srcAddr;
3669 const int64_t kFifteenMegLimit = kBetweenRegions;
3670 if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
3671 for (int i=0; i < kIslandRegionsCount; ++i) {
3672 AtomToIsland* region=&regionsMap[i];
3673 int64_t islandRegionAddr = kBetweenRegions * (i+1);
3674 if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
3675 ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
3676 TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
3677 AtomToIsland::iterator pos = region->find(islandTarget);
3678 if ( pos == region->end() ) {
3679 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
3680 island->setSection(textSection);
3681 (*region)[islandTarget] = island;
3682 regionsIslands[i].push_back(island);
3683 ++islandCount;
3684 ref->setTarget(*island, 0);
3685 }
3686 else {
3687 ref->setTarget(*(pos->second), 0);
3688 }
3689 }
3690 }
3691 }
3692 }
3693 }
3694 }
3695
3696 // insert islands into __text section and adjust section offsets
3697 if ( islandCount > 0 ) {
3698 //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
3699 std::vector<ObjectFile::Atom*> newAtomList;
3700 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
3701 uint64_t islandRegionAddr = kBetweenRegions;
3702 int regionIndex = 0;
3703 uint64_t sectionOffset = 0;
3704 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
3705 ObjectFile::Atom* atom = *it;
3706 newAtomList.push_back(atom);
3707 if ( atom->getAddress() > islandRegionAddr ) {
3708 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
3709 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3710 ObjectFile::Atom* islandAtom = *rit;
3711 newAtomList.push_back(islandAtom);
3712 uint64_t alignment = 1 << (islandAtom->getAlignment());
3713 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3714 islandAtom->setSectionOffset(sectionOffset);
3715 sectionOffset += islandAtom->getSize();
3716 }
3717 ++regionIndex;
3718 islandRegionAddr += kBetweenRegions;
3719 }
3720 uint64_t alignment = 1 << (atom->getAlignment());
3721 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3722 atom->setSectionOffset(sectionOffset);
3723 sectionOffset += atom->getSize();
3724 }
3725 // put any remaining islands at end of __text section
3726 if ( regionIndex < kIslandRegionsCount ) {
3727 sectionOffset = textSection->fSize;
3728 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
3729 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
3730 ObjectFile::Atom* islandAtom = *rit;
3731 newAtomList.push_back(islandAtom);
3732 uint64_t alignment = 1 << (islandAtom->getAlignment());
3733 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3734 islandAtom->setSectionOffset(sectionOffset);
3735 sectionOffset += islandAtom->getSize();
3736 }
3737 }
3738
3739 textSection->fAtoms = newAtomList;
3740 textSection->fSize = sectionOffset;
3741 result = true;
3742 }
3743
3744 }
3745 return result;
3746 }
3747
3748
3749 template <typename A>
3750 void Writer<A>::adjustLoadCommandsAndPadding()
3751 {
3752 fSegmentCommands->computeSize();
3753
3754 // recompute load command section offsets
3755 uint64_t offset = 0;
3756 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
3757 const unsigned int atomCount = loadCommandAtoms.size();
3758 for (unsigned int i=0; i < atomCount; ++i) {
3759 ObjectFile::Atom* atom = loadCommandAtoms[i];
3760 uint64_t alignment = 1 << atom->getAlignment();
3761 offset = ( (offset+alignment-1) & (-alignment) );
3762 atom->setSectionOffset(offset);
3763 uint32_t atomSize = atom->getSize();
3764 if ( atomSize > fLargestAtomSize )
3765 fLargestAtomSize = atomSize;
3766 offset += atomSize;
3767 fLoadCommandsSection->fSize = offset;
3768 }
3769
3770 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
3771 const int sectionCount = sectionInfos.size();
3772 uint64_t paddingSize = 0;
3773 if ( fOptions.outputKind() == Options::kDyld ) {
3774 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
3775 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
3776 for(int j=0; j < sectionCount; ++j) {
3777 SectionInfo* curSection = sectionInfos[j];
3778 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
3779 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3780 break;
3781 }
3782 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
3783 }
3784 else if ( fOptions.outputKind() == Options::kObjectFile ) {
3785 // mach-o .o files need no padding between load commands and first section
3786 paddingSize = 0;
3787 }
3788 else {
3789 // calculate max padding to keep segment size same, but all free space at end of load commands
3790 uint64_t totalSize = 0;
3791 uint64_t worstCaseAlignmentPadding = 0;
3792 for(int j=0; j < sectionCount; ++j) {
3793 SectionInfo* curSection = sectionInfos[j];
3794 totalSize += curSection->fSize;
3795 if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
3796 worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
3797 }
3798 uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
3799 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
3800 paddingSize = segmentSize - (totalSize+worstCaseAlignmentPadding);
3801
3802 // if command line requires more padding than this
3803 if ( paddingSize < fOptions.minimumHeaderPad() ) {
3804 int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
3805 paddingSize += extraPages * 4096;
3806 }
3807 }
3808
3809 // adjust atom size and update section size
3810 fHeaderPadding->setSize(paddingSize);
3811 for(int j=0; j < sectionCount; ++j) {
3812 SectionInfo* curSection = sectionInfos[j];
3813 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
3814 curSection->fSize = paddingSize;
3815 }
3816 }
3817
3818 // assign file offsets and logical address to all segments
3819 template <typename A>
3820 void Writer<A>::assignFileOffsets()
3821 {
3822 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
3823 bool haveFixedSegments = false;
3824 uint64_t fileOffset = 0;
3825 uint64_t nextContiguousAddress = fOptions.baseAddress();
3826
3827 // Run through the segments and each segment's sections to assign addresses
3828 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3829 SegmentInfo* curSegment = *segit;
3830
3831 fileOffset = (fileOffset+4095) & (-4096);
3832 curSegment->fFileOffset = fileOffset;
3833
3834 // Set the segment base address
3835 if ( curSegment->fFixedAddress )
3836 haveFixedSegments = true;
3837 else
3838 curSegment->fBaseAddress = nextContiguousAddress;
3839
3840 // We've set the segment address, now run through each section.
3841 uint64_t address = curSegment->fBaseAddress;
3842 SectionInfo* firstZeroFillSection = NULL;
3843 SectionInfo* prevSection = NULL;
3844
3845 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3846
3847 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
3848 SectionInfo* curSection = *it;
3849
3850 // adjust section address based on alignment
3851 uint64_t alignment = 1 << curSection->fAlignment;
3852 address = ( (address+alignment-1) & (-alignment) );
3853
3854 // adjust file offset to match address
3855 if ( prevSection != NULL ) {
3856 if ( finalLinkedImage || !prevSection->fVirtualSection )
3857 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
3858 else
3859 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
3860 }
3861
3862 // update section info
3863 curSection->fFileOffset = fileOffset;
3864 curSection->setBaseAddress(address);
3865
3866 // keep track of trailing zero fill sections
3867 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
3868 firstZeroFillSection = curSection;
3869 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
3870 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
3871
3872 // update running pointers
3873 if ( finalLinkedImage || !curSection->fVirtualSection )
3874 address += curSection->fSize;
3875 fileOffset += curSection->fSize;
3876
3877 // update segment info
3878 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
3879 curSegment->fSize = curSegment->fFileSize;
3880 prevSection = curSection;
3881 }
3882
3883 if ( fOptions.outputKind() == Options::kObjectFile ) {
3884 // don't page align .o files
3885 }
3886 else {
3887 // optimize trailing zero-fill sections to not occupy disk space
3888 if ( firstZeroFillSection != NULL ) {
3889 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
3890 fileOffset = firstZeroFillSection->fFileOffset;
3891 }
3892 // page align segment size
3893 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
3894 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
3895 if ( curSegment->fBaseAddress == nextContiguousAddress )
3896 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
3897 }
3898 }
3899
3900 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
3901 if ( haveFixedSegments ) {
3902 int segCount = fSegmentInfos.size();
3903 for(int i=0; i < segCount; ++i) {
3904 SegmentInfo* segment1 = fSegmentInfos[i];
3905
3906 for(int j=0; j < segCount; ++j) {
3907 if ( i != j ) {
3908 SegmentInfo* segment2 = fSegmentInfos[j];
3909
3910 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
3911 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
3912 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3913 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3914 }
3915 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
3916 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
3917 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3918 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3919 }
3920 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
3921 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
3922 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
3923 }
3924 }
3925 }
3926 }
3927 }
3928
3929 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
3930 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3931 SegmentInfo* curSegment = *segit;
3932 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
3933 if ( fFirstWritableSegment == NULL )
3934 fFirstWritableSegment = curSegment;
3935 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
3936 fWritableSegmentPastFirst4GB = true;
3937 }
3938 }
3939
3940 }
3941
3942 template <typename A>
3943 void Writer<A>::adjustLinkEditSections()
3944 {
3945 // link edit content is always in last segment
3946 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
3947 unsigned int firstLinkEditSectionIndex = 0;
3948 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
3949 ++firstLinkEditSectionIndex;
3950
3951 const unsigned int sectionCount = lastSeg->fSections.size();
3952 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
3953 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
3954 if ( fPadSegmentInfo != NULL ) {
3955 // insert __4GBFILL segment into segments vector before LINKEDIT
3956 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
3957 if ( *it == lastSeg ) {
3958 fSegmentInfos.insert(it, fPadSegmentInfo);
3959 break;
3960 }
3961 }
3962 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
3963 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
3964 fPadSegmentInfo->fBaseAddress = address;
3965 // adjust LINKEDIT to start at zeroPageSize
3966 address = fOptions.zeroPageSize();
3967 lastSeg->fBaseAddress = fOptions.zeroPageSize();
3968 }
3969 for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
3970 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
3971 const unsigned int atomCount = atoms.size();
3972 uint64_t sectionOffset = 0;
3973 lastSeg->fSections[i]->fFileOffset = fileOffset;
3974 lastSeg->fSections[i]->setBaseAddress(address);
3975 for (unsigned int j=0; j < atomCount; ++j) {
3976 ObjectFile::Atom* atom = atoms[j];
3977 uint64_t alignment = 1 << atom->getAlignment();
3978 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
3979 atom->setSectionOffset(sectionOffset);
3980 uint64_t size = atom->getSize();
3981 sectionOffset += size;
3982 if ( size > fLargestAtomSize )
3983 fLargestAtomSize = size;
3984 }
3985 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
3986 lastSeg->fSections[i]->fSize = sectionOffset;
3987 fileOffset += sectionOffset;
3988 address += sectionOffset;
3989 }
3990 if ( fOptions.outputKind() == Options::kObjectFile ) {
3991 //lastSeg->fBaseAddress = 0;
3992 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
3993 //lastSeg->fFileOffset = 0;
3994 //lastSeg->fFileSize =
3995 }
3996 else {
3997 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
3998 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
3999 }
4000 }
4001
4002
4003 template <typename A>
4004 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
4005 {
4006 switch ( fWriter.fOptions.outputKind() ) {
4007 case Options::kDynamicExecutable:
4008 case Options::kStaticExecutable:
4009 return ObjectFile::Atom::scopeGlobal;
4010 case Options::kDynamicLibrary:
4011 case Options::kDynamicBundle:
4012 case Options::kDyld:
4013 case Options::kObjectFile:
4014 return ObjectFile::Atom::scopeLinkageUnit;
4015 }
4016 throw "unknown header type";
4017 }
4018
4019 template <typename A>
4020 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
4021 {
4022 switch ( fWriter.fOptions.outputKind() ) {
4023 case Options::kDynamicExecutable:
4024 case Options::kStaticExecutable:
4025 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
4026 case Options::kDynamicLibrary:
4027 case Options::kDynamicBundle:
4028 case Options::kDyld:
4029 return ObjectFile::Atom::kSymbolTableIn;
4030 case Options::kObjectFile:
4031 return ObjectFile::Atom::kSymbolTableNotIn;
4032 }
4033 throw "unknown header type";
4034 }
4035
4036 template <typename A>
4037 const char* MachHeaderAtom<A>::getName() const
4038 {
4039 switch ( fWriter.fOptions.outputKind() ) {
4040 case Options::kDynamicExecutable:
4041 case Options::kStaticExecutable:
4042 return "__mh_execute_header";
4043 case Options::kDynamicLibrary:
4044 return "__mh_dylib_header";
4045 case Options::kDynamicBundle:
4046 return "__mh_bundle_header";
4047 case Options::kObjectFile:
4048 return NULL;
4049 case Options::kDyld:
4050 return "__mh_dylinker_header";
4051 }
4052 throw "unknown header type";
4053 }
4054
4055 template <typename A>
4056 const char* MachHeaderAtom<A>::getDisplayName() const
4057 {
4058 switch ( fWriter.fOptions.outputKind() ) {
4059 case Options::kDynamicExecutable:
4060 case Options::kStaticExecutable:
4061 case Options::kDynamicLibrary:
4062 case Options::kDynamicBundle:
4063 case Options::kDyld:
4064 return this->getName();
4065 case Options::kObjectFile:
4066 return "mach header";
4067 }
4068 throw "unknown header type";
4069 }
4070
4071 template <typename A>
4072 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
4073 {
4074 // get file type
4075 uint32_t fileType = 0;
4076 switch ( fWriter.fOptions.outputKind() ) {
4077 case Options::kDynamicExecutable:
4078 case Options::kStaticExecutable:
4079 fileType = MH_EXECUTE;
4080 break;
4081 case Options::kDynamicLibrary:
4082 fileType = MH_DYLIB;
4083 break;
4084 case Options::kDynamicBundle:
4085 fileType = MH_BUNDLE;
4086 break;
4087 case Options::kObjectFile:
4088 fileType = MH_OBJECT;
4089 break;
4090 case Options::kDyld:
4091 fileType = MH_DYLINKER;
4092 break;
4093 }
4094
4095 // get flags
4096 uint32_t flags = 0;
4097 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
4098 if ( ! fWriter.fSeenFollowOnReferences )
4099 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
4100 }
4101 else {
4102 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
4103 flags |= MH_NOUNDEFS;
4104 }
4105 else {
4106 flags = MH_DYLDLINK;
4107 if ( fWriter.fOptions.bindAtLoad() )
4108 flags |= MH_BINDATLOAD;
4109 switch ( fWriter.fOptions.nameSpace() ) {
4110 case Options::kTwoLevelNameSpace:
4111 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
4112 break;
4113 case Options::kFlatNameSpace:
4114 break;
4115 case Options::kForceFlatNameSpace:
4116 flags |= MH_FORCE_FLAT;
4117 break;
4118 }
4119 if ( fWriter.fHasWeakExports )
4120 flags |= MH_WEAK_DEFINES;
4121 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
4122 flags |= MH_BINDS_TO_WEAK;
4123 }
4124 if ( fWriter.fOptions.hasExecutableStack() )
4125 flags |= MH_ALLOW_STACK_EXECUTION;
4126 }
4127
4128 // get commands info
4129 uint32_t commandsSize = 0;
4130 uint32_t commandsCount = 0;
4131
4132 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
4133 const unsigned int atomCount = loadCommandAtoms.size();
4134 for (unsigned int i=0; i < atomCount; ++i) {
4135 ObjectFile::Atom* atom = loadCommandAtoms[i];
4136 commandsSize += atom->getSize();
4137 // segment and symbol table atoms can contain more than one load command
4138 if ( atom == fWriter.fSegmentCommands )
4139 commandsCount += fWriter.fSegmentCommands->commandCount();
4140 else if ( atom == fWriter.fSymbolTableCommands )
4141 commandsCount += fWriter.fSymbolTableCommands->commandCount();
4142 else if ( atom->getSize() != 0)
4143 ++commandsCount;
4144 }
4145
4146 // fill out mach_header
4147 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
4148 setHeaderInfo(*mh);
4149 mh->set_filetype(fileType);
4150 mh->set_ncmds(commandsCount);
4151 mh->set_sizeofcmds(commandsSize);
4152 mh->set_flags(flags);
4153 }
4154
4155 template <>
4156 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
4157 {
4158 header.set_magic(MH_MAGIC);
4159 header.set_cputype(CPU_TYPE_POWERPC);
4160 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
4161 }
4162
4163 template <>
4164 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
4165 {
4166 header.set_magic(MH_MAGIC_64);
4167 header.set_cputype(CPU_TYPE_POWERPC64);
4168 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
4169 header.set_reserved(0);
4170 }
4171
4172 template <>
4173 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
4174 {
4175 header.set_magic(MH_MAGIC);
4176 header.set_cputype(CPU_TYPE_I386);
4177 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
4178 }
4179
4180 template <>
4181 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
4182 {
4183 header.set_magic(MH_MAGIC_64);
4184 header.set_cputype(CPU_TYPE_X86_64);
4185 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
4186 }
4187
4188 template <typename A>
4189 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
4190 : WriterAtom<A>(writer, Segment::fgStackSegment)
4191 {
4192 if ( stackGrowsDown() )
4193 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
4194 else
4195 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
4196 }
4197
4198
4199 template <>
4200 bool CustomStackAtom<ppc>::stackGrowsDown()
4201 {
4202 return true;
4203 }
4204
4205 template <>
4206 bool CustomStackAtom<ppc64>::stackGrowsDown()
4207 {
4208 return true;
4209 }
4210
4211 template <>
4212 bool CustomStackAtom<x86>::stackGrowsDown()
4213 {
4214 return true;
4215 }
4216
4217 template <>
4218 bool CustomStackAtom<x86_64>::stackGrowsDown()
4219 {
4220 return true;
4221 }
4222
4223 template <typename A>
4224 void SegmentLoadCommandsAtom<A>::computeSize()
4225 {
4226 uint64_t size = 0;
4227 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
4228 const int segCount = segmentInfos.size();
4229 for(int i=0; i < segCount; ++i) {
4230 size += sizeof(macho_segment_command<P>);
4231 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
4232 const int sectionCount = sectionInfos.size();
4233 for(int j=0; j < sectionCount; ++j) {
4234 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
4235 size += sizeof(macho_section<P>);
4236 }
4237 }
4238 fSize = size;
4239 fCommandCount = segCount;
4240 if ( fWriter.fPadSegmentInfo != NULL ) {
4241 ++fCommandCount;
4242 fSize += sizeof(macho_segment_command<P>);
4243 }
4244 }
4245
4246 template <>
4247 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
4248 {
4249 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
4250 }
4251
4252 template <>
4253 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
4254 {
4255 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
4256 }
4257
4258 template <>
4259 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
4260 {
4261 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
4262 }
4263
4264 template <>
4265 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
4266 {
4267 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
4268 }
4269
4270
4271 template <typename A>
4272 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4273 {
4274 uint64_t size = this->getSize();
4275 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
4276 bzero(buffer, size);
4277 uint8_t* p = buffer;
4278 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
4279 const int segCount = segmentInfos.size();
4280 for(int i=0; i < segCount; ++i) {
4281 SegmentInfo* segInfo = segmentInfos[i];
4282 const int sectionCount = segInfo->fSections.size();
4283 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
4284 cmd->set_cmd(macho_segment_command<P>::CMD);
4285 cmd->set_segname(segInfo->fName);
4286 cmd->set_vmaddr(segInfo->fBaseAddress);
4287 cmd->set_vmsize(segInfo->fSize);
4288 cmd->set_fileoff(segInfo->fFileOffset);
4289 cmd->set_filesize(segInfo->fFileSize);
4290 cmd->set_maxprot(segInfo->fMaxProtection);
4291 cmd->set_initprot(segInfo->fInitProtection);
4292 // add sections array
4293 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
4294 unsigned int sectionsEmitted = 0;
4295 for (int j=0; j < sectionCount; ++j) {
4296 SectionInfo* sectInfo = segInfo->fSections[j];
4297 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
4298 macho_section<P>* sect = &sections[sectionsEmitted++];
4299 if ( oneSegment ) {
4300 // .o file segment does not cover load commands, so recalc at first real section
4301 if ( sectionsEmitted == 1 ) {
4302 cmd->set_vmaddr(sectInfo->getBaseAddress());
4303 cmd->set_fileoff(sectInfo->fFileOffset);
4304 }
4305 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
4306 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
4307 }
4308 sect->set_sectname(sectInfo->fSectionName);
4309 sect->set_segname(sectInfo->fSegmentName);
4310 sect->set_addr(sectInfo->getBaseAddress());
4311 sect->set_size(sectInfo->fSize);
4312 sect->set_offset(sectInfo->fFileOffset);
4313 sect->set_align(sectInfo->fAlignment);
4314 if ( sectInfo->fRelocCount != 0 ) {
4315 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
4316 sect->set_nreloc(sectInfo->fRelocCount);
4317 }
4318 if ( sectInfo->fAllZeroFill ) {
4319 sect->set_flags(S_ZEROFILL);
4320 sect->set_offset(0);
4321 }
4322 else if ( sectInfo->fAllLazyPointers ) {
4323 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
4324 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4325 }
4326 else if ( sectInfo->fAllNonLazyPointers ) {
4327 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
4328 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4329 }
4330 else if ( sectInfo->fAllStubs ) {
4331 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
4332 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4333 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
4334 }
4335 else if ( sectInfo->fAllSelfModifyingStubs ) {
4336 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
4337 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
4338 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
4339 }
4340 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4341 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
4342 }
4343 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4344 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
4345 }
4346 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4347 sect->set_flags(S_COALESCED);
4348 }
4349 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4350 sect->set_flags(S_COALESCED);
4351 }
4352 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4353 sect->set_flags(S_COALESCED);
4354 }
4355 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
4356 sect->set_flags(S_INTERPOSING);
4357 }
4358 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4359 sect->set_flags(S_CSTRING_LITERALS);
4360 }
4361 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4362 sect->set_flags(S_4BYTE_LITERALS);
4363 }
4364 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4365 sect->set_flags(S_8BYTE_LITERALS);
4366 }
4367 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4368 sect->set_flags(S_16BYTE_LITERALS);
4369 }
4370 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
4371 sect->set_flags(S_LITERAL_POINTERS);
4372 }
4373 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
4374 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
4375 }
4376 }
4377 }
4378 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
4379 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
4380 cmd->set_nsects(sectionsEmitted);
4381 }
4382 }
4383
4384
4385 template <typename A>
4386 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
4387 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
4388 {
4389 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
4390 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
4391 writer.fSymbolTableCommands = this;
4392 }
4393
4394 template <typename A>
4395 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
4396 {
4397 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable )
4398 return this->alignedSize(sizeof(macho_symtab_command<P>));
4399 else
4400 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
4401 }
4402
4403 template <typename A>
4404 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4405 {
4406 // build LC_DYSYMTAB command
4407 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
4408 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
4409 symbolTableCmd->set_cmd(LC_SYMTAB);
4410 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
4411 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
4412 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
4413 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
4414 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
4415
4416 // build LC_DYSYMTAB command
4417 if ( fWriter.fOptions.outputKind() != Options::kStaticExecutable ) {
4418 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
4419 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
4420 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
4421 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
4422 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
4423 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
4424 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
4425 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
4426 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
4427 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
4428 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
4429 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
4430 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
4431 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
4432 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
4433 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
4434 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
4435 }
4436 }
4437 }
4438
4439 template <typename A>
4440 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
4441 {
4442 return (fWriter.fOptions.outputKind() == Options::kStaticExecutable) ? 1 : 2;
4443 }
4444
4445 template <typename A>
4446 uint64_t DyldLoadCommandsAtom<A>::getSize() const
4447 {
4448 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
4449 }
4450
4451 template <typename A>
4452 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4453 {
4454 uint64_t size = this->getSize();
4455 bzero(buffer, size);
4456 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
4457 if ( fWriter.fOptions.outputKind() == Options::kDyld )
4458 cmd->set_cmd(LC_ID_DYLINKER);
4459 else
4460 cmd->set_cmd(LC_LOAD_DYLINKER);
4461 cmd->set_cmdsize(this->getSize());
4462 cmd->set_name_offset();
4463 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
4464 }
4465
4466 template <typename A>
4467 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
4468 {
4469 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
4470 }
4471
4472 template <typename A>
4473 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4474 {
4475 uint64_t size = this->getSize();
4476
4477 bzero(buffer, size);
4478 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
4479 cmd->set_cmd(LC_SUB_CLIENT);
4480 cmd->set_cmdsize(size);
4481 cmd->set_client_offset();
4482 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
4483
4484 }
4485
4486 template <typename A>
4487 uint64_t DylibLoadCommandsAtom<A>::getSize() const
4488 {
4489 const char* path = fInfo.reader->getInstallPath();
4490 if ( fInfo.options.fInstallPathOverride != NULL )
4491 path = fInfo.options.fInstallPathOverride;
4492 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
4493 }
4494
4495 template <typename A>
4496 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4497 {
4498 uint64_t size = this->getSize();
4499 bzero(buffer, size);
4500 const char* path = fInfo.reader->getInstallPath();
4501 if ( fInfo.options.fInstallPathOverride != NULL )
4502 path = fInfo.options.fInstallPathOverride;
4503 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
4504 if ( fInfo.options.fWeakImport )
4505 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
4506 else
4507 cmd->set_cmd(LC_LOAD_DYLIB);
4508 cmd->set_cmdsize(this->getSize());
4509 cmd->set_timestamp(fInfo.reader->getTimestamp());
4510 cmd->set_current_version(fInfo.reader->getCurrentVersion());
4511 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
4512 cmd->set_name_offset();
4513 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
4514 }
4515
4516
4517
4518 template <typename A>
4519 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
4520 {
4521 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
4522 }
4523
4524 template <typename A>
4525 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4526 {
4527 struct timeval currentTime = { 0 , 0 };
4528 gettimeofday(&currentTime, NULL);
4529 time_t timestamp = currentTime.tv_sec;
4530 uint64_t size = this->getSize();
4531 bzero(buffer, size);
4532 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
4533 cmd->set_cmd(LC_ID_DYLIB);
4534 cmd->set_cmdsize(this->getSize());
4535 cmd->set_name_offset();
4536 cmd->set_timestamp(timestamp);
4537 cmd->set_current_version(fWriter.fOptions.currentVersion());
4538 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
4539 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
4540 }
4541
4542
4543 template <typename A>
4544 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4545 {
4546 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4547 bzero(buffer, sizeof(macho_routines_command<P>));
4548 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
4549 cmd->set_cmd(macho_routines_command<P>::CMD);
4550 cmd->set_cmdsize(this->getSize());
4551 cmd->set_init_address(initAddr);
4552 }
4553
4554
4555 template <typename A>
4556 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
4557 {
4558 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
4559 }
4560
4561 template <typename A>
4562 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4563 {
4564 uint64_t size = this->getSize();
4565 bzero(buffer, size);
4566 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
4567 cmd->set_cmd(LC_SUB_UMBRELLA);
4568 cmd->set_cmdsize(this->getSize());
4569 cmd->set_sub_umbrella_offset();
4570 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
4571 }
4572
4573 template <typename A>
4574 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
4575 {
4576 if (fEmit) {
4577 uint64_t size = this->getSize();
4578 bzero(buffer, size);
4579 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
4580 cmd->set_cmd(LC_UUID);
4581 cmd->set_cmdsize(this->getSize());
4582 cmd->set_uuid((uint8_t*)fUUID);
4583 }
4584 }
4585
4586 template <typename A>
4587 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
4588 {
4589 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
4590 }
4591
4592 template <typename A>
4593 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4594 {
4595 uint64_t size = this->getSize();
4596 bzero(buffer, size);
4597 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
4598 cmd->set_cmd(LC_SUB_LIBRARY);
4599 cmd->set_cmdsize(this->getSize());
4600 cmd->set_sub_library_offset();
4601 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
4602 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
4603 }
4604
4605 template <typename A>
4606 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
4607 {
4608 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
4609 }
4610
4611 template <typename A>
4612 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
4613 {
4614 uint64_t size = this->getSize();
4615 bzero(buffer, size);
4616 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
4617 cmd->set_cmd(LC_SUB_FRAMEWORK);
4618 cmd->set_cmdsize(this->getSize());
4619 cmd->set_umbrella_offset();
4620 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
4621 }
4622
4623 template <>
4624 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
4625 {
4626 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
4627 }
4628
4629 template <>
4630 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
4631 {
4632 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
4633 }
4634
4635 template <>
4636 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
4637 {
4638 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
4639 }
4640
4641 template <>
4642 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
4643 {
4644 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
4645 }
4646
4647 template <>
4648 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4649 {
4650 uint64_t size = this->getSize();
4651 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4652 bzero(buffer, size);
4653 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
4654 cmd->set_cmd(LC_UNIXTHREAD);
4655 cmd->set_cmdsize(size);
4656 cmd->set_flavor(1); // PPC_THREAD_STATE
4657 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
4658 cmd->set_thread_register(0, start);
4659 if ( fWriter.fOptions.hasCustomStack() )
4660 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
4661 }
4662
4663
4664 template <>
4665 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4666 {
4667 uint64_t size = this->getSize();
4668 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4669 bzero(buffer, size);
4670 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
4671 cmd->set_cmd(LC_UNIXTHREAD);
4672 cmd->set_cmdsize(size);
4673 cmd->set_flavor(5); // PPC_THREAD_STATE64
4674 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
4675 cmd->set_thread_register(0, start);
4676 if ( fWriter.fOptions.hasCustomStack() )
4677 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
4678 }
4679
4680 template <>
4681 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
4682 {
4683 uint64_t size = this->getSize();
4684 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4685 bzero(buffer, size);
4686 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
4687 cmd->set_cmd(LC_UNIXTHREAD);
4688 cmd->set_cmdsize(size);
4689 cmd->set_flavor(1); // i386_THREAD_STATE
4690 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
4691 cmd->set_thread_register(10, start);
4692 if ( fWriter.fOptions.hasCustomStack() )
4693 cmd->set_thread_register(15, fWriter.fOptions.customStackAddr()); // uesp
4694 }
4695
4696
4697 template <>
4698 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
4699 {
4700 uint64_t size = this->getSize();
4701 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
4702 bzero(buffer, size);
4703 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
4704 cmd->set_cmd(LC_UNIXTHREAD);
4705 cmd->set_cmdsize(size);
4706 cmd->set_flavor(x86_THREAD_STATE64);
4707 cmd->set_count(x86_THREAD_STATE64_COUNT);
4708 cmd->set_thread_register(16, start); // rip
4709 if ( fWriter.fOptions.hasCustomStack() )
4710 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
4711 }
4712
4713
4714 template <typename A>
4715 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
4716 {
4717 bzero(buffer, fSize);
4718 }
4719
4720 template <typename A>
4721 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
4722 {
4723 fSize = newSize;
4724 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
4725 if ( fWriter.fLargestAtomSize < newSize )
4726 fWriter.fLargestAtomSize = newSize;
4727 }
4728
4729 template <typename A>
4730 uint64_t LinkEditAtom<A>::getFileOffset() const
4731 {
4732 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
4733 }
4734
4735
4736 template <typename A>
4737 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
4738 {
4739 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
4740 }
4741
4742 template <typename A>
4743 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4744 {
4745 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
4746 }
4747
4748
4749 template <typename A>
4750 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
4751 {
4752 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
4753 }
4754
4755 template <typename A>
4756 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4757 {
4758 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
4759 }
4760
4761
4762
4763 template <typename A>
4764 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
4765 {
4766 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
4767 }
4768
4769 template <typename A>
4770 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4771 {
4772 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
4773 }
4774
4775 template <typename A>
4776 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
4777 {
4778 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
4779 }
4780
4781 template <typename A>
4782 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4783 {
4784 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
4785 }
4786
4787
4788
4789 template <typename A>
4790 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
4791 {
4792 return fTable.size() * sizeof(uint32_t);
4793 }
4794
4795 template <typename A>
4796 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4797 {
4798 uint64_t size = this->getSize();
4799 bzero(buffer, size);
4800 const uint32_t indirectTableSize = fTable.size();
4801 uint32_t* indirectTable = (uint32_t*)buffer;
4802 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
4803 if ( it->indirectIndex < indirectTableSize ) {
4804 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
4805 }
4806 else {
4807 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
4808 }
4809 }
4810 }
4811
4812
4813
4814 template <typename A>
4815 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
4816 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
4817 {
4818 fCurrentBuffer = new char[kBufferSize];
4819 // burn first byte of string pool (so zero is never a valid string offset)
4820 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
4821 // make offset 1 always point to an empty string
4822 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
4823 }
4824
4825 template <typename A>
4826 uint64_t StringsLinkEditAtom<A>::getSize() const
4827 {
4828 return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4829 }
4830
4831 template <typename A>
4832 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
4833 {
4834 uint64_t offset = 0;
4835 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
4836 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
4837 offset += kBufferSize;
4838 }
4839 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
4840 }
4841
4842 template <typename A>
4843 int32_t StringsLinkEditAtom<A>::add(const char* name)
4844 {
4845 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
4846 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
4847 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
4848 fCurrentBufferUsed += lenNeeded;
4849 }
4850 else {
4851 int copied = kBufferSize-fCurrentBufferUsed-1;
4852 // change trailing '\0' that strlcpy added to real char
4853 fCurrentBuffer[kBufferSize-1] = name[copied];
4854 // alloc next buffer
4855 fFullBuffers.push_back(fCurrentBuffer);
4856 fCurrentBuffer = new char[kBufferSize];
4857 fCurrentBufferUsed = 0;
4858 // append rest of string
4859 this->add(&name[copied+1]);
4860 }
4861 return offset;
4862 }
4863
4864
4865 template <typename A>
4866 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
4867 {
4868 StringToOffset::iterator pos = fUniqueStrings.find(name);
4869 if ( pos != fUniqueStrings.end() ) {
4870 return pos->second;
4871 }
4872 else {
4873 int32_t offset = this->add(name);
4874 fUniqueStrings[name] = offset;
4875 return offset;
4876 }
4877 }
4878
4879
4880 template <typename A>
4881 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
4882 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
4883 {
4884 char* buf = new char[strlen(name)+32];
4885 if ( targetOffset == 0 ) {
4886 if ( islandRegion == 0 )
4887 sprintf(buf, "%s$island", name);
4888 else
4889 sprintf(buf, "%s$island_%d", name, islandRegion);
4890 }
4891 else {
4892 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
4893 }
4894 fName = buf;
4895 }
4896
4897
4898 template <>
4899 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
4900 {
4901 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4902 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4903 OSWriteBigInt32(buffer, 0, branchInstruction);
4904 }
4905
4906 template <>
4907 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
4908 {
4909 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
4910 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
4911 OSWriteBigInt32(buffer, 0, branchInstruction);
4912 }
4913
4914 template <>
4915 uint64_t BranchIslandAtom<ppc>::getSize() const
4916 {
4917 return 4;
4918 }
4919
4920 template <>
4921 uint64_t BranchIslandAtom<ppc64>::getSize() const
4922 {
4923 return 4;
4924 }
4925
4926
4927 template <>
4928 bool StubAtom<ppc64>::pic() const
4929 {
4930 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
4931 // This usually only happens when a large zero-page is requested
4932 switch ( fWriter.fOptions.outputKind() ) {
4933 case Options::kDynamicExecutable:
4934 return (fWriter.fPageZeroAtom->getSize() > 4096);
4935 case Options::kDynamicLibrary:
4936 case Options::kDynamicBundle:
4937 return true;
4938 case Options::kObjectFile:
4939 case Options::kDyld:
4940 case Options::kStaticExecutable:
4941 break;
4942 }
4943 throw "internal ld64 error: file type does not use stubs";
4944 }
4945
4946 template <>
4947 bool StubAtom<ppc>::pic() const
4948 {
4949 return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
4950 }
4951
4952
4953 template <>
4954 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
4955 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4956 {
4957 writer.fAllSynthesizedStubs.push_back(this);
4958
4959 LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
4960 if ( pic() ) {
4961 // picbase is 8 bytes into atom
4962 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, NULL, 8));
4963 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, NULL, 8));
4964 }
4965 else {
4966 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
4967 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
4968 }
4969 }
4970
4971 template <>
4972 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
4973 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
4974 {
4975 writer.fAllSynthesizedStubs.push_back(this);
4976
4977 LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
4978 if ( pic() ) {
4979 // picbase is 8 bytes into atom
4980 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, NULL, 8));
4981 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, NULL, 8));
4982 }
4983 else {
4984 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
4985 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
4986 }
4987 }
4988
4989 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
4990 template <>
4991 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
4992 : WriterAtom<x86>(writer, Segment::fgImportSegment), fName(stubName(target.getName())), fTarget(target)
4993 {
4994 writer.fAllSynthesizedStubs.push_back(this);
4995 }
4996
4997 template <>
4998 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
4999 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
5000 {
5001 writer.fAllSynthesizedStubs.push_back(this);
5002
5003 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target);
5004 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
5005 }
5006
5007 template <typename A>
5008 const char* StubAtom<A>::stubName(const char* name)
5009 {
5010 char* buf;
5011 asprintf(&buf, "%s$stub", name);
5012 return buf;
5013 }
5014
5015 template <>
5016 uint64_t StubAtom<ppc>::getSize() const
5017 {
5018 return ( pic() ? 32 : 16 );
5019 }
5020
5021 template <>
5022 uint64_t StubAtom<ppc64>::getSize() const
5023 {
5024 return ( pic() ? 32 : 16 );
5025 }
5026
5027 template <>
5028 uint64_t StubAtom<x86>::getSize() const
5029 {
5030 return 5;
5031 }
5032
5033 template <>
5034 uint64_t StubAtom<x86_64>::getSize() const
5035 {
5036 return 6;
5037 }
5038
5039 template <>
5040 uint8_t StubAtom<x86>::getAlignment() const
5041 {
5042 // special case x86 fast stubs to be byte aligned
5043 return 0;
5044 }
5045
5046 template <>
5047 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
5048 {
5049 if ( pic() ) {
5050 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
5051 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
5052 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
5053 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
5054 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
5055 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
5056 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
5057 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
5058 }
5059 else {
5060 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
5061 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
5062 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
5063 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
5064 }
5065 }
5066
5067 template <>
5068 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
5069 {
5070 if ( pic() ) {
5071 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
5072 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
5073 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
5074 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
5075 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
5076 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
5077 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
5078 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
5079 }
5080 else {
5081 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
5082 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
5083 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
5084 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
5085 }
5086 }
5087
5088 template <>
5089 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
5090 {
5091 buffer[0] = 0xF4;
5092 buffer[1] = 0xF4;
5093 buffer[2] = 0xF4;
5094 buffer[3] = 0xF4;
5095 buffer[4] = 0xF4;
5096 }
5097
5098 template <>
5099 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
5100 {
5101 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
5102 buffer[1] = 0x25;
5103 buffer[2] = 0x00;
5104 buffer[3] = 0x00;
5105 buffer[4] = 0x00;
5106 buffer[5] = 0x00;
5107 }
5108
5109 // x86_64 stubs are 7 bytes and need no alignment
5110 template <>
5111 uint8_t StubAtom<x86_64>::getAlignment() const
5112 {
5113 return 0;
5114 }
5115
5116 template <>
5117 const char* StubAtom<ppc>::getSectionName() const
5118 {
5119 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
5120 }
5121
5122 template <>
5123 const char* StubAtom<ppc64>::getSectionName() const
5124 {
5125 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
5126 }
5127
5128 template <>
5129 const char* StubAtom<x86>::getSectionName() const
5130 {
5131 return "__jump_table";
5132 }
5133
5134
5135
5136 template <>
5137 StubHelperAtom<x86_64>::StubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer)
5138 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
5139 {
5140 writer.fAllSynthesizedStubHelpers.push_back(this);
5141
5142 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &lazyPointer));
5143 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldHelper));
5144 if ( writer.fDyldHelper == NULL )
5145 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
5146 }
5147
5148 template <>
5149 uint64_t StubHelperAtom<x86_64>::getSize() const
5150 {
5151 return 12;
5152 }
5153
5154 template <>
5155 void StubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
5156 {
5157 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
5158 buffer[1] = 0x8D;
5159 buffer[2] = 0x1D;
5160 buffer[3] = 0x00;
5161 buffer[4] = 0x00;
5162 buffer[5] = 0x00;
5163 buffer[6] = 0x00;
5164 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
5165 buffer[8] = 0x00;
5166 buffer[9] = 0x00;
5167 buffer[10] = 0x00;
5168 buffer[11] = 0x00;
5169 }
5170
5171 template <typename A>
5172 const char* StubHelperAtom<A>::stubName(const char* name)
5173 {
5174 char* buf;
5175 asprintf(&buf, "%s$stubHelper", name);
5176 return buf;
5177 }
5178
5179
5180 // specialize lazy pointer for x86_64 to initially pointer to stub helper
5181 template <>
5182 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
5183 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
5184 {
5185 writer.fAllSynthesizedLazyPointers.push_back(this);
5186
5187 StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this);
5188 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
5189 }
5190
5191
5192 template <typename A>
5193 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
5194 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
5195 {
5196 writer.fAllSynthesizedLazyPointers.push_back(this);
5197
5198 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
5199 }
5200
5201
5202
5203 template <typename A>
5204 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
5205 {
5206 char* buf;
5207 asprintf(&buf, "%s$lazy_pointer", name);
5208 return buf;
5209 }
5210
5211 template <typename A>
5212 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
5213 {
5214 bzero(buffer, getSize());
5215 }
5216
5217
5218 template <typename A>
5219 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
5220 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
5221 {
5222 writer.fAllSynthesizedNonLazyPointers.push_back(this);
5223
5224 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
5225 }
5226
5227 template <typename A>
5228 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
5229 {
5230 char* buf;
5231 asprintf(&buf, "%s$non_lazy_pointer", name);
5232 return buf;
5233 }
5234
5235 template <typename A>
5236 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
5237 {
5238 bzero(buffer, getSize());
5239 }
5240
5241
5242
5243 }; // namespace executable
5244 }; // namespace mach_o
5245
5246
5247 #endif // __EXECUTABLE_MACH_O__