]> git.saurik.com Git - apple/ld64.git/blob - src/MachOWriterExecutable.hpp
f983c6c2e80365e94c61207ad6489b19af977ca8
[apple/ld64.git] / src / MachOWriterExecutable.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2008 Apple 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 <uuid/uuid.h>
33 #include <mach/i386/thread_status.h>
34 #include <mach/ppc/thread_status.h>
35 #include <CommonCrypto/CommonDigest.h>
36
37 #include <vector>
38 #include <algorithm>
39 #include <map>
40 #include <set>
41 #include <ext/hash_map>
42
43 #include "ObjectFile.h"
44 #include "ExecutableFile.h"
45 #include "Options.h"
46
47 #include "MachOFileAbstraction.hpp"
48
49
50 //
51 //
52 // To implement architecture xxx, you must write template specializations for the following methods:
53 // MachHeaderAtom<xxx>::setHeaderInfo()
54 // ThreadsLoadCommandsAtom<xxx>::getSize()
55 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
56 // Writer<xxx>::addObjectRelocs()
57 // Writer<xxx>::fixUpReferenceRelocatable()
58 // Writer<xxx>::fixUpReferenceFinal()
59 // Writer<xxx>::stubableReference()
60 // Writer<xxx>::weakImportReferenceKind()
61 // Writer<xxx>::GOTReferenceKind()
62 //
63
64
65 namespace mach_o {
66 namespace executable {
67
68 // forward references
69 template <typename A> class WriterAtom;
70 template <typename A> class PageZeroAtom;
71 template <typename A> class CustomStackAtom;
72 template <typename A> class MachHeaderAtom;
73 template <typename A> class SegmentLoadCommandsAtom;
74 template <typename A> class EncryptionLoadCommandsAtom;
75 template <typename A> class SymbolTableLoadCommandsAtom;
76 template <typename A> class ThreadsLoadCommandsAtom;
77 template <typename A> class DylibIDLoadCommandsAtom;
78 template <typename A> class RoutinesLoadCommandsAtom;
79 template <typename A> class DyldLoadCommandsAtom;
80 template <typename A> class UUIDLoadCommandAtom;
81 template <typename A> class LinkEditAtom;
82 template <typename A> class SectionRelocationsLinkEditAtom;
83 template <typename A> class LocalRelocationsLinkEditAtom;
84 template <typename A> class ExternalRelocationsLinkEditAtom;
85 template <typename A> class SymbolTableLinkEditAtom;
86 template <typename A> class SegmentSplitInfoLoadCommandsAtom;
87 template <typename A> class SegmentSplitInfoContentAtom;
88 template <typename A> class IndirectTableLinkEditAtom;
89 template <typename A> class ModuleInfoLinkEditAtom;
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 template <typename A> class DylibLoadCommandsAtom;
97
98
99 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
100 class SectionInfo : public ObjectFile::Section {
101 public:
102 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0),
103 fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false),
104 fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false),
105 fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(false),
106 fHasTextLocalRelocs(false), fHasTextExternalRelocs(false)
107 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
108 void setIndex(unsigned int index) { fIndex=index; }
109 std::vector<ObjectFile::Atom*> fAtoms;
110 char fSegmentName[20];
111 char fSectionName[20];
112 uint64_t fFileOffset;
113 uint64_t fSize;
114 uint32_t fRelocCount;
115 uint32_t fRelocOffset;
116 uint32_t fIndirectSymbolOffset;
117 uint8_t fAlignment;
118 bool fAllLazyPointers;
119 bool fAllLazyDylibPointers;
120 bool fAllNonLazyPointers;
121 bool fAllStubs;
122 bool fAllSelfModifyingStubs;
123 bool fAllZeroFill;
124 bool fVirtualSection;
125 bool fHasTextLocalRelocs;
126 bool fHasTextExternalRelocs;
127 };
128
129 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
130 class SegmentInfo
131 {
132 public:
133 SegmentInfo() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
134 fBaseAddress(0), fSize(0), fFixedAddress(false),
135 fIndependentAddress(false) { fName[0] = '\0'; }
136 std::vector<class SectionInfo*> fSections;
137 char fName[20];
138 uint32_t fInitProtection;
139 uint32_t fMaxProtection;
140 uint64_t fFileOffset;
141 uint64_t fFileSize;
142 uint64_t fBaseAddress;
143 uint64_t fSize;
144 bool fFixedAddress;
145 bool fIndependentAddress;
146 };
147
148 template <typename A>
149 class Writer : public ExecutableFile::Writer
150 {
151 public:
152 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
153 virtual ~Writer();
154
155 virtual const char* getPath() { return fFilePath; }
156 virtual time_t getModificationTime() { return 0; }
157 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
158 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
159 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
160 virtual std::vector<Stab>* getStabs() { return NULL; }
161
162 virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint,
163 bool objcReplacementClasses);
164 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
165 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
166 std::vector<class ObjectFile::Reader::Stab>& stabs,
167 class ObjectFile::Atom* entryPointAtom,
168 class ObjectFile::Atom* dyldHelperAtom,
169 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
170 bool createUUID, bool canScatter,
171 ObjectFile::Reader::CpuConstraint cpuConstraint,
172 bool biggerThanTwoGigs, bool overridesDylibWeakDefines);
173
174 private:
175 typedef typename A::P P;
176 typedef typename A::P::uint_t pint_t;
177
178 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
179
180 void assignFileOffsets();
181 void synthesizeStubs();
182 void insertDummyStubs();
183 void partitionIntoSections();
184 bool addBranchIslands();
185 bool addPPCBranchIslands();
186 bool isBranch24Reference(uint8_t kind);
187 void adjustLoadCommandsAndPadding();
188 void createDynamicLinkerCommand();
189 void createDylibCommands();
190 void buildLinkEdit();
191 const char* getArchString();
192 void writeMap();
193 uint64_t writeAtoms();
194 void writeNoOps(int fd, uint32_t from, uint32_t to);
195 void copyNoOps(uint8_t* from, uint8_t* to);
196 bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
197 void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
198 void collectExportedAndImportedAndLocalAtoms();
199 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
200 void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
201 void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
202 void buildSymbolTable();
203 const char* symbolTableName(const ObjectFile::Atom* atom);
204 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
205 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
206 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
207 void copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
208 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
209 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
210 bool shouldExport(const ObjectFile::Atom& atom) const;
211 void buildFixups();
212 void adjustLinkEditSections();
213 void buildObjectFileFixups();
214 void buildExecutableFixups();
215 bool preboundLazyPointerType(uint8_t* type);
216 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
217 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
218 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
219 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
220 uint8_t buffer[], bool finalLinkedImage) const;
221 uint32_t symbolIndex(ObjectFile::Atom& atom);
222 bool makesExternalRelocatableReference(ObjectFile::Atom& target) const;
223 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
224 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
225 uint8_t getRelocPointerSize();
226 uint64_t maxAddress();
227 bool stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref);
228 bool GOTReferenceKind(uint8_t kind);
229 bool optimizableGOTReferenceKind(uint8_t kind);
230 bool weakImportReferenceKind(uint8_t kind);
231 unsigned int collectStabs();
232 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
233 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
234 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
235 void addStabs(uint32_t startIndex);
236 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
237 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
238 bool generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
239 bool generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
240 bool mightNeedPadSegment();
241 void scanForAbsoluteReferences();
242 bool needsModuleTable();
243 void optimizeDylibReferences();
244 bool indirectSymbolIsLocal(const ObjectFile::Reference* ref) const;
245
246 struct DirectLibrary {
247 class ObjectFile::Reader* fLibrary;
248 bool fWeak;
249 bool fReExport;
250 };
251
252 friend class WriterAtom<A>;
253 friend class PageZeroAtom<A>;
254 friend class CustomStackAtom<A>;
255 friend class MachHeaderAtom<A>;
256 friend class SegmentLoadCommandsAtom<A>;
257 friend class EncryptionLoadCommandsAtom<A>;
258 friend class SymbolTableLoadCommandsAtom<A>;
259 friend class ThreadsLoadCommandsAtom<A>;
260 friend class DylibIDLoadCommandsAtom<A>;
261 friend class RoutinesLoadCommandsAtom<A>;
262 friend class DyldLoadCommandsAtom<A>;
263 friend class UUIDLoadCommandAtom<A>;
264 friend class LinkEditAtom<A>;
265 friend class SectionRelocationsLinkEditAtom<A>;
266 friend class LocalRelocationsLinkEditAtom<A>;
267 friend class ExternalRelocationsLinkEditAtom<A>;
268 friend class SymbolTableLinkEditAtom<A>;
269 friend class SegmentSplitInfoLoadCommandsAtom<A>;
270 friend class SegmentSplitInfoContentAtom<A>;
271 // friend class IndirectTableLinkEditAtom<A>;
272 friend class ModuleInfoLinkEditAtom<A>;
273 friend class StringsLinkEditAtom<A>;
274 friend class LoadCommandsPaddingAtom<A>;
275 friend class StubAtom<A>;
276 friend class StubHelperAtom<A>;
277 friend class LazyPointerAtom<A>;
278 friend class NonLazyPointerAtom<A>;
279 friend class DylibLoadCommandsAtom<A>;
280
281 const char* fFilePath;
282 Options& fOptions;
283 std::vector<class ObjectFile::Atom*>* fAllAtoms;
284 std::vector<class ObjectFile::Reader::Stab>* fStabs;
285 class SectionInfo* fLoadCommandsSection;
286 class SegmentInfo* fLoadCommandsSegment;
287 class EncryptionLoadCommandsAtom<A>* fEncryptionLoadCommand;
288 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
289 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
290 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
291 class UUIDLoadCommandAtom<A>* fUUIDAtom;
292 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
293 std::vector<SegmentInfo*> fSegmentInfos;
294 class SegmentInfo* fPadSegmentInfo;
295 class ObjectFile::Atom* fEntryPoint;
296 class ObjectFile::Atom* fDyldHelper;
297 class ObjectFile::Atom* fDyldLazyDylibHelper;
298 std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*> fLibraryToLoadCommand;
299 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
300 std::map<class ObjectFile::Reader*, class ObjectFile::Reader*> fLibraryAliases;
301 std::vector<class ObjectFile::Atom*> fExportedAtoms;
302 std::vector<class ObjectFile::Atom*> fImportedAtoms;
303 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
304 std::vector<macho_nlist<P> > fLocalExtraLabels;
305 std::vector<macho_nlist<P> > fGlobalExtraLabels;
306 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
307 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
308 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
309 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
310 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
311 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
312 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
313 class StringsLinkEditAtom<A>* fStringsAtom;
314 class PageZeroAtom<A>* fPageZeroAtom;
315 macho_nlist<P>* fSymbolTable;
316 std::vector<macho_relocation_info<P> > fSectionRelocs;
317 std::vector<macho_relocation_info<P> > fInternalRelocs;
318 std::vector<macho_relocation_info<P> > fExternalRelocs;
319 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
320 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
321 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
322 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
323 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
324 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyDylibPointers;
325 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
326 uint32_t fSymbolTableCount;
327 uint32_t fSymbolTableStabsCount;
328 uint32_t fSymbolTableStabsStartIndex;
329 uint32_t fSymbolTableLocalCount;
330 uint32_t fSymbolTableLocalStartIndex;
331 uint32_t fSymbolTableExportCount;
332 uint32_t fSymbolTableExportStartIndex;
333 uint32_t fSymbolTableImportCount;
334 uint32_t fSymbolTableImportStartIndex;
335 uint32_t fLargestAtomSize;
336 bool fEmitVirtualSections;
337 bool fHasWeakExports;
338 bool fReferencesWeakImports;
339 bool fCanScatter;
340 bool fWritableSegmentPastFirst4GB;
341 bool fNoReExportedDylibs;
342 bool fBiggerThanTwoGigs;
343 bool fSlideable;
344 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
345 std::set<const ObjectFile::Reader*> fDylibReadersWithNonWeakImports;
346 std::set<const ObjectFile::Reader*> fDylibReadersWithWeakImports;
347 SegmentInfo* fFirstWritableSegment;
348 ObjectFile::Reader::CpuConstraint fCpuConstraint;
349 uint32_t fAnonNameIndex;
350 };
351
352
353 class Segment : public ObjectFile::Segment
354 {
355 public:
356 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
357 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
358 virtual const char* getName() const { return fName; }
359 virtual bool isContentReadable() const { return fReadable; }
360 virtual bool isContentWritable() const { return fWritable; }
361 virtual bool isContentExecutable() const { return fExecutable; }
362 virtual bool hasFixedAddress() const { return fFixedAddress; }
363
364 static Segment fgTextSegment;
365 static Segment fgPageZeroSegment;
366 static Segment fgLinkEditSegment;
367 static Segment fgStackSegment;
368 static Segment fgImportSegment;
369 static Segment fgROImportSegment;
370 static Segment fgDataSegment;
371 static Segment fgObjCSegment;
372
373
374 private:
375 const char* fName;
376 const bool fReadable;
377 const bool fWritable;
378 const bool fExecutable;
379 const bool fFixedAddress;
380 };
381
382 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
383 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
384 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
385 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
386 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
387 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
388 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
389 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
390
391
392 template <typename A>
393 class WriterAtom : public ObjectFile::Atom
394 {
395 public:
396 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
397 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
398
399 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
400 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
401 virtual const char* getName() const { return NULL; }
402 virtual const char* getDisplayName() const { return this->getName(); }
403 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
404 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
405 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
406 virtual bool dontDeadStrip() const { return true; }
407 virtual bool isZeroFill() const { return false; }
408 virtual bool isThumb() const { return false; }
409 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
410 virtual bool mustRemainInSection() const { return true; }
411 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
412 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
413 virtual uint32_t getOrdinal() const { return 0; }
414 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
415 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
416 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
417 virtual void setScope(Scope) { }
418
419
420 protected:
421 virtual ~WriterAtom() {}
422 typedef typename A::P P;
423 typedef typename A::P::E E;
424
425 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
426
427 Writer<A>& fWriter;
428 Segment& fSegment;
429 };
430
431 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
432
433
434 template <typename A>
435 class PageZeroAtom : public WriterAtom<A>
436 {
437 public:
438 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
439 fSize(fWriter.fOptions.zeroPageSize()) {}
440 virtual const char* getDisplayName() const { return "page zero content"; }
441 virtual bool isZeroFill() const { return true; }
442 virtual uint64_t getSize() const { return fSize; }
443 virtual const char* getSectionName() const { return "._zeropage"; }
444 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
445 void setSize(uint64_t size) { fSize = size; }
446 private:
447 using WriterAtom<A>::fWriter;
448 typedef typename A::P P;
449 uint64_t fSize;
450 };
451
452
453 template <typename A>
454 class DsoHandleAtom : public WriterAtom<A>
455 {
456 public:
457 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
458 virtual const char* getName() const { return "___dso_handle"; }
459 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
460 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
461 virtual uint64_t getSize() const { return 0; }
462 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
463 virtual const char* getSectionName() const { return "._mach_header"; }
464 virtual void copyRawContent(uint8_t buffer[]) const {}
465 };
466
467
468 template <typename A>
469 class MachHeaderAtom : public WriterAtom<A>
470 {
471 public:
472 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
473 virtual const char* getName() const;
474 virtual const char* getDisplayName() const;
475 virtual ObjectFile::Atom::Scope getScope() const;
476 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
477 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
478 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
479 virtual const char* getSectionName() const { return "._mach_header"; }
480 virtual uint32_t getOrdinal() const { return 1; }
481 virtual void copyRawContent(uint8_t buffer[]) const;
482 private:
483 using WriterAtom<A>::fWriter;
484 typedef typename A::P P;
485 void setHeaderInfo(macho_header<typename A::P>& header) const;
486 };
487
488 template <typename A>
489 class CustomStackAtom : public WriterAtom<A>
490 {
491 public:
492 CustomStackAtom(Writer<A>& writer);
493 virtual const char* getDisplayName() const { return "custom stack content"; }
494 virtual bool isZeroFill() const { return true; }
495 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
496 virtual const char* getSectionName() const { return "._stack"; }
497 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
498 private:
499 using WriterAtom<A>::fWriter;
500 typedef typename A::P P;
501 static bool stackGrowsDown();
502 };
503
504 template <typename A>
505 class LoadCommandAtom : public WriterAtom<A>
506 {
507 protected:
508 LoadCommandAtom(Writer<A>& writer, Segment& segment) : WriterAtom<A>(writer, segment), fOrdinal(fgCurrentOrdinal++) {}
509 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
510 virtual const char* getSectionName() const { return "._load_commands"; }
511 virtual uint32_t getOrdinal() const { return fOrdinal; }
512 static uint64_t alignedSize(uint64_t size);
513 protected:
514 uint32_t fOrdinal;
515 static uint32_t fgCurrentOrdinal;
516 };
517
518 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
519
520 template <typename A>
521 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
522 {
523 public:
524 SegmentLoadCommandsAtom(Writer<A>& writer)
525 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0)
526 { writer.fSegmentCommands = this; }
527 virtual const char* getDisplayName() const { return "segment load commands"; }
528 virtual uint64_t getSize() const { return fSize; }
529 virtual void copyRawContent(uint8_t buffer[]) const;
530
531 void computeSize();
532 void setup();
533 unsigned int commandCount() { return fCommandCount; }
534 private:
535 using WriterAtom<A>::fWriter;
536 typedef typename A::P P;
537 unsigned int fCommandCount;
538 uint32_t fSize;
539 };
540
541
542 template <typename A>
543 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
544 {
545 public:
546 SymbolTableLoadCommandsAtom(Writer<A>&);
547 virtual const char* getDisplayName() const { return "symbol table load commands"; }
548 virtual uint64_t getSize() const;
549 virtual void copyRawContent(uint8_t buffer[]) const;
550 unsigned int commandCount();
551 void needDynamicTable();
552 private:
553 using WriterAtom<A>::fWriter;
554 typedef typename A::P P;
555 bool fNeedsDynamicSymbolTable;
556 macho_symtab_command<typename A::P> fSymbolTable;
557 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
558 };
559
560 template <typename A>
561 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
562 {
563 public:
564 ThreadsLoadCommandsAtom(Writer<A>& writer)
565 : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
566 virtual const char* getDisplayName() const { return "thread load commands"; }
567 virtual uint64_t getSize() const;
568 virtual void copyRawContent(uint8_t buffer[]) const;
569 private:
570 using WriterAtom<A>::fWriter;
571 typedef typename A::P P;
572 uint8_t* fBuffer;
573 uint32_t fBufferSize;
574 };
575
576 template <typename A>
577 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
578 {
579 public:
580 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
581 virtual const char* getDisplayName() const { return "dyld load command"; }
582 virtual uint64_t getSize() const;
583 virtual void copyRawContent(uint8_t buffer[]) const;
584 private:
585 using WriterAtom<A>::fWriter;
586 typedef typename A::P P;
587 };
588
589 template <typename A>
590 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
591 {
592 public:
593 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
594 virtual const char* getDisplayName() const { return "segment split info load command"; }
595 virtual uint64_t getSize() const;
596 virtual void copyRawContent(uint8_t buffer[]) const;
597 private:
598 using WriterAtom<A>::fWriter;
599 typedef typename A::P P;
600 };
601
602 template <typename A>
603 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
604 {
605 public:
606 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
607 LoadCommandAtom<A>(writer, Segment::fgTextSegment), clientString(client) {}
608 virtual const char* getDisplayName() const { return "allowable_client load command"; }
609 virtual uint64_t getSize() const;
610 virtual void copyRawContent(uint8_t buffer[]) const;
611 private:
612 using WriterAtom<A>::fWriter;
613 typedef typename A::P P;
614 const char* clientString;
615 };
616
617 template <typename A>
618 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
619 {
620 public:
621 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
622 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fInfo(info),
623 fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
624 virtual const char* getDisplayName() const { return "dylib load command"; }
625 virtual uint64_t getSize() const;
626 virtual void copyRawContent(uint8_t buffer[]) const;
627 virtual void optimizeAway() { fOptimizedAway = true; }
628 bool linkedWeak() { return fInfo.options.fWeakImport; }
629 private:
630 using WriterAtom<A>::fWriter;
631 typedef typename A::P P;
632 ExecutableFile::DyLibUsed fInfo;
633 bool fOptimizedAway;
634 };
635
636 template <typename A>
637 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
638 {
639 public:
640 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
641 virtual const char* getDisplayName() const { return "dylib ID load command"; }
642 virtual uint64_t getSize() const;
643 virtual void copyRawContent(uint8_t buffer[]) const;
644 private:
645 using WriterAtom<A>::fWriter;
646 typedef typename A::P P;
647 };
648
649 template <typename A>
650 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
651 {
652 public:
653 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
654 virtual const char* getDisplayName() const { return "routines load command"; }
655 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
656 virtual void copyRawContent(uint8_t buffer[]) const;
657 private:
658 using WriterAtom<A>::fWriter;
659 typedef typename A::P P;
660 };
661
662 template <typename A>
663 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
664 {
665 public:
666 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
667 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
668 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
669 virtual uint64_t getSize() const;
670 virtual void copyRawContent(uint8_t buffer[]) const;
671 private:
672 typedef typename A::P P;
673 const char* fName;
674 };
675
676 template <typename A>
677 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
678 {
679 public:
680 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
681 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
682 virtual const char* getDisplayName() const { return "sub-library load command"; }
683 virtual uint64_t getSize() const;
684 virtual void copyRawContent(uint8_t buffer[]) const;
685 private:
686 using WriterAtom<A>::fWriter;
687 typedef typename A::P P;
688 const char* fNameStart;
689 int fNameLength;
690 };
691
692 template <typename A>
693 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
694 {
695 public:
696 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
697 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fName(name) {}
698 virtual const char* getDisplayName() const { return "umbrella load command"; }
699 virtual uint64_t getSize() const;
700 virtual void copyRawContent(uint8_t buffer[]) const;
701 private:
702 using WriterAtom<A>::fWriter;
703 typedef typename A::P P;
704 const char* fName;
705 };
706
707 template <typename A>
708 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
709 {
710 public:
711 UUIDLoadCommandAtom(Writer<A>& writer)
712 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fEmit(false) {}
713 virtual const char* getDisplayName() const { return "uuid load command"; }
714 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
715 virtual void copyRawContent(uint8_t buffer[]) const;
716 virtual void generate();
717 void setContent(const uint8_t uuid[16]);
718 const uint8_t* getUUID() { return fUUID; }
719 private:
720 using WriterAtom<A>::fWriter;
721 typedef typename A::P P;
722 uuid_t fUUID;
723 bool fEmit;
724 };
725
726
727 template <typename A>
728 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
729 {
730 public:
731 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
732 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fPath(path) {}
733 virtual const char* getDisplayName() const { return "rpath load command"; }
734 virtual uint64_t getSize() const;
735 virtual void copyRawContent(uint8_t buffer[]) const;
736 private:
737 using WriterAtom<A>::fWriter;
738 typedef typename A::P P;
739 const char* fPath;
740 };
741
742 template <typename A>
743 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
744 {
745 public:
746 EncryptionLoadCommandsAtom(Writer<A>& writer)
747 : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fStartOffset(0),
748 fEndOffset(0) {}
749 virtual const char* getDisplayName() const { return "encryption info load command"; }
750 virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
751 virtual void copyRawContent(uint8_t buffer[]) const;
752 void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
753 void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
754 private:
755 using WriterAtom<A>::fWriter;
756 typedef typename A::P P;
757 uint32_t fStartOffset;
758 uint32_t fEndOffset;
759 };
760
761 template <typename A>
762 class LoadCommandsPaddingAtom : public WriterAtom<A>
763 {
764 public:
765 LoadCommandsPaddingAtom(Writer<A>& writer)
766 : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
767 virtual const char* getDisplayName() const { return "header padding"; }
768 virtual uint64_t getSize() const { return fSize; }
769 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
770 virtual void copyRawContent(uint8_t buffer[]) const;
771
772 void setSize(uint64_t newSize);
773 private:
774 using WriterAtom<A>::fWriter;
775 typedef typename A::P P;
776 uint64_t fSize;
777 };
778
779 template <typename A>
780 class LinkEditAtom : public WriterAtom<A>
781 {
782 public:
783 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
784 uint64_t getFileOffset() const;
785 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
786 virtual uint32_t getOrdinal() const { return fOrdinal; }
787 private:
788 uint32_t fOrdinal;
789 static uint32_t fgCurrentOrdinal;
790 private:
791 typedef typename A::P P;
792 };
793
794 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
795
796 template <typename A>
797 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
798 {
799 public:
800 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
801 virtual const char* getDisplayName() const { return "section relocations"; }
802 virtual uint64_t getSize() const;
803 virtual const char* getSectionName() const { return "._section_relocs"; }
804 virtual void copyRawContent(uint8_t buffer[]) const;
805 private:
806 using WriterAtom<A>::fWriter;
807 typedef typename A::P P;
808 };
809
810 template <typename A>
811 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
812 {
813 public:
814 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
815 virtual const char* getDisplayName() const { return "local relocations"; }
816 virtual uint64_t getSize() const;
817 virtual const char* getSectionName() const { return "._local_relocs"; }
818 virtual void copyRawContent(uint8_t buffer[]) const;
819 private:
820 using WriterAtom<A>::fWriter;
821 typedef typename A::P P;
822 };
823
824 template <typename A>
825 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
826 {
827 public:
828 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
829 virtual const char* getDisplayName() const { return "symbol table"; }
830 virtual uint64_t getSize() const;
831 virtual const char* getSectionName() const { return "._symbol_table"; }
832 virtual void copyRawContent(uint8_t buffer[]) const;
833 private:
834 using WriterAtom<A>::fWriter;
835 typedef typename A::P P;
836 };
837
838 template <typename A>
839 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
840 {
841 public:
842 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
843 virtual const char* getDisplayName() const { return "external relocations"; }
844 virtual uint64_t getSize() const;
845 virtual const char* getSectionName() const { return "._extern_relocs"; }
846 virtual void copyRawContent(uint8_t buffer[]) const;
847 private:
848 using WriterAtom<A>::fWriter;
849 typedef typename A::P P;
850 };
851
852 struct IndirectEntry {
853 uint32_t indirectIndex;
854 uint32_t symbolIndex;
855 };
856
857
858 template <typename A>
859 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
860 {
861 public:
862 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
863 virtual const char* getDisplayName() const { return "split segment info"; }
864 virtual uint64_t getSize() const;
865 virtual const char* getSectionName() const { return "._split_info"; }
866 virtual void copyRawContent(uint8_t buffer[]) const;
867 bool canEncode() { return !fCantEncode; }
868 void setCantEncode() { fCantEncode = true; }
869 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
870 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
871 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
872 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
873 void encode();
874
875 private:
876 using WriterAtom<A>::fWriter;
877 typedef typename A::P P;
878 typedef typename A::P::uint_t pint_t;
879 struct AtomAndOffset {
880 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
881 const ObjectFile::Atom* atom;
882 uint32_t offset;
883 };
884 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
885
886 std::vector<AtomAndOffset> fKind1Locations;
887 std::vector<AtomAndOffset> fKind2Locations;
888 std::vector<AtomAndOffset> fKind3Locations;
889 std::vector<AtomAndOffset> fKind4Locations;
890 std::vector<uint8_t> fEncodedData;
891 bool fCantEncode;
892 };
893
894 template <typename A>
895 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
896 {
897 public:
898 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
899 virtual const char* getDisplayName() const { return "indirect symbol table"; }
900 virtual uint64_t getSize() const;
901 virtual const char* getSectionName() const { return "._indirect_syms"; }
902 virtual void copyRawContent(uint8_t buffer[]) const;
903
904 std::vector<IndirectEntry> fTable;
905
906 private:
907 using WriterAtom<A>::fWriter;
908 typedef typename A::P P;
909 };
910
911 template <typename A>
912 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
913 {
914 public:
915 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
916 virtual const char* getDisplayName() const { return "module table"; }
917 virtual uint64_t getSize() const;
918 virtual const char* getSectionName() const { return "._module_info"; }
919 virtual void copyRawContent(uint8_t buffer[]) const;
920
921 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
922 uint32_t getTableOfContentsFileOffset() const;
923 uint32_t getModuleTableFileOffset() const;
924 uint32_t getReferencesFileOffset() const;
925 uint32_t getReferencesCount() const;
926
927 private:
928 using WriterAtom<A>::fWriter;
929 typedef typename A::P P;
930 uint32_t fModuleNameOffset;
931 };
932
933
934 class CStringEquals
935 {
936 public:
937 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
938 };
939
940 template <typename A>
941 class StringsLinkEditAtom : public LinkEditAtom<A>
942 {
943 public:
944 StringsLinkEditAtom(Writer<A>& writer);
945 virtual const char* getDisplayName() const { return "string pool"; }
946 virtual uint64_t getSize() const;
947 virtual const char* getSectionName() const { return "._string_pool"; }
948 virtual void copyRawContent(uint8_t buffer[]) const;
949
950 int32_t add(const char* name);
951 int32_t addUnique(const char* name);
952 int32_t emptyString() { return 1; }
953 const char* stringForIndex(int32_t) const;
954
955 private:
956 using WriterAtom<A>::fWriter;
957 typedef typename A::P P;
958 enum { kBufferSize = 0x01000000 };
959 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
960
961 std::vector<char*> fFullBuffers;
962 char* fCurrentBuffer;
963 uint32_t fCurrentBufferUsed;
964 StringToOffset fUniqueStrings;
965 };
966
967
968
969 template <typename A>
970 class UndefinedSymbolProxyAtom : public WriterAtom<A>
971 {
972 public:
973 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
974 virtual const char* getName() const { return fName; }
975 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
976 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
977 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
978 virtual uint64_t getSize() const { return 0; }
979 virtual const char* getSectionName() const { return "._imports"; }
980 private:
981 using WriterAtom<A>::fWriter;
982 typedef typename A::P P;
983 const char* fName;
984 };
985
986 template <typename A>
987 class BranchIslandAtom : public WriterAtom<A>
988 {
989 public:
990 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
991 virtual const char* getName() const { return fName; }
992 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
993 virtual uint64_t getSize() const;
994 virtual const char* getSectionName() const { return "__text"; }
995 virtual void copyRawContent(uint8_t buffer[]) const;
996 private:
997 using WriterAtom<A>::fWriter;
998 const char* fName;
999 ObjectFile::Atom& fTarget;
1000 uint32_t fTargetOffset;
1001 };
1002
1003 template <typename A>
1004 class StubAtom : public WriterAtom<A>
1005 {
1006 public:
1007 StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
1008 virtual const char* getName() const { return fName; }
1009 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1010 virtual uint64_t getSize() const;
1011 virtual ObjectFile::Alignment getAlignment() const;
1012 virtual const char* getSectionName() const { return "__symbol_stub1"; }
1013 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1014 virtual void copyRawContent(uint8_t buffer[]) const;
1015 ObjectFile::Atom* getTarget() { return &fTarget; }
1016 private:
1017 static const char* stubName(const char* importName);
1018 bool pic() const { return fWriter.fSlideable; }
1019 using WriterAtom<A>::fWriter;
1020 const char* fName;
1021 ObjectFile::Atom& fTarget;
1022 std::vector<ObjectFile::Reference*> fReferences;
1023 bool fForLazyDylib;
1024 };
1025
1026 template <typename A>
1027 class StubHelperAtom : public WriterAtom<A>
1028 {
1029 public:
1030 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer, bool forLazyDylib);
1031 virtual const char* getName() const { return fName; }
1032 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1033 virtual uint64_t getSize() const;
1034 virtual const char* getSectionName() const { return "__stub_helper"; }
1035 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1036 virtual void copyRawContent(uint8_t buffer[]) const;
1037 ObjectFile::Atom* getTarget() { return &fTarget; }
1038 private:
1039 static const char* stubName(const char* importName);
1040 using WriterAtom<A>::fWriter;
1041 const char* fName;
1042 ObjectFile::Atom& fTarget;
1043 std::vector<ObjectFile::Reference*> fReferences;
1044 };
1045
1046 template <typename A>
1047 class LazyPointerAtom : public WriterAtom<A>
1048 {
1049 public:
1050 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target,
1051 StubAtom<A>& stub, bool forLazyDylib);
1052 virtual const char* getName() const { return fName; }
1053 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1054 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1055 virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; }
1056 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1057 virtual void copyRawContent(uint8_t buffer[]) const;
1058 ObjectFile::Atom* getTarget() { return &fExternalTarget; }
1059 private:
1060 using WriterAtom<A>::fWriter;
1061 static const char* lazyPointerName(const char* importName);
1062 const char* fName;
1063 ObjectFile::Atom& fTarget;
1064 ObjectFile::Atom& fExternalTarget;
1065 std::vector<ObjectFile::Reference*> fReferences;
1066 bool fForLazyDylib;
1067 };
1068
1069
1070 template <typename A>
1071 class NonLazyPointerAtom : public WriterAtom<A>
1072 {
1073 public:
1074 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1075 virtual const char* getName() const { return fName; }
1076 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1077 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1078 virtual const char* getSectionName() const { return "__nl_symbol_ptr"; }
1079 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1080 virtual void copyRawContent(uint8_t buffer[]) const;
1081 ObjectFile::Atom* getTarget() { return &fTarget; }
1082 private:
1083 using WriterAtom<A>::fWriter;
1084 static const char* nonlazyPointerName(const char* importName);
1085 const char* fName;
1086 ObjectFile::Atom& fTarget;
1087 std::vector<ObjectFile::Reference*> fReferences;
1088 };
1089
1090
1091 template <typename A>
1092 class ObjCInfoAtom : public WriterAtom<A>
1093 {
1094 public:
1095 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1096 bool objcReplacementClasses);
1097 virtual const char* getName() const { return "objc$info"; }
1098 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1099 virtual uint64_t getSize() const { return 8; }
1100 virtual const char* getSectionName() const;
1101 virtual void copyRawContent(uint8_t buffer[]) const;
1102 private:
1103 Segment& getInfoSegment() const;
1104 uint32_t fContent[2];
1105 };
1106
1107
1108 template <typename A>
1109 class WriterReference : public ObjectFile::Reference
1110 {
1111 public:
1112 typedef typename A::ReferenceKinds Kinds;
1113
1114 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1115 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1116 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target),
1117 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1118
1119 virtual ~WriterReference() {}
1120
1121 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return ObjectFile::Reference::kBoundDirectly; }
1122 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1123 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1124 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1125 virtual const char* getTargetName() const { return fTarget->getName(); }
1126 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1127 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1128 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1129 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1130 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = &target; fTargetOffset = offset; }
1131 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = &target; }
1132 virtual void setFromTargetName(const char* name) { }
1133 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1134 virtual const char* getDescription() const { return "writer reference"; }
1135 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1136
1137 private:
1138 Kinds fKind;
1139 uint32_t fFixUpOffsetInSrc;
1140 ObjectFile::Atom* fTarget;
1141 uint32_t fTargetOffset;
1142 ObjectFile::Atom* fFromTarget;
1143 uint32_t fFromTargetOffset;
1144 };
1145
1146
1147
1148 template <>
1149 StubHelperAtom<x86_64>::StubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1150 ObjectFile::Atom& lazyPointer, bool forLazyDylib)
1151 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1152 {
1153 writer.fAllSynthesizedStubHelpers.push_back(this);
1154
1155 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &lazyPointer));
1156 if ( forLazyDylib ) {
1157 if ( writer.fDyldLazyDylibHelper == NULL )
1158 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1159 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldLazyDylibHelper));
1160 }
1161 else {
1162 if ( writer.fDyldHelper == NULL )
1163 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1164 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldHelper));
1165 }
1166 }
1167
1168 template <>
1169 uint64_t StubHelperAtom<x86_64>::getSize() const
1170 {
1171 return 12;
1172 }
1173
1174 template <>
1175 void StubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1176 {
1177 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1178 buffer[1] = 0x8D;
1179 buffer[2] = 0x1D;
1180 buffer[3] = 0x00;
1181 buffer[4] = 0x00;
1182 buffer[5] = 0x00;
1183 buffer[6] = 0x00;
1184 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1185 buffer[8] = 0x00;
1186 buffer[9] = 0x00;
1187 buffer[10] = 0x00;
1188 buffer[11] = 0x00;
1189 }
1190
1191
1192 template <typename A>
1193 const char* StubHelperAtom<A>::stubName(const char* name)
1194 {
1195 char* buf;
1196 asprintf(&buf, "%s$stubHelper", name);
1197 return buf;
1198 }
1199
1200
1201 // specialize lazy pointer for x86_64 to initially pointer to stub helper
1202 template <>
1203 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
1204 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
1205 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
1206 {
1207 if ( forLazyDylib )
1208 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
1209 else
1210 writer.fAllSynthesizedLazyPointers.push_back(this);
1211
1212 StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
1213 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
1214 }
1215
1216 // specialize lazy pointer for x86 to initially pointer to second half of stub
1217 template <>
1218 LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
1219 : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
1220 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
1221 {
1222 if ( forLazyDylib )
1223 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
1224 else
1225 writer.fAllSynthesizedLazyPointers.push_back(this);
1226
1227 // helper part of stub is 14 or 6 bytes into stub
1228 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, &stub, writer.fSlideable ? 14 : 6));
1229 }
1230
1231 template <typename A>
1232 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
1233 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
1234 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
1235 {
1236 if ( forLazyDylib )
1237 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
1238 else
1239 writer.fAllSynthesizedLazyPointers.push_back(this);
1240
1241 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
1242 }
1243
1244
1245
1246 template <typename A>
1247 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
1248 {
1249 char* buf;
1250 asprintf(&buf, "%s$lazy_pointer", name);
1251 return buf;
1252 }
1253
1254 template <typename A>
1255 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
1256 {
1257 bzero(buffer, getSize());
1258 }
1259
1260
1261 template <typename A>
1262 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
1263 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
1264 {
1265 writer.fAllSynthesizedNonLazyPointers.push_back(this);
1266
1267 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
1268 }
1269
1270 template <typename A>
1271 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
1272 {
1273 char* buf;
1274 asprintf(&buf, "%s$non_lazy_pointer", name);
1275 return buf;
1276 }
1277
1278 template <typename A>
1279 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
1280 {
1281 bzero(buffer, getSize());
1282 }
1283
1284
1285
1286 template <>
1287 bool StubAtom<ppc64>::pic() const
1288 {
1289 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
1290 // Usually that only happens if page zero is very large
1291 return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
1292 }
1293
1294
1295 template <>
1296 bool StubAtom<arm>::pic() const
1297 {
1298 return fWriter.fSlideable;
1299 }
1300
1301 template <>
1302 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
1303 {
1304 return 2;
1305 }
1306
1307 template <>
1308 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
1309 {
1310 return 2;
1311 }
1312
1313 template <>
1314 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
1315 {
1316 return 2;
1317 }
1318
1319 template <>
1320 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1321 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1322 fTarget(target), fForLazyDylib(forLazyDylib)
1323 {
1324 writer.fAllSynthesizedStubs.push_back(this);
1325 LazyPointerAtom<ppc>* lp;
1326 if ( fWriter.fOptions.prebind() ) {
1327 // for prebound ppc, lazy pointer starts out pointing to target symbol's address
1328 // if target is a weak definition within this linkage unit or zero if in some dylib
1329 lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
1330 }
1331 else {
1332 // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
1333 if ( forLazyDylib ) {
1334 if ( writer.fDyldLazyDylibHelper == NULL )
1335 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1336 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
1337 }
1338 else {
1339 if ( writer.fDyldHelper == NULL )
1340 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1341 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldHelper, *this, forLazyDylib);
1342 }
1343 }
1344 if ( pic() ) {
1345 // picbase is 8 bytes into atom
1346 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
1347 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
1348 }
1349 else {
1350 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
1351 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
1352 }
1353 }
1354
1355 template <>
1356 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1357 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1358 fTarget(target), fForLazyDylib(forLazyDylib)
1359 {
1360 writer.fAllSynthesizedStubs.push_back(this);
1361
1362 LazyPointerAtom<ppc64>* lp;
1363 if ( forLazyDylib ) {
1364 if ( writer.fDyldLazyDylibHelper == NULL )
1365 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1366 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
1367 }
1368 else {
1369 if ( writer.fDyldHelper == NULL )
1370 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1371 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldHelper, *this, forLazyDylib);
1372 }
1373 if ( pic() ) {
1374 // picbase is 8 bytes into atom
1375 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
1376 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
1377 }
1378 else {
1379 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
1380 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
1381 }
1382 }
1383
1384 // specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
1385 template <>
1386 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1387 : WriterAtom<x86>(writer, (writer.fOptions.slowx86Stubs() || forLazyDylib) ? Segment::fgTextSegment :
1388 ( writer.fOptions.readOnlyx86Stubs() ? Segment::fgROImportSegment : Segment::fgImportSegment)),
1389 fTarget(target), fForLazyDylib(forLazyDylib)
1390 {
1391 if ( writer.fOptions.slowx86Stubs() || forLazyDylib ) {
1392 fName = stubName(target.getName());
1393 writer.fAllSynthesizedStubs.push_back(this);
1394 LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
1395 ObjectFile::Atom* helper;
1396 if ( forLazyDylib ) {
1397 if ( writer.fDyldLazyDylibHelper == NULL )
1398 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1399 helper = writer.fDyldLazyDylibHelper;
1400 }
1401 else {
1402 if ( writer.fDyldHelper == NULL )
1403 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1404 helper = writer.fDyldHelper;
1405 }
1406 if ( pic() ) {
1407 // picbase is 5 bytes into atom
1408 fReferences.push_back(new WriterReference<x86>(8, x86::kPointerDiff, lp, 0, this, 5));
1409 fReferences.push_back(new WriterReference<x86>(16, x86::kPCRel32, helper));
1410 }
1411 else {
1412 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
1413 fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, lp));
1414 fReferences.push_back(new WriterReference<x86>(12, x86::kPCRel32, helper));
1415 }
1416 }
1417 else {
1418 if ( &target == NULL )
1419 fName = "cache-line-crossing-stub";
1420 else {
1421 fName = stubName(target.getName());
1422 writer.fAllSynthesizedStubs.push_back(this);
1423 }
1424 }
1425 }
1426
1427 template <>
1428 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1429 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1430 {
1431 writer.fAllSynthesizedStubs.push_back(this);
1432
1433 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
1434 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
1435 }
1436
1437 template <>
1438 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
1439 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
1440 {
1441 writer.fAllSynthesizedStubs.push_back(this);
1442
1443 LazyPointerAtom<arm>* lp;
1444 if ( fWriter.fOptions.prebind() && !forLazyDylib ) {
1445 // for prebound arm, lazy pointer starts out pointing to target symbol's address
1446 // if target is a weak definition within this linkage unit or zero if in some dylib
1447 lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
1448 }
1449 else {
1450 // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
1451 ObjectFile::Atom* helper;
1452 if ( forLazyDylib ) {
1453 if ( writer.fDyldLazyDylibHelper == NULL )
1454 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1455 helper = writer.fDyldLazyDylibHelper;
1456 }
1457 else {
1458 if ( writer.fDyldHelper == NULL )
1459 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1460 helper = writer.fDyldHelper;
1461 }
1462 lp = new LazyPointerAtom<arm>(writer, *helper, *this, forLazyDylib);
1463 }
1464 if ( pic() )
1465 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
1466 else
1467 fReferences.push_back(new WriterReference<arm>(8, arm::kPointer, lp));
1468 }
1469
1470 template <typename A>
1471 const char* StubAtom<A>::stubName(const char* name)
1472 {
1473 char* buf;
1474 asprintf(&buf, "%s$stub", name);
1475 return buf;
1476 }
1477
1478 template <>
1479 uint64_t StubAtom<ppc>::getSize() const
1480 {
1481 return ( pic() ? 32 : 16 );
1482 }
1483
1484 template <>
1485 uint64_t StubAtom<ppc64>::getSize() const
1486 {
1487 return ( pic() ? 32 : 16 );
1488 }
1489
1490
1491 template <>
1492 uint64_t StubAtom<arm>::getSize() const
1493 {
1494 return ( pic() ? 16 : 12 );
1495 }
1496
1497 template <>
1498 uint64_t StubAtom<x86>::getSize() const
1499 {
1500 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
1501 if ( pic() )
1502 return 20;
1503 else
1504 return 16;
1505 }
1506 return 5;
1507 }
1508
1509 template <>
1510 uint64_t StubAtom<x86_64>::getSize() const
1511 {
1512 return 6;
1513 }
1514
1515 template <>
1516 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
1517 {
1518 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib )
1519 return 2;
1520 else
1521 return 0; // special case x86 fast stubs to be byte aligned
1522 }
1523
1524 template <>
1525 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
1526 {
1527 if ( pic() ) {
1528 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
1529 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
1530 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
1531 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
1532 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
1533 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
1534 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
1535 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
1536 }
1537 else {
1538 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
1539 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
1540 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
1541 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
1542 }
1543 }
1544
1545 template <>
1546 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
1547 {
1548 if ( pic() ) {
1549 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
1550 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
1551 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
1552 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
1553 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
1554 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
1555 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
1556 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
1557 }
1558 else {
1559 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
1560 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
1561 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
1562 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
1563 }
1564 }
1565
1566 template <>
1567 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
1568 {
1569 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
1570 if ( pic() ) {
1571 buffer[0] = 0xE8; // call picbase
1572 buffer[1] = 0x00;
1573 buffer[2] = 0x00;
1574 buffer[3] = 0x00;
1575 buffer[4] = 0x00;
1576 buffer[5] = 0x58; // pop eax
1577 buffer[6] = 0x8D; // lea foo$lazy_pointer-picbase(eax),eax
1578 buffer[7] = 0x80;
1579 buffer[8] = 0x00;
1580 buffer[9] = 0x00;
1581 buffer[10] = 0x00;
1582 buffer[11] = 0x00;
1583 buffer[12] = 0xFF; // jmp *(eax)
1584 buffer[13] = 0x20;
1585 buffer[14] = 0x50; // push eax
1586 buffer[15] = 0xE9; // jump dyld_stub_binding_helper
1587 buffer[16] = 0x00;
1588 buffer[17] = 0x00;
1589 buffer[18] = 0x00;
1590 buffer[19] = 0x00;
1591 }
1592 else {
1593 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
1594 buffer[1] = 0x25;
1595 buffer[2] = 0x00;
1596 buffer[3] = 0x00;
1597 buffer[4] = 0x00;
1598 buffer[5] = 0x00;
1599 buffer[6] = 0x68; // pushl $foo$lazy_pointer
1600 buffer[7] = 0x00;
1601 buffer[8] = 0x00;
1602 buffer[9] = 0x00;
1603 buffer[10] = 0x00;
1604 buffer[11] = 0xE9; // jump dyld_stub_binding_helper
1605 buffer[12] = 0x00;
1606 buffer[13] = 0x00;
1607 buffer[14] = 0x00;
1608 buffer[15] = 0x00;
1609 }
1610 }
1611 else {
1612 if ( fWriter.fOptions.prebind() ) {
1613 uint32_t address = this->getAddress();
1614 int32_t rel32 = 0 - (address+5);
1615 buffer[0] = 0xE9;
1616 buffer[1] = rel32 & 0xFF;
1617 buffer[2] = (rel32 >> 8) & 0xFF;
1618 buffer[3] = (rel32 >> 16) & 0xFF;
1619 buffer[4] = (rel32 >> 24) & 0xFF;
1620 }
1621 else {
1622 buffer[0] = 0xF4;
1623 buffer[1] = 0xF4;
1624 buffer[2] = 0xF4;
1625 buffer[3] = 0xF4;
1626 buffer[4] = 0xF4;
1627 }
1628 }
1629 }
1630
1631 template <>
1632 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1633 {
1634 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
1635 buffer[1] = 0x25;
1636 buffer[2] = 0x00;
1637 buffer[3] = 0x00;
1638 buffer[4] = 0x00;
1639 buffer[5] = 0x00;
1640 }
1641
1642 template <>
1643 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
1644 {
1645 if ( pic() ) {
1646 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
1647 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
1648 OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
1649 OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
1650 }
1651 else {
1652 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
1653 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
1654 OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
1655 }
1656 }
1657
1658 // x86_64 stubs are 7 bytes and need no alignment
1659 template <>
1660 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
1661 {
1662 return 0;
1663 }
1664
1665 template <>
1666 const char* StubAtom<ppc>::getSectionName() const
1667 {
1668 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
1669 }
1670
1671 template <>
1672 const char* StubAtom<ppc64>::getSectionName() const
1673 {
1674 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
1675 }
1676
1677 template <>
1678 const char* StubAtom<arm>::getSectionName() const
1679 {
1680 return ( pic() ? "__picsymbolstub4" : "__symbol_stub4");
1681 }
1682
1683 template <>
1684 const char* StubAtom<x86>::getSectionName() const
1685 {
1686 if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
1687 if ( pic() )
1688 return "__picsymbol_stub";
1689 else
1690 return "__symbol_stub";
1691 }
1692 return "__jump_table";
1693 }
1694
1695
1696
1697
1698 struct AtomByNameSorter
1699 {
1700 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
1701 {
1702 return (strcmp(left->getName(), right->getName()) < 0);
1703 }
1704 };
1705
1706 template <typename P>
1707 struct ExternalRelocSorter
1708 {
1709 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
1710 {
1711 // sort first by symbol number
1712 if ( left.r_symbolnum() != right.r_symbolnum() )
1713 return (left.r_symbolnum() < right.r_symbolnum());
1714 // then sort all uses of the same symbol by address
1715 return (left.r_address() < right.r_address());
1716 }
1717 };
1718
1719
1720 template <typename A>
1721 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
1722 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
1723 fAllAtoms(NULL), fStabs(NULL), fLoadCommandsSection(NULL),
1724 fLoadCommandsSegment(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
1725 fSymbolTableCommands(NULL), fHeaderPadding(NULL),
1726 fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL), fDyldHelper(NULL), fDyldLazyDylibHelper(NULL),
1727 fSectionRelocationsAtom(NULL), fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
1728 fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
1729 fStringsAtom(NULL), fPageZeroAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0), fSymbolTableStabsCount(0),
1730 fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
1731 fLargestAtomSize(1),
1732 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
1733 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
1734 fBiggerThanTwoGigs(false), fSlideable(false),
1735 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
1736 {
1737 switch ( fOptions.outputKind() ) {
1738 case Options::kDynamicExecutable:
1739 case Options::kStaticExecutable:
1740 if ( fOptions.zeroPageSize() != 0 )
1741 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
1742 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1743 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1744 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1745 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1746 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1747 if ( fOptions.outputKind() == Options::kDynamicExecutable )
1748 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1749 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1750 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1751 if ( fOptions.hasCustomStack() )
1752 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
1753 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1754 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1755 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1756 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1757 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1758 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1759 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1760 break;
1761 case Options::kDynamicLibrary:
1762 case Options::kDynamicBundle:
1763 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1764 // fall through
1765 case Options::kObjectFile:
1766 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1767 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1768 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
1769 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
1770 if ( fOptions.initFunctionName() != NULL )
1771 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
1772 }
1773 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1774 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1775 if ( fOptions.sharedRegionEligible() )
1776 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
1777 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1778 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
1779 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1780 if ( fOptions.sharedRegionEligible() ) {
1781 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
1782 }
1783 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1784 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1785 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1786 if ( this->needsModuleTable() )
1787 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
1788 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1789 break;
1790 case Options::kDyld:
1791 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
1792 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
1793 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
1794 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
1795 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
1796 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
1797 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
1798 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
1799 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
1800 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
1801 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
1802 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
1803 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
1804 break;
1805 }
1806
1807 // add extra commmands
1808 bool hasReExports = false;
1809 uint32_t ordinal = 1;
1810 switch ( fOptions.outputKind() ) {
1811 case Options::kDynamicExecutable:
1812 if ( fOptions.makeEncryptable() ) {
1813 fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
1814 fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
1815 }
1816 // fall through
1817 case Options::kDynamicLibrary:
1818 case Options::kDynamicBundle:
1819 {
1820 // add dylib load command atoms for all dynamic libraries
1821 const unsigned int libCount = dynamicLibraries.size();
1822 for (unsigned int i=0; i < libCount; ++i) {
1823 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
1824 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
1825
1826 if ( dylibInfo.options.fReExport ) {
1827 hasReExports = true;
1828 }
1829 else {
1830 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
1831 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
1832 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
1833 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
1834 hasReExports = true;
1835 }
1836 }
1837
1838 if ( dylibInfo.options.fBundleLoader ) {
1839 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
1840 }
1841 else {
1842 // see if a DylibLoadCommandsAtom has already been created for this install path
1843 bool newDylib = true;
1844 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
1845 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
1846 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
1847 if ( !seenDylibInfo.options.fBundleLoader ) {
1848 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
1849 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
1850 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
1851 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
1852 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
1853 newDylib = false;
1854 break;
1855 }
1856 }
1857 }
1858
1859 if ( newDylib ) {
1860 // assign new ordinal and check for other paired load commands
1861 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
1862 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
1863 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
1864 fWriterSynthesizedAtoms.push_back(dyliblc);
1865 if ( dylibInfo.options.fReExport
1866 && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
1867 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
1868 // see if child has sub-framework that is this
1869 bool isSubFramework = false;
1870 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
1871 if ( childInUmbrella != NULL ) {
1872 const char* myLeaf = strrchr(fOptions.installPath(), '/');
1873 if ( myLeaf != NULL ) {
1874 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
1875 isSubFramework = true;
1876 }
1877 }
1878 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
1879 if ( ! isSubFramework ) {
1880 // this dylib also needs a sub_x load command
1881 bool isFrameworkReExport = false;
1882 const char* lastSlash = strrchr(dylibInstallPath, '/');
1883 if ( lastSlash != NULL ) {
1884 char frameworkName[strlen(lastSlash)+20];
1885 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
1886 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
1887 }
1888 if ( isFrameworkReExport ) {
1889 // needs a LC_SUB_UMBRELLA command
1890 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
1891 }
1892 else {
1893 // needs a LC_SUB_LIBRARY command
1894 const char* nameStart = &lastSlash[1];
1895 if ( lastSlash == NULL )
1896 nameStart = dylibInstallPath;
1897 int len = strlen(nameStart);
1898 const char* dot = strchr(nameStart, '.');
1899 if ( dot != NULL )
1900 len = dot - nameStart;
1901 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
1902 }
1903 }
1904 }
1905 }
1906 }
1907 }
1908 // add umbrella command if needed
1909 if ( fOptions.umbrellaName() != NULL ) {
1910 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
1911 }
1912 // add allowable client commands if used
1913 std::vector<const char*>& allowableClients = fOptions.allowableClients();
1914 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
1915 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
1916 }
1917 break;
1918 case Options::kStaticExecutable:
1919 case Options::kObjectFile:
1920 case Options::kDyld:
1921 break;
1922 }
1923 fNoReExportedDylibs = !hasReExports;
1924
1925 // add any rpath load commands
1926 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
1927 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
1928 }
1929
1930 // set up fSlideable
1931 switch ( fOptions.outputKind() ) {
1932 case Options::kObjectFile:
1933 case Options::kStaticExecutable:
1934 fSlideable = false;
1935 break;
1936 case Options::kDynamicExecutable:
1937 fSlideable = fOptions.positionIndependentExecutable();
1938 break;
1939 case Options::kDyld:
1940 case Options::kDynamicLibrary:
1941 case Options::kDynamicBundle:
1942 fSlideable = true;
1943 break;
1944 }
1945
1946 //fprintf(stderr, "ordinals table:\n");
1947 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
1948 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
1949 //}
1950 }
1951
1952 template <typename A>
1953 Writer<A>::~Writer()
1954 {
1955 if ( fFilePath != NULL )
1956 free((void*)fFilePath);
1957 if ( fSymbolTable != NULL )
1958 delete [] fSymbolTable;
1959 }
1960
1961
1962 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
1963 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
1964 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
1965
1966
1967 template <typename A>
1968 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
1969 {
1970 if ( fOptions.outputKind() == Options::kObjectFile ) {
1971 // when doing -r -exported_symbols_list, don't creat proxy for a symbol
1972 // that is supposed to be exported. We want an error instead
1973 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
1974 if ( fOptions.hasExportRestrictList() && fOptions.shouldExport(name) )
1975 return NULL;
1976 else
1977 return new UndefinedSymbolProxyAtom<A>(*this, name);
1978 }
1979 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
1980 return new UndefinedSymbolProxyAtom<A>(*this, name);
1981 else
1982 return NULL;
1983 }
1984
1985 template <typename A>
1986 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
1987 {
1988 // flat namespace images use zero for all ordinals
1989 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
1990 return 0;
1991
1992 // is an UndefinedSymbolProxyAtom
1993 if ( lib == this )
1994 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
1995 return DYNAMIC_LOOKUP_ORDINAL;
1996
1997 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
1998 if ( pos != fLibraryToOrdinal.end() )
1999 return pos->second;
2000
2001 throw "can't find ordinal for imported symbol";
2002 }
2003
2004 template <typename A>
2005 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
2006 {
2007 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
2008 }
2009
2010
2011 template <typename A>
2012 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
2013 std::vector<class ObjectFile::Reader::Stab>& stabs,
2014 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
2015 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
2016 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
2017 bool biggerThanTwoGigs, bool overridesDylibWeakDefines)
2018 {
2019 fAllAtoms = &atoms;
2020 fStabs = &stabs;
2021 fEntryPoint = entryPointAtom;
2022 fDyldHelper = dyldHelperAtom;
2023 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
2024 fCanScatter = canScatter;
2025 fCpuConstraint = cpuConstraint;
2026 fBiggerThanTwoGigs = biggerThanTwoGigs;
2027 fHasWeakExports = overridesDylibWeakDefines; // dyld needs to search this image as if it had weak exports
2028
2029 try {
2030 // Set for create UUID
2031 if (createUUID)
2032 fUUIDAtom->generate();
2033
2034 // remove uneeded dylib load commands
2035 optimizeDylibReferences();
2036
2037 // check for mdynamic-no-pic codegen
2038 scanForAbsoluteReferences();
2039
2040 // create inter-library stubs
2041 synthesizeStubs();
2042
2043 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
2044 partitionIntoSections();
2045
2046 // segment load command can now be sized and padding can be set
2047 adjustLoadCommandsAndPadding();
2048
2049 // assign each section a file offset
2050 assignFileOffsets();
2051
2052 // if need to add branch islands, reassign file offsets
2053 if ( addBranchIslands() )
2054 assignFileOffsets();
2055
2056 // build symbol table and relocations
2057 buildLinkEdit();
2058
2059 // write map file if requested
2060 writeMap();
2061
2062 // write everything
2063 return writeAtoms();
2064 } catch (...) {
2065 // clean up if any errors
2066 (void)unlink(fFilePath);
2067 throw;
2068 }
2069 }
2070
2071 template <typename A>
2072 void Writer<A>::buildLinkEdit()
2073 {
2074 this->collectExportedAndImportedAndLocalAtoms();
2075 this->buildSymbolTable();
2076 this->buildFixups();
2077 this->adjustLinkEditSections();
2078 }
2079
2080
2081
2082 template <typename A>
2083 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
2084 {
2085 return atom->getAddress();
2086 // SectionInfo* info = (SectionInfo*)atom->getSection();
2087 // return info->getBaseAddress() + atom->getSectionOffset();
2088 }
2089
2090
2091 template <>
2092 const char* Writer<x86_64>::symbolTableName(const ObjectFile::Atom* atom)
2093 {
2094 static unsigned int counter = 0;
2095 const char* name = atom->getName();
2096 if ( strncmp(name, "cstring=", 8) == 0 )
2097 asprintf((char**)&name, "LC%u", counter++);
2098 return name;
2099 }
2100
2101 template <typename A>
2102 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
2103 {
2104 return atom->getName();
2105 }
2106
2107 template <typename A>
2108 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
2109 {
2110 // set n_strx
2111 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
2112
2113 // set n_type
2114 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
2115 entry->set_n_type(N_EXT | N_ABS);
2116 }
2117 else {
2118 entry->set_n_type(N_EXT | N_SECT);
2119 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
2120 if ( fOptions.keepPrivateExterns() )
2121 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
2122 }
2123 }
2124
2125 // set n_sect (section number of implementation )
2126 uint8_t sectionIndex = atom->getSection()->getIndex();
2127 entry->set_n_sect(sectionIndex);
2128
2129 // the __mh_execute_header is magic and must be an absolute symbol
2130 if ( (sectionIndex==0)
2131 && (fOptions.outputKind() == Options::kDynamicExecutable)
2132 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
2133 entry->set_n_type(N_EXT | N_ABS);
2134
2135 // set n_desc
2136 uint16_t desc = 0;
2137 if ( atom->isThumb() )
2138 desc |= N_ARM_THUMB_DEF;
2139 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
2140 desc |= REFERENCED_DYNAMICALLY;
2141 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
2142 desc |= N_WEAK_DEF;
2143 fHasWeakExports = true;
2144 }
2145 entry->set_n_desc(desc);
2146
2147 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2148 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2149 entry->set_n_value(atom->getSectionOffset());
2150 else
2151 entry->set_n_value(this->getAtomLoadAddress(atom));
2152 }
2153
2154 template <typename A>
2155 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
2156 {
2157 // set n_strx
2158 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
2159
2160 // set n_type
2161 if ( (fOptions.outputKind() == Options::kObjectFile)
2162 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
2163 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
2164 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
2165 else if ( fOptions.prebind() )
2166 entry->set_n_type(N_PBUD | N_EXT);
2167 else
2168 entry->set_n_type(N_UNDF | N_EXT);
2169
2170 // set n_sect
2171 entry->set_n_sect(0);
2172
2173 uint16_t desc = 0;
2174 if ( fOptions.outputKind() != Options::kObjectFile ) {
2175 // set n_desc ( high byte is library ordinal, low byte is reference type )
2176 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
2177 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
2178 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
2179 else
2180 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
2181 try {
2182 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
2183 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
2184 SET_LIBRARY_ORDINAL(desc, ordinal);
2185 }
2186 catch (const char* msg) {
2187 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
2188 }
2189 }
2190 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
2191 uint8_t align = atom->getAlignment().powerOf2;
2192 // always record custom alignment of common symbols to match what compiler does
2193 SET_COMM_ALIGN(desc, align);
2194 }
2195 if ( atom->isThumb() )
2196 desc |= N_ARM_THUMB_DEF;
2197 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
2198 desc |= REFERENCED_DYNAMICALLY;
2199 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
2200 desc |= N_REF_TO_WEAK;
2201 fReferencesWeakImports = true;
2202 }
2203 // set weak_import attribute
2204 if ( fWeakImportMap[atom] )
2205 desc |= N_WEAK_REF;
2206 entry->set_n_desc(desc);
2207
2208 // set n_value, zero for import proxy and size for tentative definition
2209 entry->set_n_value(atom->getSize());
2210 }
2211
2212
2213 template <typename A>
2214 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
2215 {
2216 // set n_strx
2217 const char* symbolName = this->symbolTableName(atom);
2218 char anonName[32];
2219 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
2220 sprintf(anonName, "l%u", fAnonNameIndex++);
2221 symbolName = anonName;
2222 }
2223 entry->set_n_strx(this->fStringsAtom->add(symbolName));
2224
2225 // set n_type
2226 uint8_t type = N_SECT;
2227 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2228 type = N_ABS;
2229 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
2230 type |= N_PEXT;
2231 entry->set_n_type(type);
2232
2233 // set n_sect (section number of implementation )
2234 uint8_t sectIndex = atom->getSection()->getIndex();
2235 if ( sectIndex == 0 ) {
2236 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
2237 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
2238 sectIndex = 1;
2239 }
2240 entry->set_n_sect(sectIndex);
2241
2242 // set n_desc
2243 uint16_t desc = 0;
2244 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2245 desc |= N_WEAK_DEF;
2246 if ( atom->isThumb() )
2247 desc |= N_ARM_THUMB_DEF;
2248 entry->set_n_desc(desc);
2249
2250 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2251 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
2252 entry->set_n_value(atom->getSectionOffset());
2253 else
2254 entry->set_n_value(this->getAtomLoadAddress(atom));
2255 }
2256
2257
2258 template <typename A>
2259 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
2260 {
2261 macho_nlist<P> entry;
2262
2263 // set n_strx
2264 entry.set_n_strx(fStringsAtom->add(name));
2265
2266 // set n_type
2267 entry.set_n_type(N_SECT);
2268
2269 // set n_sect (section number of implementation )
2270 entry.set_n_sect(atom.getSection()->getIndex());
2271
2272 // set n_desc
2273 entry.set_n_desc(0);
2274
2275 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2276 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
2277
2278 // add
2279 fLocalExtraLabels.push_back(entry);
2280 }
2281
2282
2283
2284 template <typename A>
2285 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
2286 {
2287 macho_nlist<P> entry;
2288
2289 // set n_strx
2290 entry.set_n_strx(fStringsAtom->add(name));
2291
2292 // set n_type
2293 entry.set_n_type(N_SECT|N_EXT);
2294
2295 // set n_sect (section number of implementation )
2296 entry.set_n_sect(atom.getSection()->getIndex());
2297
2298 // set n_desc
2299 entry.set_n_desc(0);
2300
2301 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
2302 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
2303
2304 // add
2305 fGlobalExtraLabels.push_back(entry);
2306 }
2307
2308 template <typename A>
2309 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
2310 {
2311 macho_nlist<P>* entry = &fSymbolTable[startIndex];
2312 for (uint32_t i=0; i < count; ++i, ++entry) {
2313 ObjectFile::Atom* atom = atoms[i];
2314 if ( &atoms == &fExportedAtoms ) {
2315 this->setExportNlist(atom, entry);
2316 }
2317 else if ( &atoms == &fImportedAtoms ) {
2318 this->setImportNlist(atom, entry);
2319 }
2320 else {
2321 this->setLocalNlist(atom, entry);
2322 }
2323 }
2324 }
2325
2326 template <typename A>
2327 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
2328 {
2329 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
2330 fSymbolTable[startIndex++] = *it;
2331 }
2332
2333
2334 template <typename A>
2335 struct NListNameSorter
2336 {
2337 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
2338
2339 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
2340 {
2341 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
2342 }
2343 private:
2344 StringsLinkEditAtom<A>* fStringPool;
2345 };
2346
2347
2348 template <typename A>
2349 void Writer<A>::buildSymbolTable()
2350 {
2351 fSymbolTableStabsStartIndex = 0;
2352 fSymbolTableStabsCount = fStabs->size();
2353 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
2354 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
2355 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
2356 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
2357 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
2358 fSymbolTableImportCount = fImportedAtoms.size();
2359
2360 // allocate symbol table
2361 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
2362 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
2363
2364 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
2365 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
2366 if ( fLocalExtraLabels.size() != 0 )
2367 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
2368 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
2369 if ( fGlobalExtraLabels.size() != 0 ) {
2370 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
2371 // re-sort combined range
2372 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
2373 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
2374 NListNameSorter<A>(fStringsAtom) );
2375 }
2376 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
2377 addStabs(fSymbolTableStabsStartIndex);
2378
2379 // set up module table
2380 if ( fModuleInfoAtom != NULL )
2381 fModuleInfoAtom->setName();
2382 }
2383
2384
2385
2386 template <typename A>
2387 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
2388 {
2389 switch ( atom.getSymbolTableInclusion() ) {
2390 case ObjectFile::Atom::kSymbolTableNotIn:
2391 return false;
2392 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
2393 return true;
2394 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
2395 case ObjectFile::Atom::kSymbolTableIn:
2396 switch ( atom.getScope() ) {
2397 case ObjectFile::Atom::scopeGlobal:
2398 return true;
2399 case ObjectFile::Atom::scopeLinkageUnit:
2400 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
2401 default:
2402 return false;
2403 }
2404 break;
2405 }
2406 return false;
2407 }
2408
2409 template <typename A>
2410 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
2411 {
2412 const int atomCount = fAllAtoms->size();
2413 // guess at sizes of each bucket to minimize re-allocations
2414 fImportedAtoms.reserve(100);
2415 fExportedAtoms.reserve(atomCount/2);
2416 fLocalSymbolAtoms.reserve(atomCount);
2417 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
2418 ObjectFile::Atom* atom = *it;
2419 // only named atoms go in symbol table
2420 if ( atom->getName() != NULL ) {
2421 // put atom into correct bucket: imports, exports, locals
2422 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
2423 switch ( atom->getDefinitionKind() ) {
2424 case ObjectFile::Atom::kExternalDefinition:
2425 case ObjectFile::Atom::kExternalWeakDefinition:
2426 fImportedAtoms.push_back(atom);
2427 break;
2428 case ObjectFile::Atom::kTentativeDefinition:
2429 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
2430 fImportedAtoms.push_back(atom);
2431 break;
2432 }
2433 // else fall into
2434 case ObjectFile::Atom::kRegularDefinition:
2435 case ObjectFile::Atom::kWeakDefinition:
2436 case ObjectFile::Atom::kAbsoluteSymbol:
2437 if ( this->shouldExport(*atom) )
2438 fExportedAtoms.push_back(atom);
2439 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
2440 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
2441 fLocalSymbolAtoms.push_back(atom);
2442 break;
2443 }
2444 }
2445 // when geneating a .o file, dtrace static probes become local labels
2446 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
2447 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2448 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2449 ObjectFile::Reference* ref = *rit;
2450 if ( ref->getKind() == A::kDtraceProbe ) {
2451 // dtrace probe points to be add back into generated .o file
2452 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
2453 }
2454 }
2455 }
2456 // when linking kernel, old style dtrace static probes become global labels
2457 else if ( fOptions.readerOptions().fForStatic ) {
2458 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
2459 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
2460 ObjectFile::Reference* ref = *rit;
2461 if ( ref->getKind() == A::kDtraceProbe ) {
2462 // dtrace probe points to be add back into generated .o file
2463 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
2464 }
2465 }
2466 }
2467 }
2468
2469 // sort exported atoms by name
2470 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
2471 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
2472 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
2473 }
2474
2475
2476 template <typename A>
2477 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
2478 {
2479 switch ( stab.type ) {
2480 case N_FUN:
2481 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
2482 // end of function N_FUN has size
2483 return stab.atom->getSize();
2484 }
2485 else {
2486 // start of function N_FUN has address
2487 return getAtomLoadAddress(stab.atom);
2488 }
2489 case N_LBRAC:
2490 case N_RBRAC:
2491 case N_SLINE:
2492 if ( stab.atom == NULL )
2493 // some weird assembly files have slines not associated with a function
2494 return stab.value;
2495 else
2496 // all these stab types need their value changed from an offset in the atom to an address
2497 return getAtomLoadAddress(stab.atom) + stab.value;
2498 case N_STSYM:
2499 case N_LCSYM:
2500 case N_BNSYM:
2501 // all these need address of atom
2502 return getAtomLoadAddress(stab.atom);;
2503 case N_ENSYM:
2504 return stab.atom->getSize();
2505 case N_SO:
2506 if ( stab.atom == NULL ) {
2507 return 0;
2508 }
2509 else {
2510 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
2511 // end of translation unit N_SO has address of end of last atom
2512 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
2513 }
2514 else {
2515 // start of translation unit N_SO has address of end of first atom
2516 return getAtomLoadAddress(stab.atom);
2517 }
2518 }
2519 break;
2520 default:
2521 return stab.value;
2522 }
2523 }
2524
2525 template <typename A>
2526 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
2527 {
2528 switch (stab.type) {
2529 case N_SO:
2530 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
2531 return this->fStringsAtom->emptyString();
2532 break;
2533 }
2534 // fall into uniquing case
2535 case N_SOL:
2536 case N_BINCL:
2537 case N_EXCL:
2538 return this->fStringsAtom->addUnique(stab.string);
2539 break;
2540 default:
2541 if ( stab.string == NULL )
2542 return 0;
2543 else if ( stab.string[0] == '\0' )
2544 return this->fStringsAtom->emptyString();
2545 else
2546 return this->fStringsAtom->add(stab.string);
2547 }
2548 return 0;
2549 }
2550
2551 template <typename A>
2552 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
2553 {
2554 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
2555 if ( stab.type == N_FUN )
2556 return stab.other;
2557 else if ( stab.atom != NULL )
2558 return stab.atom->getSection()->getIndex();
2559 else
2560 return stab.other;
2561 }
2562
2563 template <typename A>
2564 void Writer<A>::addStabs(uint32_t startIndex)
2565 {
2566 macho_nlist<P>* entry = &fSymbolTable[startIndex];
2567 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
2568 const ObjectFile::Reader::Stab& stab = *it;
2569 entry->set_n_type(stab.type);
2570 entry->set_n_sect(sectionIndexForStab(stab));
2571 entry->set_n_desc(stab.desc);
2572 entry->set_n_value(valueForStab(stab));
2573 entry->set_n_strx(stringOffsetForStab(stab));
2574 }
2575 }
2576
2577
2578
2579 template <typename A>
2580 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
2581 {
2582 // search imports
2583 int i = 0;
2584 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
2585 if ( &atom == *it )
2586 return i + fSymbolTableImportStartIndex;
2587 ++i;
2588 }
2589
2590 // search locals
2591 i = 0;
2592 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
2593 if ( &atom == *it )
2594 return i + fSymbolTableLocalStartIndex;
2595 ++i;
2596 }
2597
2598 // search exports
2599 i = 0;
2600 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
2601 if ( &atom == *it )
2602 return i + fSymbolTableExportStartIndex;
2603 ++i;
2604 }
2605
2606 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
2607 }
2608
2609
2610 template <>
2611 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
2612 {
2613 switch ( target.getSymbolTableInclusion() ) {
2614 case ObjectFile::Atom::kSymbolTableNotIn:
2615 return false;
2616 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
2617 case ObjectFile::Atom::kSymbolTableIn:
2618 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
2619 return true;
2620 };
2621 return false;
2622 }
2623
2624 template <typename A>
2625 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
2626 {
2627 switch ( target.getDefinitionKind() ) {
2628 case ObjectFile::Atom::kRegularDefinition:
2629 case ObjectFile::Atom::kWeakDefinition:
2630 case ObjectFile::Atom::kAbsoluteSymbol:
2631 return false;
2632 case ObjectFile::Atom::kTentativeDefinition:
2633 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
2634 return false;
2635 else
2636 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
2637 case ObjectFile::Atom::kExternalDefinition:
2638 case ObjectFile::Atom::kExternalWeakDefinition:
2639 return shouldExport(target);
2640 }
2641 return false;
2642 }
2643
2644 template <typename A>
2645 void Writer<A>::buildFixups()
2646 {
2647 if ( fOptions.outputKind() == Options::kObjectFile ) {
2648 this->buildObjectFileFixups();
2649 }
2650 else {
2651 if ( fOptions.keepRelocations() )
2652 this->buildObjectFileFixups();
2653 this->buildExecutableFixups();
2654 }
2655 }
2656
2657 template <>
2658 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2659 {
2660 ObjectFile::Atom& target = ref->getTarget();
2661 bool external = this->makesExternalRelocatableReference(target);
2662 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
2663 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2664 macho_relocation_info<P> reloc1;
2665 macho_relocation_info<P> reloc2;
2666 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
2667
2668 switch ( kind ) {
2669 case x86_64::kNoFixUp:
2670 case x86_64::kFollowOn:
2671 case x86_64::kGroupSubordinate:
2672 return 0;
2673
2674 case x86_64::kPointer:
2675 case x86_64::kPointerWeakImport:
2676 reloc1.set_r_address(address);
2677 reloc1.set_r_symbolnum(symbolIndex);
2678 reloc1.set_r_pcrel(false);
2679 reloc1.set_r_length(3);
2680 reloc1.set_r_extern(external);
2681 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2682 fSectionRelocs.push_back(reloc1);
2683 return 1;
2684
2685 case x86_64::kPointerDiff32:
2686 case x86_64::kPointerDiff:
2687 {
2688 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2689 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2690 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
2691 reloc1.set_r_address(address);
2692 reloc1.set_r_symbolnum(symbolIndex);
2693 reloc1.set_r_pcrel(false);
2694 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2695 reloc1.set_r_extern(external);
2696 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2697 reloc2.set_r_address(address);
2698 reloc2.set_r_symbolnum(fromSymbolIndex);
2699 reloc2.set_r_pcrel(false);
2700 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2701 reloc2.set_r_extern(fromExternal);
2702 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
2703 fSectionRelocs.push_back(reloc1);
2704 fSectionRelocs.push_back(reloc2);
2705 return 2;
2706 }
2707
2708 case x86_64::kBranchPCRel32:
2709 case x86_64::kBranchPCRel32WeakImport:
2710 case x86_64::kDtraceProbeSite:
2711 case x86_64::kDtraceIsEnabledSite:
2712 reloc1.set_r_address(address);
2713 reloc1.set_r_symbolnum(symbolIndex);
2714 reloc1.set_r_pcrel(true);
2715 reloc1.set_r_length(2);
2716 reloc1.set_r_extern(external);
2717 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2718 fSectionRelocs.push_back(reloc1);
2719 return 1;
2720
2721 case x86_64::kPCRel32:
2722 reloc1.set_r_address(address);
2723 reloc1.set_r_symbolnum(symbolIndex);
2724 reloc1.set_r_pcrel(true);
2725 reloc1.set_r_length(2);
2726 reloc1.set_r_extern(external);
2727 reloc1.set_r_type(X86_64_RELOC_SIGNED);
2728 fSectionRelocs.push_back(reloc1);
2729 return 1;
2730
2731 case x86_64::kPCRel32_1:
2732 reloc1.set_r_address(address);
2733 reloc1.set_r_symbolnum(symbolIndex);
2734 reloc1.set_r_pcrel(true);
2735 reloc1.set_r_length(2);
2736 reloc1.set_r_extern(external);
2737 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
2738 fSectionRelocs.push_back(reloc1);
2739 return 1;
2740
2741 case x86_64::kPCRel32_2:
2742 reloc1.set_r_address(address);
2743 reloc1.set_r_symbolnum(symbolIndex);
2744 reloc1.set_r_pcrel(true);
2745 reloc1.set_r_length(2);
2746 reloc1.set_r_extern(external);
2747 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
2748 fSectionRelocs.push_back(reloc1);
2749 return 1;
2750
2751 case x86_64::kPCRel32_4:
2752 reloc1.set_r_address(address);
2753 reloc1.set_r_symbolnum(symbolIndex);
2754 reloc1.set_r_pcrel(true);
2755 reloc1.set_r_length(2);
2756 reloc1.set_r_extern(external);
2757 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
2758 fSectionRelocs.push_back(reloc1);
2759 return 1;
2760
2761 case x86_64::kBranchPCRel8:
2762 reloc1.set_r_address(address);
2763 reloc1.set_r_symbolnum(symbolIndex);
2764 reloc1.set_r_pcrel(true);
2765 reloc1.set_r_length(0);
2766 reloc1.set_r_extern(external);
2767 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2768 fSectionRelocs.push_back(reloc1);
2769 return 1;
2770
2771 case x86_64::kPCRel32GOT:
2772 case x86_64::kPCRel32GOTWeakImport:
2773 reloc1.set_r_address(address);
2774 reloc1.set_r_symbolnum(symbolIndex);
2775 reloc1.set_r_pcrel(true);
2776 reloc1.set_r_length(2);
2777 reloc1.set_r_extern(external);
2778 reloc1.set_r_type(X86_64_RELOC_GOT);
2779 fSectionRelocs.push_back(reloc1);
2780 return 1;
2781
2782 case x86_64::kPCRel32GOTLoad:
2783 case x86_64::kPCRel32GOTLoadWeakImport:
2784 reloc1.set_r_address(address);
2785 reloc1.set_r_symbolnum(symbolIndex);
2786 reloc1.set_r_pcrel(true);
2787 reloc1.set_r_length(2);
2788 reloc1.set_r_extern(external);
2789 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
2790 fSectionRelocs.push_back(reloc1);
2791 return 1;
2792
2793 case x86_64::kDtraceTypeReference:
2794 case x86_64::kDtraceProbe:
2795 // generates no relocs
2796 return 0;
2797 }
2798 return 0;
2799 }
2800
2801
2802 template <>
2803 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2804 {
2805 ObjectFile::Atom& target = ref->getTarget();
2806 bool isExtern = this->makesExternalRelocatableReference(target);
2807 uint32_t symbolIndex = 0;
2808 if ( isExtern )
2809 symbolIndex = this->symbolIndex(target);
2810 uint32_t sectionNum = target.getSection()->getIndex();
2811 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2812 macho_relocation_info<P> reloc1;
2813 macho_relocation_info<P> reloc2;
2814 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2815 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2816 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
2817
2818 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2819 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
2820 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2821
2822
2823 switch ( kind ) {
2824 case x86::kNoFixUp:
2825 case x86::kFollowOn:
2826 case x86::kGroupSubordinate:
2827 return 0;
2828
2829 case x86::kPointer:
2830 case x86::kPointerWeakImport:
2831 case x86::kAbsolute32:
2832 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2833 // use scattered reloc is target offset is non-zero
2834 sreloc1->set_r_scattered(true);
2835 sreloc1->set_r_pcrel(false);
2836 sreloc1->set_r_length(2);
2837 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2838 sreloc1->set_r_address(address);
2839 sreloc1->set_r_value(target.getAddress());
2840 }
2841 else {
2842 reloc1.set_r_address(address);
2843 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2844 reloc1.set_r_pcrel(false);
2845 reloc1.set_r_length(2);
2846 reloc1.set_r_extern(isExtern);
2847 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2848 }
2849 fSectionRelocs.push_back(reloc1);
2850 return 1;
2851
2852 case x86::kPointerDiff16:
2853 case x86::kPointerDiff:
2854 {
2855 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2856 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
2857 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
2858 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
2859 sreloc1->set_r_scattered(true);
2860 sreloc1->set_r_pcrel(false);
2861 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2862 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2863 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
2864 else
2865 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
2866 sreloc1->set_r_address(address);
2867 sreloc1->set_r_value(target.getAddress());
2868 sreloc2->set_r_scattered(true);
2869 sreloc2->set_r_pcrel(false);
2870 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2871 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
2872 sreloc2->set_r_address(0);
2873 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
2874 fSectionRelocs.push_back(reloc2);
2875 fSectionRelocs.push_back(reloc1);
2876 return 2;
2877 }
2878
2879 case x86::kPCRel32WeakImport:
2880 case x86::kPCRel32:
2881 case x86::kPCRel16:
2882 case x86::kPCRel8:
2883 case x86::kDtraceProbeSite:
2884 case x86::kDtraceIsEnabledSite:
2885 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2886 // use scattered reloc is target offset is non-zero
2887 sreloc1->set_r_scattered(true);
2888 sreloc1->set_r_pcrel(true);
2889 sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
2890 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2891 sreloc1->set_r_address(address);
2892 sreloc1->set_r_value(target.getAddress());
2893 }
2894 else {
2895 reloc1.set_r_address(address);
2896 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2897 reloc1.set_r_pcrel(true);
2898 reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
2899 reloc1.set_r_extern(isExtern);
2900 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2901 }
2902 fSectionRelocs.push_back(reloc1);
2903 return 1;
2904
2905 case x86::kDtraceTypeReference:
2906 case x86::kDtraceProbe:
2907 // generates no relocs
2908 return 0;
2909
2910 }
2911 return 0;
2912 }
2913
2914 template <>
2915 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2916 {
2917 ObjectFile::Atom& target = ref->getTarget();
2918 bool isExtern = this->makesExternalRelocatableReference(target);
2919 uint32_t symbolIndex = 0;
2920 if ( isExtern )
2921 symbolIndex = this->symbolIndex(target);
2922 uint32_t sectionNum = target.getSection()->getIndex();
2923 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2924 macho_relocation_info<P> reloc1;
2925 macho_relocation_info<P> reloc2;
2926 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2927 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2928 arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
2929
2930 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2931 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
2932 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2933
2934
2935 switch ( kind ) {
2936 case arm::kNoFixUp:
2937 case arm::kFollowOn:
2938 case arm::kGroupSubordinate:
2939 return 0;
2940
2941 case arm::kPointer:
2942 case arm::kReadOnlyPointer:
2943 case arm::kPointerWeakImport:
2944 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2945 // use scattered reloc is target offset is non-zero
2946 sreloc1->set_r_scattered(true);
2947 sreloc1->set_r_pcrel(false);
2948 sreloc1->set_r_length(2);
2949 sreloc1->set_r_type(ARM_RELOC_VANILLA);
2950 sreloc1->set_r_address(address);
2951 sreloc1->set_r_value(target.getAddress());
2952 }
2953 else {
2954 reloc1.set_r_address(address);
2955 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2956 reloc1.set_r_pcrel(false);
2957 reloc1.set_r_length(2);
2958 reloc1.set_r_extern(isExtern);
2959 reloc1.set_r_type(ARM_RELOC_VANILLA);
2960 }
2961 fSectionRelocs.push_back(reloc1);
2962 return 1;
2963
2964 case arm::kPointerDiff:
2965 {
2966 sreloc1->set_r_scattered(true);
2967 sreloc1->set_r_pcrel(false);
2968 sreloc1->set_r_length(2);
2969 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2970 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
2971 else
2972 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
2973 sreloc1->set_r_address(address);
2974 sreloc1->set_r_value(target.getAddress());
2975 sreloc2->set_r_scattered(true);
2976 sreloc2->set_r_pcrel(false);
2977 sreloc2->set_r_length(2);
2978 sreloc2->set_r_type(ARM_RELOC_PAIR);
2979 sreloc2->set_r_address(0);
2980 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
2981 fSectionRelocs.push_back(reloc2);
2982 fSectionRelocs.push_back(reloc1);
2983 return 2;
2984 }
2985
2986 case arm::kBranch24WeakImport:
2987 case arm::kBranch24:
2988 case arm::kDtraceProbeSite:
2989 case arm::kDtraceIsEnabledSite:
2990 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2991 // use scattered reloc is target offset is non-zero
2992 sreloc1->set_r_scattered(true);
2993 sreloc1->set_r_pcrel(true);
2994 sreloc1->set_r_length(2);
2995 sreloc1->set_r_type(ARM_RELOC_BR24);
2996 sreloc1->set_r_address(address);
2997 sreloc1->set_r_value(target.getAddress());
2998 }
2999 else {
3000 reloc1.set_r_address(address);
3001 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3002 reloc1.set_r_pcrel(true);
3003 reloc1.set_r_length(2);
3004 reloc1.set_r_extern(isExtern);
3005 reloc1.set_r_type(ARM_RELOC_BR24);
3006 }
3007 fSectionRelocs.push_back(reloc1);
3008 return 1;
3009
3010 case arm::kThumbBranch22WeakImport:
3011 case arm::kThumbBranch22:
3012 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
3013 // use scattered reloc is target offset is non-zero
3014 sreloc1->set_r_scattered(true);
3015 sreloc1->set_r_pcrel(true);
3016 sreloc1->set_r_length(2);
3017 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
3018 sreloc1->set_r_address(address);
3019 sreloc1->set_r_value(target.getAddress());
3020 }
3021 else {
3022 reloc1.set_r_address(address);
3023 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3024 reloc1.set_r_pcrel(true);
3025 reloc1.set_r_length(2);
3026 reloc1.set_r_extern(isExtern);
3027 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
3028 }
3029 fSectionRelocs.push_back(reloc1);
3030 return 1;
3031
3032 case arm::kDtraceTypeReference:
3033 case arm::kDtraceProbe:
3034 // generates no relocs
3035 return 0;
3036
3037 }
3038 return 0;
3039 }
3040
3041 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
3042 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
3043 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
3044 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
3045 template <> uint64_t Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
3046
3047 template <>
3048 uint8_t Writer<ppc>::getRelocPointerSize()
3049 {
3050 return 2;
3051 }
3052
3053 template <>
3054 uint8_t Writer<ppc64>::getRelocPointerSize()
3055 {
3056 return 3;
3057 }
3058
3059 template <>
3060 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3061 {
3062 return addObjectRelocs_powerpc(atom, ref);
3063 }
3064
3065 template <>
3066 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3067 {
3068 return addObjectRelocs_powerpc(atom, ref);
3069 }
3070
3071 //
3072 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
3073 // they use a common addObjectRelocs_powerpc() method.
3074 //
3075 template <typename A>
3076 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3077 {
3078 ObjectFile::Atom& target = ref->getTarget();
3079 bool isExtern = this->makesExternalRelocatableReference(target);
3080 uint32_t symbolIndex = 0;
3081 if ( isExtern )
3082 symbolIndex = this->symbolIndex(target);
3083 uint32_t sectionNum = target.getSection()->getIndex();
3084 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3085 macho_relocation_info<P> reloc1;
3086 macho_relocation_info<P> reloc2;
3087 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
3088 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
3089 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
3090
3091 switch ( kind ) {
3092 case A::kNoFixUp:
3093 case A::kFollowOn:
3094 case A::kGroupSubordinate:
3095 return 0;
3096
3097 case A::kPointer:
3098 case A::kPointerWeakImport:
3099 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
3100 // use scattered reloc is target offset is outside target
3101 sreloc1->set_r_scattered(true);
3102 sreloc1->set_r_pcrel(false);
3103 sreloc1->set_r_length(getRelocPointerSize());
3104 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
3105 sreloc1->set_r_address(address);
3106 sreloc1->set_r_value(target.getAddress());
3107 }
3108 else {
3109 reloc1.set_r_address(address);
3110 if ( isExtern )
3111 reloc1.set_r_symbolnum(symbolIndex);
3112 else
3113 reloc1.set_r_symbolnum(sectionNum);
3114 reloc1.set_r_pcrel(false);
3115 reloc1.set_r_length(getRelocPointerSize());
3116 reloc1.set_r_extern(isExtern);
3117 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3118 }
3119 fSectionRelocs.push_back(reloc1);
3120 return 1;
3121
3122 case A::kPointerDiff16:
3123 case A::kPointerDiff32:
3124 case A::kPointerDiff64:
3125 {
3126 sreloc1->set_r_scattered(true);
3127 sreloc1->set_r_pcrel(false);
3128 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
3129 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
3130 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
3131 else
3132 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
3133 sreloc1->set_r_address(address);
3134 sreloc1->set_r_value(target.getAddress());
3135 sreloc2->set_r_scattered(true);
3136 sreloc2->set_r_pcrel(false);
3137 sreloc2->set_r_length(sreloc1->r_length());
3138 sreloc2->set_r_type(PPC_RELOC_PAIR);
3139 sreloc2->set_r_address(0);
3140 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
3141 fSectionRelocs.push_back(reloc2);
3142 fSectionRelocs.push_back(reloc1);
3143 return 2;
3144 }
3145
3146 case A::kBranch24WeakImport:
3147 case A::kBranch24:
3148 case A::kDtraceProbeSite:
3149 case A::kDtraceIsEnabledSite:
3150 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3151 reloc1.set_r_address(address);
3152 if ( isExtern )
3153 reloc1.set_r_symbolnum(symbolIndex);
3154 else
3155 reloc1.set_r_symbolnum(sectionNum);
3156 reloc1.set_r_pcrel(true);
3157 reloc1.set_r_length(2);
3158 reloc1.set_r_type(PPC_RELOC_BR24);
3159 reloc1.set_r_extern(isExtern);
3160 }
3161 else {
3162 sreloc1->set_r_scattered(true);
3163 sreloc1->set_r_pcrel(true);
3164 sreloc1->set_r_length(2);
3165 sreloc1->set_r_type(PPC_RELOC_BR24);
3166 sreloc1->set_r_address(address);
3167 sreloc1->set_r_value(target.getAddress());
3168 }
3169 fSectionRelocs.push_back(reloc1);
3170 return 1;
3171
3172 case A::kBranch14:
3173 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3174 reloc1.set_r_address(address);
3175 if ( isExtern )
3176 reloc1.set_r_symbolnum(symbolIndex);
3177 else
3178 reloc1.set_r_symbolnum(sectionNum);
3179 reloc1.set_r_pcrel(true);
3180 reloc1.set_r_length(2);
3181 reloc1.set_r_type(PPC_RELOC_BR14);
3182 reloc1.set_r_extern(isExtern);
3183 }
3184 else {
3185 sreloc1->set_r_scattered(true);
3186 sreloc1->set_r_pcrel(true);
3187 sreloc1->set_r_length(2);
3188 sreloc1->set_r_type(PPC_RELOC_BR14);
3189 sreloc1->set_r_address(address);
3190 sreloc1->set_r_value(target.getAddress());
3191 }
3192 fSectionRelocs.push_back(reloc1);
3193 return 1;
3194
3195 case A::kPICBaseLow16:
3196 case A::kPICBaseLow14:
3197 {
3198 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
3199 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3200 sreloc1->set_r_scattered(true);
3201 sreloc1->set_r_pcrel(false);
3202 sreloc1->set_r_length(2);
3203 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
3204 sreloc1->set_r_address(address);
3205 sreloc1->set_r_value(target.getAddress());
3206 sreloc2->set_r_scattered(true);
3207 sreloc2->set_r_pcrel(false);
3208 sreloc2->set_r_length(2);
3209 sreloc2->set_r_type(PPC_RELOC_PAIR);
3210 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
3211 sreloc2->set_r_value(fromAddr);
3212 fSectionRelocs.push_back(reloc2);
3213 fSectionRelocs.push_back(reloc1);
3214 return 2;
3215 }
3216
3217 case A::kPICBaseHigh16:
3218 {
3219 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
3220 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3221 sreloc1->set_r_scattered(true);
3222 sreloc1->set_r_pcrel(false);
3223 sreloc1->set_r_length(2);
3224 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
3225 sreloc1->set_r_address(address);
3226 sreloc1->set_r_value(target.getAddress());
3227 sreloc2->set_r_scattered(true);
3228 sreloc2->set_r_pcrel(false);
3229 sreloc2->set_r_length(2);
3230 sreloc2->set_r_type(PPC_RELOC_PAIR);
3231 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
3232 sreloc2->set_r_value(fromAddr);
3233 fSectionRelocs.push_back(reloc2);
3234 fSectionRelocs.push_back(reloc1);
3235 return 2;
3236 }
3237
3238 case A::kAbsLow14:
3239 case A::kAbsLow16:
3240 {
3241 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3242 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3243 reloc1.set_r_address(address);
3244 if ( isExtern )
3245 reloc1.set_r_symbolnum(symbolIndex);
3246 else
3247 reloc1.set_r_symbolnum(sectionNum);
3248 reloc1.set_r_pcrel(false);
3249 reloc1.set_r_length(2);
3250 reloc1.set_r_extern(isExtern);
3251 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
3252 }
3253 else {
3254 sreloc1->set_r_scattered(true);
3255 sreloc1->set_r_pcrel(false);
3256 sreloc1->set_r_length(2);
3257 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
3258 sreloc1->set_r_address(address);
3259 sreloc1->set_r_value(target.getAddress());
3260 }
3261 if ( isExtern )
3262 reloc2.set_r_address(ref->getTargetOffset() >> 16);
3263 else
3264 reloc2.set_r_address(toAddr >> 16);
3265 reloc2.set_r_symbolnum(0);
3266 reloc2.set_r_pcrel(false);
3267 reloc2.set_r_length(2);
3268 reloc2.set_r_extern(false);
3269 reloc2.set_r_type(PPC_RELOC_PAIR);
3270 fSectionRelocs.push_back(reloc2);
3271 fSectionRelocs.push_back(reloc1);
3272 return 2;
3273 }
3274
3275 case A::kAbsHigh16:
3276 {
3277 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3278 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3279 reloc1.set_r_address(address);
3280 if ( isExtern )
3281 reloc1.set_r_symbolnum(symbolIndex);
3282 else
3283 reloc1.set_r_symbolnum(sectionNum);
3284 reloc1.set_r_pcrel(false);
3285 reloc1.set_r_length(2);
3286 reloc1.set_r_extern(isExtern);
3287 reloc1.set_r_type(PPC_RELOC_HI16);
3288 }
3289 else {
3290 sreloc1->set_r_scattered(true);
3291 sreloc1->set_r_pcrel(false);
3292 sreloc1->set_r_length(2);
3293 sreloc1->set_r_type(PPC_RELOC_HI16);
3294 sreloc1->set_r_address(address);
3295 sreloc1->set_r_value(target.getAddress());
3296 }
3297 if ( isExtern )
3298 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
3299 else
3300 reloc2.set_r_address(toAddr & 0xFFFF);
3301 reloc2.set_r_symbolnum(0);
3302 reloc2.set_r_pcrel(false);
3303 reloc2.set_r_length(2);
3304 reloc2.set_r_extern(false);
3305 reloc2.set_r_type(PPC_RELOC_PAIR);
3306 fSectionRelocs.push_back(reloc2);
3307 fSectionRelocs.push_back(reloc1);
3308 return 2;
3309 }
3310
3311 case A::kAbsHigh16AddLow:
3312 {
3313 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
3314 uint32_t overflow = 0;
3315 if ( (toAddr & 0x00008000) != 0 )
3316 overflow = 0x10000;
3317 if ( (ref->getTargetOffset() == 0) || isExtern ) {
3318 reloc1.set_r_address(address);
3319 if ( isExtern )
3320 reloc1.set_r_symbolnum(symbolIndex);
3321 else
3322 reloc1.set_r_symbolnum(sectionNum);
3323 reloc1.set_r_pcrel(false);
3324 reloc1.set_r_length(2);
3325 reloc1.set_r_extern(isExtern);
3326 reloc1.set_r_type(PPC_RELOC_HA16);
3327 }
3328 else {
3329 sreloc1->set_r_scattered(true);
3330 sreloc1->set_r_pcrel(false);
3331 sreloc1->set_r_length(2);
3332 sreloc1->set_r_type(PPC_RELOC_HA16);
3333 sreloc1->set_r_address(address);
3334 sreloc1->set_r_value(target.getAddress());
3335 }
3336 if ( isExtern )
3337 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
3338 else
3339 reloc2.set_r_address(toAddr & 0xFFFF);
3340 reloc2.set_r_symbolnum(0);
3341 reloc2.set_r_pcrel(false);
3342 reloc2.set_r_length(2);
3343 reloc2.set_r_extern(false);
3344 reloc2.set_r_type(PPC_RELOC_PAIR);
3345 fSectionRelocs.push_back(reloc2);
3346 fSectionRelocs.push_back(reloc1);
3347 return 2;
3348 }
3349
3350 case A::kDtraceTypeReference:
3351 case A::kDtraceProbe:
3352 // generates no relocs
3353 return 0;
3354 }
3355 return 0;
3356 }
3357
3358
3359
3360 //
3361 // There are cases when an entry in the indirect symbol table is the magic value
3362 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
3363 // the content of the corresponding part of the __nl_symbol_pointer section
3364 // must also change.
3365 //
3366 template <typename A>
3367 bool Writer<A>::indirectSymbolIsLocal(const ObjectFile::Reference* ref) const
3368 {
3369 // use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3370 return ( !this->shouldExport(ref->getTarget()) || (ref->getTargetOffset() != 0) );
3371 }
3372
3373
3374 template <typename A>
3375 void Writer<A>::buildObjectFileFixups()
3376 {
3377 uint32_t relocIndex = 0;
3378 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3379 const int segCount = segmentInfos.size();
3380 for(int i=0; i < segCount; ++i) {
3381 SegmentInfo* curSegment = segmentInfos[i];
3382 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3383 const int sectionCount = sectionInfos.size();
3384 for(int j=0; j < sectionCount; ++j) {
3385 SectionInfo* curSection = sectionInfos[j];
3386 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
3387 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3388 if ( ! curSection->fAllZeroFill ) {
3389 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
3390 || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
3391 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3392 curSection->fRelocOffset = relocIndex;
3393 const int atomCount = sectionAtoms.size();
3394 for (int k=0; k < atomCount; ++k) {
3395 ObjectFile::Atom* atom = sectionAtoms[k];
3396 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
3397 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3398 const int refCount = refs.size();
3399 for (int l=0; l < refCount; ++l) {
3400 ObjectFile::Reference* ref = refs[l];
3401 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
3402 || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
3403 uint32_t offsetInSection = atom->getSectionOffset();
3404 uint32_t indexInSection = offsetInSection / atom->getSize();
3405 uint32_t undefinedSymbolIndex;
3406 if ( curSection->fAllStubs ) {
3407 ObjectFile::Atom& stubTarget =ref->getTarget();
3408 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
3409 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
3410 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
3411 }
3412 else if ( curSection->fAllNonLazyPointers) {
3413 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3414 if ( this->indirectSymbolIsLocal(ref) )
3415 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3416 else
3417 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
3418 }
3419 else {
3420 // should never get here, fAllLazyPointers not used in generated .o files
3421 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3422 }
3423 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3424 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3425 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
3426 fIndirectTableAtom->fTable.push_back(entry);
3427 if ( curSection->fAllLazyPointers ) {
3428 ObjectFile::Atom& target = ref->getTarget();
3429 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3430 if ( &fromTarget == NULL ) {
3431 warning("lazy pointer %s missing initial binding", atom->getDisplayName());
3432 }
3433 else {
3434 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3435 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
3436 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
3437 macho_relocation_info<P> reloc1;
3438 reloc1.set_r_address(atom->getSectionOffset());
3439 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
3440 reloc1.set_r_pcrel(false);
3441 reloc1.set_r_length();
3442 reloc1.set_r_extern(isExtern);
3443 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3444 fSectionRelocs.push_back(reloc1);
3445 ++relocIndex;
3446 }
3447 }
3448 else if ( curSection->fAllStubs ) {
3449 relocIndex += this->addObjectRelocs(atom, ref);
3450 }
3451 }
3452 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
3453 relocIndex += this->addObjectRelocs(atom, ref);
3454 }
3455 }
3456 }
3457 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
3458 }
3459 }
3460 }
3461
3462 // reverse the relocs
3463 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
3464
3465 // now reverse section reloc offsets
3466 for(int i=0; i < segCount; ++i) {
3467 SegmentInfo* curSegment = segmentInfos[i];
3468 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3469 const int sectionCount = sectionInfos.size();
3470 for(int j=0; j < sectionCount; ++j) {
3471 SectionInfo* curSection = sectionInfos[j];
3472 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
3473 }
3474 }
3475
3476 }
3477
3478 template <>
3479 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3480 {
3481 switch ( ref.getKind() ) {
3482 case ppc::kAbsLow16:
3483 case ppc::kAbsLow14:
3484 case ppc::kAbsHigh16:
3485 case ppc::kAbsHigh16AddLow:
3486 if ( fSlideable )
3487 return true;
3488 }
3489 return false;
3490 }
3491
3492
3493 template <>
3494 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3495 {
3496 switch ( ref.getKind() ) {
3497 case ppc::kAbsLow16:
3498 case ppc::kAbsLow14:
3499 case ppc::kAbsHigh16:
3500 case ppc::kAbsHigh16AddLow:
3501 if ( fSlideable )
3502 return true;
3503 }
3504 return false;
3505 }
3506
3507 template <>
3508 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3509 {
3510 if ( ref.getKind() == x86::kAbsolute32 ) {
3511 switch ( ref.getTarget().getDefinitionKind() ) {
3512 case ObjectFile::Atom::kTentativeDefinition:
3513 case ObjectFile::Atom::kRegularDefinition:
3514 case ObjectFile::Atom::kWeakDefinition:
3515 // illegal in dylibs/bundles, until we support TEXT relocs
3516 return fSlideable;
3517 case ObjectFile::Atom::kExternalDefinition:
3518 case ObjectFile::Atom::kExternalWeakDefinition:
3519 // illegal until we support TEXT relocs
3520 return true;
3521 case ObjectFile::Atom::kAbsoluteSymbol:
3522 // absolute symbbols only allowed in static executables
3523 return ( fOptions.outputKind() != Options::kStaticExecutable);
3524 }
3525 }
3526 return false;
3527 }
3528
3529 template <>
3530 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3531 {
3532 return false;
3533 }
3534
3535 template <>
3536 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3537 {
3538 if ( ref.getKind() == arm::kReadOnlyPointer ) {
3539 switch ( ref.getTarget().getDefinitionKind() ) {
3540 case ObjectFile::Atom::kTentativeDefinition:
3541 case ObjectFile::Atom::kRegularDefinition:
3542 case ObjectFile::Atom::kWeakDefinition:
3543 // illegal in dylibs/bundles, until we support TEXT relocs
3544 return fSlideable;
3545 case ObjectFile::Atom::kExternalDefinition:
3546 case ObjectFile::Atom::kExternalWeakDefinition:
3547 // illegal until we support TEXT relocs
3548 return true;
3549 case ObjectFile::Atom::kAbsoluteSymbol:
3550 // absolute symbbols only allowed in static executables
3551 return ( fOptions.outputKind() != Options::kStaticExecutable);
3552 }
3553 }
3554 return false;
3555 }
3556
3557 template <>
3558 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3559 {
3560 if ( ref.getKind() == x86::kAbsolute32 ) {
3561 switch ( ref.getTarget().getDefinitionKind() ) {
3562 case ObjectFile::Atom::kTentativeDefinition:
3563 case ObjectFile::Atom::kRegularDefinition:
3564 case ObjectFile::Atom::kWeakDefinition:
3565 // a reference to the absolute address of something in this same linkage unit can be
3566 // encoded as a local text reloc in a dylib or bundle
3567 if ( fSlideable ) {
3568 macho_relocation_info<P> reloc;
3569 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3570 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3571 reloc.set_r_symbolnum(sectInfo->getIndex());
3572 reloc.set_r_pcrel(false);
3573 reloc.set_r_length();
3574 reloc.set_r_extern(false);
3575 reloc.set_r_type(GENERIC_RELOC_VANILLA);
3576 fInternalRelocs.push_back(reloc);
3577 atomSection->fHasTextLocalRelocs = true;
3578 return true;
3579 }
3580 return false;
3581 case ObjectFile::Atom::kExternalDefinition:
3582 case ObjectFile::Atom::kExternalWeakDefinition:
3583 case ObjectFile::Atom::kAbsoluteSymbol:
3584 return false;
3585 }
3586 }
3587 return false;
3588 }
3589
3590 template <>
3591 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3592 {
3593 macho_relocation_info<P> reloc1;
3594 macho_relocation_info<P> reloc2;
3595 switch ( ref.getTarget().getDefinitionKind() ) {
3596 case ObjectFile::Atom::kTentativeDefinition:
3597 case ObjectFile::Atom::kRegularDefinition:
3598 case ObjectFile::Atom::kWeakDefinition:
3599 switch ( ref.getKind() ) {
3600 case ppc::kAbsLow16:
3601 case ppc::kAbsLow14:
3602 // a reference to the absolute address of something in this same linkage unit can be
3603 // encoded as a local text reloc in a dylib or bundle
3604 if ( fSlideable ) {
3605 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3606 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
3607 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3608 reloc1.set_r_symbolnum(sectInfo->getIndex());
3609 reloc1.set_r_pcrel(false);
3610 reloc1.set_r_length(2);
3611 reloc1.set_r_extern(false);
3612 reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
3613 reloc2.set_r_address(targetAddr >> 16);
3614 reloc2.set_r_symbolnum(0);
3615 reloc2.set_r_pcrel(false);
3616 reloc2.set_r_length(2);
3617 reloc2.set_r_extern(false);
3618 reloc2.set_r_type(PPC_RELOC_PAIR);
3619 fInternalRelocs.push_back(reloc1);
3620 fInternalRelocs.push_back(reloc2);
3621 atomSection->fHasTextLocalRelocs = true;
3622 return true;
3623 }
3624 break;
3625 case ppc::kAbsHigh16:
3626 case ppc::kAbsHigh16AddLow:
3627 if ( fSlideable ) {
3628 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3629 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
3630 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3631 reloc1.set_r_symbolnum(sectInfo->getIndex());
3632 reloc1.set_r_pcrel(false);
3633 reloc1.set_r_length(2);
3634 reloc1.set_r_extern(false);
3635 reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
3636 reloc2.set_r_address(targetAddr & 0xFFFF);
3637 reloc2.set_r_symbolnum(0);
3638 reloc2.set_r_pcrel(false);
3639 reloc2.set_r_length(2);
3640 reloc2.set_r_extern(false);
3641 reloc2.set_r_type(PPC_RELOC_PAIR);
3642 fInternalRelocs.push_back(reloc1);
3643 fInternalRelocs.push_back(reloc2);
3644 atomSection->fHasTextLocalRelocs = true;
3645 return true;
3646 }
3647 }
3648 break;
3649 case ObjectFile::Atom::kExternalDefinition:
3650 case ObjectFile::Atom::kExternalWeakDefinition:
3651 case ObjectFile::Atom::kAbsoluteSymbol:
3652 return false;
3653 }
3654 return false;
3655 }
3656
3657 template <>
3658 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3659 {
3660 if ( ref.getKind() == arm::kReadOnlyPointer ) {
3661 switch ( ref.getTarget().getDefinitionKind() ) {
3662 case ObjectFile::Atom::kTentativeDefinition:
3663 case ObjectFile::Atom::kRegularDefinition:
3664 case ObjectFile::Atom::kWeakDefinition:
3665 // a reference to the absolute address of something in this same linkage unit can be
3666 // encoded as a local text reloc in a dylib or bundle
3667 if ( fSlideable ) {
3668 macho_relocation_info<P> reloc;
3669 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
3670 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3671 reloc.set_r_symbolnum(sectInfo->getIndex());
3672 reloc.set_r_pcrel(false);
3673 reloc.set_r_length();
3674 reloc.set_r_extern(false);
3675 reloc.set_r_type(GENERIC_RELOC_VANILLA);
3676 fInternalRelocs.push_back(reloc);
3677 atomSection->fHasTextLocalRelocs = true;
3678 return true;
3679 }
3680 return false;
3681 case ObjectFile::Atom::kExternalDefinition:
3682 case ObjectFile::Atom::kExternalWeakDefinition:
3683 case ObjectFile::Atom::kAbsoluteSymbol:
3684 return false;
3685 }
3686 }
3687 return false;
3688 }
3689
3690
3691 template <>
3692 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
3693 {
3694 // text relocs not supported (usually never needed because of RIP addressing)
3695 return false;
3696 }
3697
3698 template <>
3699 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
3700 {
3701 // text relocs not supported
3702 return false;
3703 }
3704
3705 template <>
3706 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
3707 {
3708 if ( ref.getKind() == x86::kAbsolute32 ) {
3709 macho_relocation_info<P> reloc;
3710 switch ( ref.getTarget().getDefinitionKind() ) {
3711 case ObjectFile::Atom::kTentativeDefinition:
3712 case ObjectFile::Atom::kRegularDefinition:
3713 case ObjectFile::Atom::kWeakDefinition:
3714 return false;
3715 case ObjectFile::Atom::kExternalDefinition:
3716 case ObjectFile::Atom::kExternalWeakDefinition:
3717 // a reference to the absolute address of something in another linkage unit can be
3718 // encoded as an external text reloc in a dylib or bundle
3719 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
3720 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
3721 reloc.set_r_pcrel(false);
3722 reloc.set_r_length();
3723 reloc.set_r_extern(true);
3724 reloc.set_r_type(GENERIC_RELOC_VANILLA);
3725 fExternalRelocs.push_back(reloc);
3726 atomSection->fHasTextExternalRelocs = true;
3727 return true;
3728 case ObjectFile::Atom::kAbsoluteSymbol:
3729 return false;
3730 }
3731 }
3732 return false;
3733 }
3734
3735 template <typename A>
3736 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
3737 {
3738 return false;
3739 }
3740
3741
3742
3743
3744 template <typename A>
3745 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
3746 {
3747 switch ( target.getDefinitionKind() ) {
3748 case ObjectFile::Atom::kTentativeDefinition:
3749 case ObjectFile::Atom::kRegularDefinition:
3750 // in main executables, the only way regular symbols are indirected is if -interposable is used
3751 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
3752 if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
3753 return kRelocExternal;
3754 else if ( fSlideable )
3755 return kRelocInternal;
3756 else
3757 return kRelocNone;
3758 }
3759 // for flat-namespace or interposable two-level-namespace
3760 // all references to exported symbols get indirected
3761 else if ( this->shouldExport(target) &&
3762 ((fOptions.nameSpace() == Options::kFlatNameSpace)
3763 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
3764 || fOptions.interposable(target.getName()))
3765 && (target.getName() != NULL)
3766 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
3767 return kRelocExternal;
3768 else if ( fSlideable )
3769 return kRelocInternal;
3770 else
3771 return kRelocNone;
3772 case ObjectFile::Atom::kWeakDefinition:
3773 // all calls to global weak definitions get indirected
3774 if ( this->shouldExport(target) )
3775 return kRelocExternal;
3776 else if ( fSlideable )
3777 return kRelocInternal;
3778 else
3779 return kRelocNone;
3780 case ObjectFile::Atom::kExternalDefinition:
3781 case ObjectFile::Atom::kExternalWeakDefinition:
3782 return kRelocExternal;
3783 case ObjectFile::Atom::kAbsoluteSymbol:
3784 return kRelocNone;
3785 }
3786 return kRelocNone;
3787 }
3788
3789 template <typename A>
3790 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3791 {
3792 // for 32-bit architectures, the r_address field in relocs
3793 // for final linked images is the offset from the first segment
3794 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
3795 // or the offset from the first writable segment if built split-seg
3796 if ( fOptions.splitSeg() )
3797 result = address - fFirstWritableSegment->fBaseAddress;
3798 if ( result > 0x7FFFFFFF ) {
3799 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
3800 atom->getDisplayName(), atom->getFile()->getPath());
3801 }
3802 return result;
3803 }
3804
3805 template <>
3806 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3807 {
3808 // for x86_64, the r_address field in relocs for final linked images
3809 // is the offset from the start address of the first writable segment
3810 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
3811 if ( result > 0xFFFFFFFF ) {
3812 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3813 atom->getDisplayName(), atom->getFile()->getPath());
3814 }
3815 return result;
3816 }
3817
3818 template <>
3819 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3820 {
3821 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
3822 // the 10.5 dyld, iterprets the r_address as:
3823 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
3824 // 2) an offset from the base address of the first writable segment
3825 // For dyld, r_address is always the offset from the base address
3826 uint64_t result;
3827 bool badFor10_4 = false;
3828 if ( fWritableSegmentPastFirst4GB ) {
3829 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
3830 badFor10_4 = true;
3831 result = address - fFirstWritableSegment->fBaseAddress;
3832 if ( result > 0xFFFFFFFF ) {
3833 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3834 atom->getDisplayName(), atom->getFile()->getPath());
3835 }
3836 }
3837 else {
3838 result = address - fSegmentInfos[0]->fBaseAddress;
3839 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
3840 badFor10_4 = true;
3841 }
3842 if ( badFor10_4 ) {
3843 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",
3844 atom->getDisplayName(), atom->getFile()->getPath());
3845 }
3846 return result;
3847 }
3848
3849
3850 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
3851 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3852 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
3853 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3854 template <> bool Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
3855
3856 template <typename A>
3857 void Writer<A>::buildExecutableFixups()
3858 {
3859 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
3860 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3861 const int segCount = segmentInfos.size();
3862 for(int i=0; i < segCount; ++i) {
3863 SegmentInfo* curSegment = segmentInfos[i];
3864 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3865 const int sectionCount = sectionInfos.size();
3866 for(int j=0; j < sectionCount; ++j) {
3867 SectionInfo* curSection = sectionInfos[j];
3868 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
3869 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3870 if ( ! curSection->fAllZeroFill ) {
3871 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers
3872 || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
3873 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3874 const int atomCount = sectionAtoms.size();
3875 for (int k=0; k < atomCount; ++k) {
3876 ObjectFile::Atom* atom = sectionAtoms[k];
3877 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3878 const int refCount = refs.size();
3879 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
3880 for (int l=0; l < refCount; ++l) {
3881 ObjectFile::Reference* ref = refs[l];
3882 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
3883 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
3884 if ( atom->getSize() != sizeof(pint_t) ) {
3885 warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
3886 }
3887 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
3888 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
3889 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
3890 }
3891 uint32_t offsetInSection = atom->getSectionOffset();
3892 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
3893 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3894 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
3895 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
3896 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3897 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3898 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X), pointerTarget=%s\n",
3899 // indirectTableIndex, undefinedSymbolIndex, pointerTarget->getDisplayName());
3900 fIndirectTableAtom->fTable.push_back(entry);
3901 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
3902 uint8_t preboundLazyType;
3903 if ( fOptions.prebind() && (fDyldHelper != NULL)
3904 && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
3905 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
3906 macho_scattered_relocation_info<P> pblaReloc;
3907 pblaReloc.set_r_scattered(true);
3908 pblaReloc.set_r_pcrel(false);
3909 pblaReloc.set_r_length();
3910 pblaReloc.set_r_type(preboundLazyType);
3911 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3912 pblaReloc.set_r_value(fDyldHelper->getAddress());
3913 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
3914 }
3915 else if ( fSlideable ) {
3916 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
3917 macho_relocation_info<P> dyldHelperReloc;
3918 uint32_t sectionNum = 1;
3919 if ( fDyldHelper != NULL )
3920 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
3921 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
3922 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3923 dyldHelperReloc.set_r_symbolnum(sectionNum);
3924 dyldHelperReloc.set_r_pcrel(false);
3925 dyldHelperReloc.set_r_length();
3926 dyldHelperReloc.set_r_extern(false);
3927 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
3928 fInternalRelocs.push_back(dyldHelperReloc);
3929 }
3930 }
3931 }
3932 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
3933 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
3934 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
3935 atom->getDisplayName(), atom->getFile()->getPath());
3936 }
3937 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
3938 case kRelocNone:
3939 // no reloc needed
3940 break;
3941 case kRelocInternal:
3942 {
3943 macho_relocation_info<P> internalReloc;
3944 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
3945 uint32_t sectionNum = sectInfo->getIndex();
3946 // special case _mh_dylib_header and friends which are not in any real section
3947 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
3948 sectionNum = 1;
3949 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3950 internalReloc.set_r_symbolnum(sectionNum);
3951 internalReloc.set_r_pcrel(false);
3952 internalReloc.set_r_length();
3953 internalReloc.set_r_extern(false);
3954 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3955 fInternalRelocs.push_back(internalReloc);
3956 }
3957 break;
3958 case kRelocExternal:
3959 {
3960 macho_relocation_info<P> externalReloc;
3961 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3962 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
3963 externalReloc.set_r_pcrel(false);
3964 externalReloc.set_r_length();
3965 externalReloc.set_r_extern(true);
3966 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3967 fExternalRelocs.push_back(externalReloc);
3968 }
3969 break;
3970 }
3971 }
3972 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
3973 if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
3974 if ( fOptions.warnAboutTextRelocs() )
3975 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
3976 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
3977 // relocs added to fInternalRelocs
3978 }
3979 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
3980 // relocs added to fExternalRelocs
3981 }
3982 else {
3983 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
3984 }
3985 }
3986 else {
3987 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
3988 "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
3989 }
3990 }
3991 }
3992 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
3993 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
3994 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
3995 uint32_t offsetInSection = atom->getSectionOffset();
3996 uint32_t indexInSection = offsetInSection / atom->getSize();
3997 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3998 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3999 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
4000 fIndirectTableAtom->fTable.push_back(entry);
4001 }
4002 }
4003 }
4004 }
4005 }
4006 if ( fSplitCodeToDataContentAtom != NULL )
4007 fSplitCodeToDataContentAtom->encode();
4008 }
4009
4010
4011 template <>
4012 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4013 {
4014 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
4015 case ppc::kPICBaseHigh16:
4016 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
4017 break;
4018 case ppc::kPointerDiff32:
4019 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4020 break;
4021 case ppc::kPointerDiff64:
4022 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
4023 break;
4024 case ppc::kNoFixUp:
4025 case ppc::kGroupSubordinate:
4026 case ppc::kPointer:
4027 case ppc::kPointerWeakImport:
4028 case ppc::kPICBaseLow16:
4029 case ppc::kPICBaseLow14:
4030 // ignore
4031 break;
4032 default:
4033 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
4034 fSplitCodeToDataContentAtom->setCantEncode();
4035 }
4036 }
4037
4038 template <>
4039 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4040 {
4041 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
4042 case ppc64::kPICBaseHigh16:
4043 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
4044 break;
4045 case ppc64::kPointerDiff32:
4046 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4047 break;
4048 case ppc64::kPointerDiff64:
4049 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
4050 break;
4051 case ppc64::kNoFixUp:
4052 case ppc64::kGroupSubordinate:
4053 case ppc64::kPointer:
4054 case ppc64::kPointerWeakImport:
4055 case ppc64::kPICBaseLow16:
4056 case ppc64::kPICBaseLow14:
4057 // ignore
4058 break;
4059 default:
4060 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
4061 fSplitCodeToDataContentAtom->setCantEncode();
4062 }
4063 }
4064
4065 template <>
4066 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4067 {
4068 switch ( (x86::ReferenceKinds)ref->getKind() ) {
4069 case x86::kPointerDiff:
4070 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
4071 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
4072 else
4073 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4074 break;
4075 case x86::kNoFixUp:
4076 case x86::kGroupSubordinate:
4077 case x86::kPointer:
4078 case x86::kPointerWeakImport:
4079 // ignore
4080 break;
4081 case x86::kPCRel32:
4082 case x86::kPCRel32WeakImport:
4083 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
4084 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
4085 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
4086 break;
4087 }
4088 // fall into warning case
4089 default:
4090 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
4091 fSplitCodeToDataContentAtom->setCantEncode();
4092 }
4093 }
4094
4095 template <>
4096 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4097 {
4098 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
4099 case x86_64::kPCRel32:
4100 case x86_64::kPCRel32_1:
4101 case x86_64::kPCRel32_2:
4102 case x86_64::kPCRel32_4:
4103 case x86_64::kPCRel32GOTLoad:
4104 case x86_64::kPCRel32GOTLoadWeakImport:
4105 case x86_64::kPCRel32GOT:
4106 case x86_64::kPCRel32GOTWeakImport:
4107 case x86_64::kPointerDiff32:
4108 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4109 break;
4110 case x86_64::kPointerDiff:
4111 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
4112 break;
4113 case x86_64::kNoFixUp:
4114 case x86_64::kGroupSubordinate:
4115 case x86_64::kPointer:
4116 // ignore
4117 break;
4118 default:
4119 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
4120 fSplitCodeToDataContentAtom->setCantEncode();
4121 }
4122 }
4123
4124 template <>
4125 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
4126 {
4127 switch ( (arm::ReferenceKinds)ref->getKind() ) {
4128 case arm::kPointerDiff:
4129 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
4130 break;
4131 case arm::kNoFixUp:
4132 case arm::kGroupSubordinate:
4133 case arm::kPointer:
4134 case arm::kPointerWeakImport:
4135 case arm::kReadOnlyPointer:
4136 // ignore
4137 break;
4138 default:
4139 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
4140 fSplitCodeToDataContentAtom->setCantEncode();
4141 }
4142 }
4143
4144 template <typename A>
4145 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
4146 {
4147 switch ( to.getDefinitionKind() ) {
4148 case ObjectFile::Atom::kExternalDefinition:
4149 case ObjectFile::Atom::kExternalWeakDefinition:
4150 case ObjectFile::Atom::kAbsoluteSymbol:
4151 return false;
4152 case ObjectFile::Atom::kRegularDefinition:
4153 case ObjectFile::Atom::kWeakDefinition:
4154 case ObjectFile::Atom::kTentativeDefinition:
4155 // segments with same permissions slide together
4156 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
4157 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
4158 }
4159 throw "ld64 internal error";
4160 }
4161
4162
4163 template <>
4164 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
4165 {
4166 uint32_t ppcNop;
4167 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
4168 for (uint32_t p=from; p < to; p += 4)
4169 ::pwrite(fd, &ppcNop, 4, p);
4170 }
4171
4172 template <>
4173 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
4174 {
4175 uint32_t ppcNop;
4176 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
4177 for (uint32_t p=from; p < to; p += 4)
4178 ::pwrite(fd, &ppcNop, 4, p);
4179 }
4180
4181 template <>
4182 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
4183 {
4184 uint8_t x86Nop = 0x90;
4185 for (uint32_t p=from; p < to; ++p)
4186 ::pwrite(fd, &x86Nop, 1, p);
4187 }
4188
4189 template <>
4190 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
4191 {
4192 uint8_t x86Nop = 0x90;
4193 for (uint32_t p=from; p < to; ++p)
4194 ::pwrite(fd, &x86Nop, 1, p);
4195 }
4196
4197 template <>
4198 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
4199 {
4200 // FIXME: need thumb nop?
4201 uint32_t armNop;
4202 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
4203 for (uint32_t p=from; p < to; p += 4)
4204 ::pwrite(fd, &armNop, 4, p);
4205 }
4206
4207 template <>
4208 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
4209 {
4210 for (uint8_t* p=from; p < to; p += 4)
4211 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
4212 }
4213
4214 template <>
4215 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
4216 {
4217 for (uint8_t* p=from; p < to; p += 4)
4218 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
4219 }
4220
4221 template <>
4222 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
4223 {
4224 for (uint8_t* p=from; p < to; ++p)
4225 *p = 0x90;
4226 }
4227
4228 template <>
4229 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
4230 {
4231 for (uint8_t* p=from; p < to; ++p)
4232 *p = 0x90;
4233 }
4234
4235 template <>
4236 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
4237 {
4238 // fixme: need thumb nop?
4239 for (uint8_t* p=from; p < to; p += 4)
4240 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
4241 }
4242
4243 static const char* stringName(const char* str)
4244 {
4245 if ( strncmp(str, "cstring=", 8) == 0) {
4246 static char buffer[1024];
4247 char* t = buffer;
4248 *t++ = '\"';
4249 for(const char*s = &str[8]; *s != '\0'; ++s) {
4250 switch(*s) {
4251 case '\n':
4252 *t++ = '\\';
4253 *t++ = 'n';
4254 break;
4255 case '\t':
4256 *t++ = '\\';
4257 *t++ = 't';
4258 break;
4259 default:
4260 *t++ = *s;
4261 break;
4262 }
4263 if ( t > &buffer[1020] ) {
4264 *t++= '\"';
4265 *t++= '.';
4266 *t++= '.';
4267 *t++= '.';
4268 *t++= '\0';
4269 return buffer;
4270 }
4271 }
4272 *t++= '\"';
4273 *t++= '\0';
4274 return buffer;
4275 }
4276 else {
4277 return str;
4278 }
4279 }
4280
4281
4282 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
4283 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
4284 template <> const char* Writer<x86>::getArchString() { return "i386"; }
4285 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
4286 template <> const char* Writer<arm>::getArchString() { return "arm"; }
4287
4288 template <typename A>
4289 void Writer<A>::writeMap()
4290 {
4291 if ( fOptions.generatedMapPath() != NULL ) {
4292 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
4293 if ( mapFile != NULL ) {
4294 // write output path
4295 fprintf(mapFile, "# Path: %s\n", fFilePath);
4296 // write output architecure
4297 fprintf(mapFile, "# Arch: %s\n", getArchString());
4298 // write UUID
4299 if ( fUUIDAtom != NULL ) {
4300 const uint8_t* uuid = fUUIDAtom->getUUID();
4301 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
4302 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
4303 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
4304 }
4305 // write table of object files
4306 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
4307 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
4308 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
4309 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4310 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
4311 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4312 if ( ! (*secit)->fVirtualSection ) {
4313 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
4314 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
4315 ObjectFile::Reader* reader = (*ait)->getFile();
4316 uint32_t readerOrdinal = (*ait)->getOrdinal();
4317 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
4318 if ( pos == readerToOrdinal.end() ) {
4319 readerToOrdinal[reader] = readerOrdinal;
4320 ordinalToReader[readerOrdinal] = reader;
4321 }
4322 }
4323 }
4324 }
4325 }
4326 fprintf(mapFile, "# Object files:\n");
4327 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
4328 uint32_t fileIndex = 0;
4329 readerToFileOrdinal[this] = fileIndex++;
4330 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
4331 if ( it->first != 0 ) {
4332 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
4333 readerToFileOrdinal[it->second] = fileIndex++;
4334 }
4335 }
4336 // write table of sections
4337 fprintf(mapFile, "# Sections:\n");
4338 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
4339 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4340 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
4341 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4342 if ( ! (*secit)->fVirtualSection ) {
4343 SectionInfo* sect = *secit;
4344 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
4345 (*segit)->fName, sect->fSectionName);
4346 }
4347 }
4348 }
4349 // write table of symbols
4350 fprintf(mapFile, "# Symbols:\n");
4351 fprintf(mapFile, "# Address\tSize \tFile Name\n");
4352 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4353 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
4354 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4355 if ( ! (*secit)->fVirtualSection ) {
4356 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
4357 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
4358 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
4359 ObjectFile::Atom* atom = *ait;
4360 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
4361 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
4362 }
4363 }
4364 }
4365 }
4366 fclose(mapFile);
4367 }
4368 else {
4369 warning("could not write map file: %s\n", fOptions.generatedMapPath());
4370 }
4371 }
4372 }
4373
4374 static const char* sCleanupFile = NULL;
4375 static void cleanup(int sig)
4376 {
4377 ::signal(sig, SIG_DFL);
4378 if ( sCleanupFile != NULL ) {
4379 ::unlink(sCleanupFile);
4380 }
4381 if ( sig == SIGINT )
4382 ::exit(1);
4383 }
4384
4385
4386 template <typename A>
4387 uint64_t Writer<A>::writeAtoms()
4388 {
4389 // for UNIX conformance, error if file exists and is not writable
4390 if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
4391 throwf("can't write output file: %s", fFilePath);
4392
4393 int permissions = 0777;
4394 if ( fOptions.outputKind() == Options::kObjectFile )
4395 permissions = 0666;
4396 // Calling unlink first assures the file is gone so that open creates it with correct permissions
4397 // It also handles the case where fFilePath file is not writable but its directory is
4398 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
4399 (void)unlink(fFilePath);
4400
4401 // try to allocate buffer for entire output file content
4402 int fd = -1;
4403 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
4404 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
4405 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
4406 uint8_t* atomBuffer = NULL;
4407 bool streaming = false;
4408 if ( wholeBuffer == NULL ) {
4409 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
4410 if ( fd == -1 )
4411 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
4412 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
4413 streaming = true;
4414 // install signal handlers to delete output file if program is killed
4415 sCleanupFile = fFilePath;
4416 ::signal(SIGINT, cleanup);
4417 ::signal(SIGBUS, cleanup);
4418 ::signal(SIGSEGV, cleanup);
4419 }
4420 uint32_t size = 0;
4421 uint32_t end = 0;
4422 try {
4423 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
4424 SegmentInfo* curSegment = *segit;
4425 bool isTextSeg = (strcmp(curSegment->fName, "__TEXT") == 0);
4426 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4427 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
4428 SectionInfo* curSection = *secit;
4429 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
4430 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
4431 //fprintf(stderr, "writing %lu atoms for section %s\n", sectionAtoms.size(), curSection->fSectionName);
4432 if ( ! curSection->fAllZeroFill ) {
4433 end = curSection->fFileOffset;
4434 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
4435 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
4436 ObjectFile::Atom* atom = *ait;
4437 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
4438 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
4439 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
4440 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
4441 if ( fileOffset != end ) {
4442 if ( needsNops ) {
4443 // fill gaps with no-ops
4444 if ( streaming )
4445 writeNoOps(fd, end, fileOffset);
4446 else
4447 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
4448 }
4449 else if ( streaming ) {
4450 // zero fill gaps
4451 if ( (fileOffset-end) == 4 ) {
4452 uint32_t zero = 0;
4453 ::pwrite(fd, &zero, 4, end);
4454 }
4455 else {
4456 uint8_t zero = 0x00;
4457 for (uint32_t p=end; p < fileOffset; ++p)
4458 ::pwrite(fd, &zero, 1, p);
4459 }
4460 }
4461 }
4462 uint64_t atomSize = atom->getSize();
4463 if ( streaming ) {
4464 if ( atomSize > fLargestAtomSize )
4465 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
4466 atom->getDisplayName(), atomSize, fLargestAtomSize);
4467 }
4468 else {
4469 if ( fileOffset > fileBufferSize )
4470 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
4471 atom->getDisplayName(), fileOffset, fileBufferSize);
4472 }
4473 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
4474 end = fileOffset+atomSize;
4475 // copy raw bytes
4476 atom->copyRawContent(buffer);
4477 // apply any fix-ups
4478 try {
4479 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4480 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
4481 ObjectFile::Reference* ref = *it;
4482 if ( fOptions.outputKind() == Options::kObjectFile ) {
4483 // doing ld -r
4484 // skip fix-ups for undefined targets
4485 if ( &(ref->getTarget()) != NULL )
4486 this->fixUpReferenceRelocatable(ref, atom, buffer);
4487 }
4488 else {
4489 // producing final linked image
4490 this->fixUpReferenceFinal(ref, atom, buffer);
4491 }
4492 }
4493 }
4494 catch (const char* msg) {
4495 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
4496 }
4497 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
4498 // fileOffset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
4499 if ( streaming ) {
4500 // write out
4501 ::pwrite(fd, buffer, atomSize, fileOffset);
4502 }
4503 else {
4504 if ( (fileOffset + atomSize) > size )
4505 size = fileOffset + atomSize;
4506 }
4507 }
4508 }
4509 }
4510 }
4511 }
4512
4513 // update content based UUID
4514 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
4515 uint8_t digest[CC_MD5_DIGEST_LENGTH];
4516 if ( streaming ) {
4517 // if output file file did not fit in memory, re-read file to generate md5 hash
4518 uint32_t kMD5BufferSize = 16*1024;
4519 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
4520 if ( md5Buffer != NULL ) {
4521 CC_MD5_CTX md5State;
4522 CC_MD5_Init(&md5State);
4523 ::lseek(fd, 0, SEEK_SET);
4524 ssize_t len;
4525 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
4526 CC_MD5_Update(&md5State, md5Buffer, len);
4527 CC_MD5_Final(digest, &md5State);
4528 ::free(md5Buffer);
4529 }
4530 else {
4531 // if malloc fails, fall back to random uuid
4532 ::uuid_generate_random(digest);
4533 }
4534 fUUIDAtom->setContent(digest);
4535 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
4536 fUUIDAtom->copyRawContent(atomBuffer);
4537 ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
4538 }
4539 else {
4540 // if output file fit in memory, just genrate an md5 hash in memory
4541 #if 1
4542 // temp hack for building on Tiger
4543 CC_MD5_CTX md5State;
4544 CC_MD5_Init(&md5State);
4545 CC_MD5_Update(&md5State, wholeBuffer, size);
4546 CC_MD5_Final(digest, &md5State);
4547 #else
4548 CC_MD5(wholeBuffer, size, digest);
4549 #endif
4550 fUUIDAtom->setContent(digest);
4551 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
4552 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
4553 }
4554 }
4555 }
4556 catch (...) {
4557 if ( sCleanupFile != NULL )
4558 ::unlink(sCleanupFile);
4559 throw;
4560 }
4561
4562 // finish up
4563 if ( streaming ) {
4564 delete [] atomBuffer;
4565 close(fd);
4566 // restore default signal handlers
4567 sCleanupFile = NULL;
4568 ::signal(SIGINT, SIG_DFL);
4569 ::signal(SIGBUS, SIG_DFL);
4570 ::signal(SIGSEGV, SIG_DFL);
4571 }
4572 else {
4573 // write whole output file in one chunk
4574 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
4575 if ( fd == -1 )
4576 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
4577 ::pwrite(fd, wholeBuffer, size, 0);
4578 close(fd);
4579 delete [] wholeBuffer;
4580 }
4581
4582 return end;
4583 }
4584
4585 template <>
4586 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4587 {
4588 int64_t displacement;
4589 int64_t baseAddr;
4590 uint32_t instruction;
4591 uint32_t newInstruction;
4592 uint64_t targetAddr = 0;
4593 uint32_t firstDisp;
4594 uint32_t nextDisp;
4595 uint32_t opcode;
4596 bool relocateableExternal = false;
4597 bool is_bl;
4598 bool is_blx;
4599 bool targetIsThumb;
4600
4601 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4602 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4603 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
4604 }
4605
4606 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4607 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
4608 case arm::kNoFixUp:
4609 case arm::kFollowOn:
4610 case arm::kGroupSubordinate:
4611 // do nothing
4612 break;
4613 case arm::kPointerWeakImport:
4614 case arm::kPointer:
4615 // If this is the lazy pointers section, then set all lazy pointers to
4616 // point to the dyld stub binding helper.
4617 if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers
4618 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
4619 switch (ref->getTarget().getDefinitionKind()) {
4620 case ObjectFile::Atom::kExternalDefinition:
4621 case ObjectFile::Atom::kExternalWeakDefinition:
4622 // prebound lazy pointer to another dylib ==> pointer contains zero
4623 LittleEndian::set32(*fixUp, 0);
4624 break;
4625 case ObjectFile::Atom::kTentativeDefinition:
4626 case ObjectFile::Atom::kRegularDefinition:
4627 case ObjectFile::Atom::kWeakDefinition:
4628 case ObjectFile::Atom::kAbsoluteSymbol:
4629 // prebound lazy pointer to withing this dylib ==> pointer contains address
4630 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
4631 targetAddr |= 1;
4632 LittleEndian::set32(*fixUp, targetAddr);
4633 break;
4634 }
4635 }
4636 else if ( relocateableExternal ) {
4637 if ( fOptions.prebind() ) {
4638 switch (ref->getTarget().getDefinitionKind()) {
4639 case ObjectFile::Atom::kExternalDefinition:
4640 case ObjectFile::Atom::kExternalWeakDefinition:
4641 // prebound external relocation ==> pointer contains addend
4642 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4643 break;
4644 case ObjectFile::Atom::kTentativeDefinition:
4645 case ObjectFile::Atom::kRegularDefinition:
4646 case ObjectFile::Atom::kWeakDefinition:
4647 // prebound external relocation to internal atom ==> pointer contains target address + addend
4648 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
4649 targetAddr |= 1;
4650 LittleEndian::set32(*fixUp, targetAddr);
4651 break;
4652 case ObjectFile::Atom::kAbsoluteSymbol:
4653 break;
4654 }
4655 }
4656 else {
4657 // external relocation ==> pointer contains addend
4658 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4659 }
4660 }
4661 else {
4662 // pointer contains target address
4663 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
4664 targetAddr |= 1;
4665 LittleEndian::set32(*fixUp, targetAddr);
4666 }
4667 break;
4668 case arm::kPointerDiff:
4669 LittleEndian::set32(*fixUp,
4670 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4671 break;
4672 case arm::kReadOnlyPointer:
4673 switch ( ref->getTarget().getDefinitionKind() ) {
4674 case ObjectFile::Atom::kRegularDefinition:
4675 case ObjectFile::Atom::kWeakDefinition:
4676 case ObjectFile::Atom::kTentativeDefinition:
4677 // pointer contains target address
4678 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4679 break;
4680 case ObjectFile::Atom::kExternalDefinition:
4681 case ObjectFile::Atom::kExternalWeakDefinition:
4682 // external relocation ==> pointer contains addend
4683 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4684 break;
4685 case ObjectFile::Atom::kAbsoluteSymbol:
4686 // pointer contains target address
4687 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
4688 break;
4689 }
4690 break;
4691 case arm::kBranch24WeakImport:
4692 case arm::kBranch24:
4693 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4694 // The pc added will be +8 from the pc
4695 displacement -= 8;
4696 // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
4697 // max positive displacement is 0x007FFFFF << 2
4698 // max negative displacement is 0xFF800000 << 2
4699 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
4700 throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
4701 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4702 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4703 }
4704 instruction = LittleEndian::get32(*fixUp);
4705 // Make sure we are calling arm with bl, thumb with blx
4706 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
4707 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
4708 if ( is_bl && ref->getTarget().isThumb() ) {
4709 uint32_t opcode = 0xFA000000;
4710 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4711 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
4712 newInstruction = opcode | h_bit | disp;
4713 }
4714 else if ( is_blx && !ref->getTarget().isThumb() ) {
4715 uint32_t opcode = 0xEB000000;
4716 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4717 newInstruction = opcode | disp;
4718 }
4719 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
4720 throwf("don't know how to convert instruction %x referencing %s to thumb",
4721 instruction, ref->getTarget().getDisplayName());
4722 }
4723 else {
4724 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
4725 }
4726 LittleEndian::set32(*fixUp, newInstruction);
4727 break;
4728 case arm::kThumbBranch22WeakImport:
4729 case arm::kThumbBranch22:
4730 instruction = LittleEndian::get32(*fixUp);
4731 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
4732 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
4733 targetIsThumb = ref->getTarget().isThumb();
4734
4735 // The pc added will be +4 from the pc
4736 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
4737 // If the target is not thumb, we will be generating a blx instruction
4738 // Since blx cannot have the low bit set, set bit[1] of the target to
4739 // bit[1] of the base address, so that the difference is a multiple of
4740 // 4 bytes.
4741 if ( !targetIsThumb ) {
4742 targetAddr &= -3ULL;
4743 targetAddr |= (baseAddr & 2LL);
4744 }
4745 displacement = targetAddr - baseAddr;
4746
4747 // max positive displacement is 0x003FFFFE
4748 // max negative displacement is 0xFFC00000
4749 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
4750 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
4751 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4752 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4753 }
4754 // The instruction is really two instructions:
4755 // The lower 16 bits are the first instruction, which contains the first
4756 // 11 bits of the displacement.
4757 // The upper 16 bits are the second instruction, which contains the next
4758 // 11 bits of the displacement, as well as differentiating bl and blx.
4759 {
4760 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
4761 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
4762 if ( is_bl && !targetIsThumb ) {
4763 opcode = 0xE800F000;
4764 }
4765 else if ( is_blx && targetIsThumb ) {
4766 opcode = 0xF800F000;
4767 }
4768 else if ( !is_bl && !is_blx && !targetIsThumb ) {
4769 throwf("don't know how to convert instruction %x referencing %s to arm",
4770 instruction, ref->getTarget().getDisplayName());
4771 }
4772 else {
4773 opcode = instruction & 0xF800F800;
4774 }
4775 newInstruction = opcode | (nextDisp << 16) | firstDisp;
4776 LittleEndian::set32(*fixUp, newInstruction);
4777 }
4778 break;
4779 case arm::kDtraceProbeSite:
4780 case arm::kDtraceIsEnabledSite:
4781 if ( inAtom->isThumb() ) {
4782 // change 32-bit blx call site to two thumb NOPs
4783 LittleEndian::set32(*fixUp, 0x46C046C0);
4784 }
4785 else {
4786 // change call site to a NOP
4787 LittleEndian::set32(*fixUp, 0xE1A00000);
4788 }
4789 break;
4790 case arm::kDtraceTypeReference:
4791 case arm::kDtraceProbe:
4792 // nothing to fix up
4793 break;
4794 default:
4795 throw "boom shaka laka";
4796 }
4797 }
4798
4799 template <>
4800 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4801 {
4802 int64_t displacement;
4803 uint32_t instruction;
4804 uint32_t newInstruction;
4805 uint64_t targetAddr = 0;
4806 int64_t baseAddr;
4807 uint32_t firstDisp;
4808 uint32_t nextDisp;
4809 uint32_t opcode;
4810 bool relocateableExternal = false;
4811 bool is_bl;
4812 bool is_blx;
4813 bool targetIsThumb;
4814
4815 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4816 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4817 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
4818 }
4819
4820 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4821 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
4822 case arm::kNoFixUp:
4823 case arm::kFollowOn:
4824 case arm::kGroupSubordinate:
4825 // do nothing
4826 break;
4827 case arm::kPointer:
4828 case arm::kReadOnlyPointer:
4829 case arm::kPointerWeakImport:
4830 {
4831 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4832 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
4833 if ( this->indirectSymbolIsLocal(ref) )
4834 LittleEndian::set32(*fixUp, targetAddr);
4835 else
4836 LittleEndian::set32(*fixUp, 0);
4837 }
4838 else if ( relocateableExternal ) {
4839 if ( fOptions.prebind() ) {
4840 switch (ref->getTarget().getDefinitionKind()) {
4841 case ObjectFile::Atom::kExternalDefinition:
4842 case ObjectFile::Atom::kExternalWeakDefinition:
4843 // prebound external relocation ==> pointer contains addend
4844 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4845 break;
4846 case ObjectFile::Atom::kTentativeDefinition:
4847 case ObjectFile::Atom::kRegularDefinition:
4848 case ObjectFile::Atom::kWeakDefinition:
4849 // prebound external relocation to internal atom ==> pointer contains target address + addend
4850 LittleEndian::set32(*fixUp, targetAddr);
4851 break;
4852 case ObjectFile::Atom::kAbsoluteSymbol:
4853 break;
4854 }
4855 }
4856 }
4857 else {
4858 // internal relocation
4859 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
4860 // pointer contains target address
4861 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
4862 targetAddr |= 1;
4863 LittleEndian::set32(*fixUp, targetAddr);
4864 }
4865 else {
4866 // pointer contains addend
4867 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4868 }
4869 }
4870 }
4871 break;
4872 case arm::kPointerDiff:
4873 LittleEndian::set32(*fixUp,
4874 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4875 break;
4876 case arm::kDtraceProbeSite:
4877 case arm::kDtraceIsEnabledSite:
4878 case arm::kBranch24WeakImport:
4879 case arm::kBranch24:
4880 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4881 // The pc added will be +8 from the pc
4882 displacement -= 8;
4883 // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
4884 if ( relocateableExternal ) {
4885 // doing "ld -r" to an external symbol
4886 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4887 displacement -= ref->getTarget().getAddress();
4888 }
4889 else {
4890 // max positive displacement is 0x007FFFFF << 2
4891 // max negative displacement is 0xFF800000 << 2
4892 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
4893 throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
4894 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4895 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4896 }
4897 }
4898 instruction = LittleEndian::get32(*fixUp);
4899 // Make sure we are calling arm with bl, thumb with blx
4900 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
4901 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
4902 if ( is_bl && ref->getTarget().isThumb() ) {
4903 uint32_t opcode = 0xFA000000;
4904 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4905 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
4906 newInstruction = opcode | h_bit | disp;
4907 }
4908 else if ( is_blx && !ref->getTarget().isThumb() ) {
4909 uint32_t opcode = 0xEB000000;
4910 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
4911 newInstruction = opcode | disp;
4912 }
4913 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
4914 throwf("don't know how to convert instruction %x referencing %s to thumb",
4915 instruction, ref->getTarget().getDisplayName());
4916 }
4917 else {
4918 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
4919 }
4920 LittleEndian::set32(*fixUp, newInstruction);
4921 break;
4922 case arm::kThumbBranch22WeakImport:
4923 case arm::kThumbBranch22:
4924 instruction = LittleEndian::get32(*fixUp);
4925 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
4926 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
4927 targetIsThumb = ref->getTarget().isThumb();
4928
4929 // The pc added will be +4 from the pc
4930 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
4931 // If the target is not thumb, we will be generating a blx instruction
4932 // Since blx cannot have the low bit set, set bit[1] of the target to
4933 // bit[1] of the base address, so that the difference is a multiple of
4934 // 4 bytes.
4935 if (!targetIsThumb) {
4936 targetAddr &= -3ULL;
4937 targetAddr |= (baseAddr & 2LL);
4938 }
4939 displacement = targetAddr - baseAddr;
4940
4941 //fprintf(stderr, "thumb %s fixup to %s at 0x%08llX, baseAddr = 0x%08llX, displacement = 0x%08llX, %d\n", is_blx ? "blx" : "bl", ref->getTarget().getDisplayName(), targetAddr, baseAddr, displacement, targetIsThumb);
4942 if ( relocateableExternal ) {
4943 // doing "ld -r" to an external symbol
4944 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4945 displacement -= ref->getTarget().getAddress();
4946 }
4947 else {
4948 // max positive displacement is 0x003FFFFE
4949 // max negative displacement is 0xFFC00000
4950 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
4951 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
4952 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4953 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4954 }
4955 }
4956 // The instruction is really two instructions:
4957 // The lower 16 bits are the first instruction, which contains the first
4958 // 11 bits of the displacement.
4959 // The upper 16 bits are the second instruction, which contains the next
4960 // 11 bits of the displacement, as well as differentiating bl and blx.
4961 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
4962 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
4963 if ( is_bl && !targetIsThumb ) {
4964 opcode = 0xE800F000;
4965 }
4966 else if ( is_blx && targetIsThumb ) {
4967 opcode = 0xF800F000;
4968 }
4969 else if ( !is_bl && !is_blx && !targetIsThumb ) {
4970 throwf("don't know how to convert instruction %x referencing %s to arm",
4971 instruction, ref->getTarget().getDisplayName());
4972 }
4973 else {
4974 opcode = instruction & 0xF800F800;
4975 }
4976 newInstruction = opcode | (nextDisp << 16) | firstDisp;
4977 LittleEndian::set32(*fixUp, newInstruction);
4978 break;
4979 case arm::kDtraceProbe:
4980 case arm::kDtraceTypeReference:
4981 // nothing to fix up
4982 break;
4983 }
4984 }
4985
4986 template <>
4987 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4988 {
4989 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4990 uint8_t* dtraceProbeSite;
4991 const int64_t kTwoGigLimit = 0x7FFFFFFF;
4992 const int64_t kSixtyFourKiloLimit = 0x7FFF;
4993 const int64_t kOneTwentyEightLimit = 0x7F;
4994 int64_t displacement;
4995 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
4996 switch ( kind ) {
4997 case x86::kNoFixUp:
4998 case x86::kFollowOn:
4999 case x86::kGroupSubordinate:
5000 // do nothing
5001 break;
5002 case x86::kPointerWeakImport:
5003 case x86::kPointer:
5004 {
5005 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
5006 if ( fOptions.prebind() ) {
5007 switch (ref->getTarget().getDefinitionKind()) {
5008 case ObjectFile::Atom::kExternalDefinition:
5009 case ObjectFile::Atom::kExternalWeakDefinition:
5010 // prebound external relocation ==> pointer contains addend
5011 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5012 break;
5013 case ObjectFile::Atom::kTentativeDefinition:
5014 case ObjectFile::Atom::kRegularDefinition:
5015 case ObjectFile::Atom::kWeakDefinition:
5016 // prebound external relocation to internal atom ==> pointer contains target address + addend
5017 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5018 break;
5019 case ObjectFile::Atom::kAbsoluteSymbol:
5020 break;
5021 }
5022 }
5023 else {
5024 // external relocation ==> pointer contains addend
5025 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5026 }
5027 }
5028 else {
5029 // pointer contains target address
5030 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
5031 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5032 }
5033 }
5034 break;
5035 case x86::kPointerDiff:
5036 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5037 LittleEndian::set32(*fixUp, (uint32_t)displacement);
5038 break;
5039 case x86::kPointerDiff16:
5040 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5041 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
5042 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
5043 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
5044 break;
5045 case x86::kDtraceProbeSite:
5046 // change call site to a NOP
5047 dtraceProbeSite = (uint8_t*)fixUp;
5048 dtraceProbeSite[-1] = 0x90; // 1-byte nop
5049 dtraceProbeSite[0] = 0x0F; // 4-byte nop
5050 dtraceProbeSite[1] = 0x1F;
5051 dtraceProbeSite[2] = 0x40;
5052 dtraceProbeSite[3] = 0x00;
5053 break;
5054 case x86::kDtraceIsEnabledSite:
5055 // change call site to a clear eax
5056 dtraceProbeSite = (uint8_t*)fixUp;
5057 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
5058 dtraceProbeSite[0] = 0xC0;
5059 dtraceProbeSite[1] = 0x90; // 1-byte nop
5060 dtraceProbeSite[2] = 0x90; // 1-byte nop
5061 dtraceProbeSite[3] = 0x90; // 1-byte nop
5062 break;
5063 case x86::kPCRel32WeakImport:
5064 case x86::kPCRel32:
5065 case x86::kPCRel16:
5066 case x86::kPCRel8:
5067 displacement = 0;
5068 switch ( ref->getTarget().getDefinitionKind() ) {
5069 case ObjectFile::Atom::kRegularDefinition:
5070 case ObjectFile::Atom::kWeakDefinition:
5071 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5072 break;
5073 case ObjectFile::Atom::kExternalDefinition:
5074 case ObjectFile::Atom::kExternalWeakDefinition:
5075 throw "codegen problem, can't use rel32 to external symbol";
5076 case ObjectFile::Atom::kTentativeDefinition:
5077 displacement = 0;
5078 break;
5079 case ObjectFile::Atom::kAbsoluteSymbol:
5080 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5081 break;
5082 }
5083 if ( kind == x86::kPCRel8 ) {
5084 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
5085 //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());
5086 throwf("rel8 out of range in %s", inAtom->getDisplayName());
5087 }
5088 *(int8_t*)fixUp = (int8_t)displacement;
5089 }
5090 else if ( kind == x86::kPCRel16 ) {
5091 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
5092 //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());
5093 throwf("rel16 out of range in %s", inAtom->getDisplayName());
5094 }
5095 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
5096 }
5097 else {
5098 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
5099 //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());
5100 throwf("rel32 out of range in %s", inAtom->getDisplayName());
5101 }
5102 LittleEndian::set32(*fixUp, (int32_t)displacement);
5103 }
5104 break;
5105 case x86::kAbsolute32:
5106 switch ( ref->getTarget().getDefinitionKind() ) {
5107 case ObjectFile::Atom::kRegularDefinition:
5108 case ObjectFile::Atom::kWeakDefinition:
5109 case ObjectFile::Atom::kTentativeDefinition:
5110 // pointer contains target address
5111 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5112 break;
5113 case ObjectFile::Atom::kExternalDefinition:
5114 case ObjectFile::Atom::kExternalWeakDefinition:
5115 // external relocation ==> pointer contains addend
5116 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5117 break;
5118 case ObjectFile::Atom::kAbsoluteSymbol:
5119 // pointer contains target address
5120 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
5121 break;
5122 }
5123 break;
5124 case x86::kDtraceTypeReference:
5125 case x86::kDtraceProbe:
5126 // nothing to fix up
5127 break;
5128 }
5129 }
5130
5131
5132
5133 template <>
5134 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5135 {
5136 const int64_t kTwoGigLimit = 0x7FFFFFFF;
5137 const int64_t kSixtyFourKiloLimit = 0x7FFF;
5138 const int64_t kOneTwentyEightLimit = 0x7F;
5139 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
5140 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
5141 int64_t displacement;
5142 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
5143 switch ( kind ) {
5144 case x86::kNoFixUp:
5145 case x86::kFollowOn:
5146 case x86::kGroupSubordinate:
5147 // do nothing
5148 break;
5149 case x86::kPointer:
5150 case x86::kPointerWeakImport:
5151 case x86::kAbsolute32:
5152 {
5153 if ( isExtern ) {
5154 // external relocation ==> pointer contains addend
5155 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5156 }
5157 else if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
5158 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
5159 if ( this->indirectSymbolIsLocal(ref) )
5160 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5161 else
5162 LittleEndian::set32(*fixUp, 0);
5163 }
5164 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
5165 // internal relocation => pointer contains target address
5166 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5167 }
5168 else {
5169 // internal relocation to tentative ==> pointer contains addend
5170 LittleEndian::set32(*fixUp, ref->getTargetOffset());
5171 }
5172 }
5173 break;
5174 case x86::kPointerDiff:
5175 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5176 LittleEndian::set32(*fixUp, (uint32_t)displacement);
5177 break;
5178 case x86::kPointerDiff16:
5179 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5180 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
5181 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
5182 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
5183 break;
5184 case x86::kPCRel8:
5185 case x86::kPCRel16:
5186 case x86::kPCRel32:
5187 case x86::kPCRel32WeakImport:
5188 case x86::kDtraceProbeSite:
5189 case x86::kDtraceIsEnabledSite:
5190 {
5191 if ( isExtern )
5192 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5193 else
5194 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5195 if ( kind == x86::kPCRel8 ) {
5196 displacement += 3;
5197 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
5198 //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());
5199 throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
5200 }
5201 int8_t byte = (int8_t)displacement;
5202 *((int8_t*)fixUp) = byte;
5203 }
5204 else if ( kind == x86::kPCRel16 ) {
5205 displacement += 2;
5206 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
5207 //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());
5208 throwf("rel16 out of range in %s", inAtom->getDisplayName());
5209 }
5210 int16_t word = (int16_t)displacement;
5211 LittleEndian::set16(*((uint16_t*)fixUp), word);
5212 }
5213 else {
5214 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
5215 //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement,
5216 // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
5217 throwf("rel32 out of range in %s", inAtom->getDisplayName());
5218 }
5219 LittleEndian::set32(*fixUp, (int32_t)displacement);
5220 }
5221 }
5222 break;
5223 case x86::kDtraceProbe:
5224 case x86::kDtraceTypeReference:
5225 // nothing to fix up
5226 break;
5227 }
5228 }
5229
5230 template <>
5231 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5232 {
5233 const int64_t twoGigLimit = 0x7FFFFFFF;
5234 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
5235 uint8_t* dtraceProbeSite;
5236 int64_t displacement = 0;
5237 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
5238 case x86_64::kNoFixUp:
5239 case x86_64::kFollowOn:
5240 case x86_64::kGroupSubordinate:
5241 // do nothing
5242 break;
5243 case x86_64::kPointerWeakImport:
5244 case x86_64::kPointer:
5245 {
5246 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
5247 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
5248 // external relocation ==> pointer contains addend
5249 LittleEndian::set64(*fixUp, ref->getTargetOffset());
5250 }
5251 else {
5252 // internal relocation
5253 // pointer contains target address
5254 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
5255 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5256 }
5257 }
5258 break;
5259 case x86_64::kPointerDiff32:
5260 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
5261 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
5262 throw "32-bit pointer difference out of range";
5263 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
5264 break;
5265 case x86_64::kPointerDiff:
5266 LittleEndian::set64(*fixUp,
5267 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5268 break;
5269 case x86_64::kPCRel32GOTLoad:
5270 case x86_64::kPCRel32GOTLoadWeakImport:
5271 // if GOT entry was optimized away, change movq instruction to a leaq
5272 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
5273 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
5274 uint8_t* opcodes = (uint8_t*)fixUp;
5275 if ( opcodes[-2] != 0x8B )
5276 throw "GOT load reloc does not point to a movq instruction";
5277 opcodes[-2] = 0x8D;
5278 }
5279 // fall into general rel32 case
5280 case x86_64::kBranchPCRel32WeakImport:
5281 case x86_64::kBranchPCRel32:
5282 case x86_64::kBranchPCRel8:
5283 case x86_64::kPCRel32:
5284 case x86_64::kPCRel32_1:
5285 case x86_64::kPCRel32_2:
5286 case x86_64::kPCRel32_4:
5287 case x86_64::kPCRel32GOT:
5288 case x86_64::kPCRel32GOTWeakImport:
5289 switch ( ref->getTarget().getDefinitionKind() ) {
5290 case ObjectFile::Atom::kRegularDefinition:
5291 case ObjectFile::Atom::kWeakDefinition:
5292 case ObjectFile::Atom::kTentativeDefinition:
5293 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5294 break;
5295 case ObjectFile::Atom::kAbsoluteSymbol:
5296 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5297 break;
5298 case ObjectFile::Atom::kExternalDefinition:
5299 case ObjectFile::Atom::kExternalWeakDefinition:
5300 throw "codegen problem, can't use rel32 to external symbol";
5301 break;
5302 }
5303 switch ( ref->getKind() ) {
5304 case x86_64::kPCRel32_1:
5305 displacement -= 1;
5306 break;
5307 case x86_64::kPCRel32_2:
5308 displacement -= 2;
5309 break;
5310 case x86_64::kPCRel32_4:
5311 displacement -= 4;
5312 break;
5313 case x86_64::kBranchPCRel8:
5314 displacement += 3;
5315 break;
5316 }
5317 if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
5318 if ( (displacement > 127) || (displacement < (-128)) ) {
5319 fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n",
5320 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
5321 throw "rel8 out of range";
5322 }
5323 *((int8_t*)fixUp) = (int8_t)displacement;
5324 }
5325 else {
5326 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
5327 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
5328 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
5329 throw "rel32 out of range";
5330 }
5331 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
5332 }
5333 break;
5334 case x86_64::kDtraceProbeSite:
5335 // change call site to a NOP
5336 dtraceProbeSite = (uint8_t*)fixUp;
5337 dtraceProbeSite[-1] = 0x90; // 1-byte nop
5338 dtraceProbeSite[0] = 0x0F; // 4-byte nop
5339 dtraceProbeSite[1] = 0x1F;
5340 dtraceProbeSite[2] = 0x40;
5341 dtraceProbeSite[3] = 0x00;
5342 break;
5343 case x86_64::kDtraceIsEnabledSite:
5344 // change call site to a clear eax
5345 dtraceProbeSite = (uint8_t*)fixUp;
5346 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
5347 dtraceProbeSite[0] = 0x33;
5348 dtraceProbeSite[1] = 0xC0;
5349 dtraceProbeSite[2] = 0x90; // 1-byte nop
5350 dtraceProbeSite[3] = 0x90; // 1-byte nop
5351 break;
5352 case x86_64::kDtraceTypeReference:
5353 case x86_64::kDtraceProbe:
5354 // nothing to fix up
5355 break;
5356 }
5357 }
5358
5359 template <>
5360 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5361 {
5362 const int64_t twoGigLimit = 0x7FFFFFFF;
5363 bool external = this->makesExternalRelocatableReference(ref->getTarget());
5364 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
5365 int64_t displacement = 0;
5366 int32_t temp32;
5367 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
5368 case x86_64::kNoFixUp:
5369 case x86_64::kFollowOn:
5370 case x86_64::kGroupSubordinate:
5371 // do nothing
5372 break;
5373 case x86_64::kPointer:
5374 case x86_64::kPointerWeakImport:
5375 {
5376 if ( external ) {
5377 // external relocation ==> pointer contains addend
5378 LittleEndian::set64(*fixUp, ref->getTargetOffset());
5379 }
5380 else {
5381 // internal relocation ==> pointer contains target address
5382 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
5383 }
5384 }
5385 break;
5386 case x86_64::kPointerDiff32:
5387 // addend in content
5388 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
5389 break;
5390 case x86_64::kPointerDiff:
5391 // addend in content
5392 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
5393 break;
5394 case x86_64::kBranchPCRel32:
5395 case x86_64::kBranchPCRel32WeakImport:
5396 case x86_64::kDtraceProbeSite:
5397 case x86_64::kDtraceIsEnabledSite:
5398 case x86_64::kPCRel32:
5399 case x86_64::kPCRel32_1:
5400 case x86_64::kPCRel32_2:
5401 case x86_64::kPCRel32_4:
5402 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
5403 temp32 = ref->getTargetOffset();
5404 if ( external ) {
5405 // extern relocation contains addend
5406 displacement = temp32;
5407 }
5408 else {
5409 // internal relocations contain delta to target address
5410 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
5411 }
5412 switch ( ref->getKind() ) {
5413 case x86_64::kPCRel32_1:
5414 displacement -= 1;
5415 break;
5416 case x86_64::kPCRel32_2:
5417 displacement -= 2;
5418 break;
5419 case x86_64::kPCRel32_4:
5420 displacement -= 4;
5421 break;
5422 }
5423 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
5424 //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());
5425 throw "rel32 out of range";
5426 }
5427 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
5428 break;
5429 case x86_64::kBranchPCRel8:
5430 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
5431 temp32 = ref->getTargetOffset();
5432 if ( external ) {
5433 // extern relocation contains addend
5434 displacement = temp32;
5435 }
5436 else {
5437 // internal relocations contain delta to target address
5438 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
5439 }
5440 if ( (displacement > 127) || (displacement < (-128)) ) {
5441 //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());
5442 throw "rel8 out of range";
5443 }
5444 *((int8_t*)fixUp) = (int8_t)displacement;
5445 break;
5446 case x86_64::kPCRel32GOT:
5447 case x86_64::kPCRel32GOTLoad:
5448 case x86_64::kPCRel32GOTWeakImport:
5449 case x86_64::kPCRel32GOTLoadWeakImport:
5450 // contains addend (usually zero)
5451 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
5452 break;
5453 case x86_64::kDtraceTypeReference:
5454 case x86_64::kDtraceProbe:
5455 // nothing to fix up
5456 break;
5457 }
5458 }
5459
5460 template <>
5461 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5462 {
5463 fixUpReference_powerpc(ref, inAtom, buffer, true);
5464 }
5465
5466 template <>
5467 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5468 {
5469 fixUpReference_powerpc(ref, inAtom, buffer, true);
5470 }
5471
5472 template <>
5473 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5474 {
5475 fixUpReference_powerpc(ref, inAtom, buffer, false);
5476 }
5477
5478 template <>
5479 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5480 {
5481 fixUpReference_powerpc(ref, inAtom, buffer, false);
5482 }
5483
5484 //
5485 // ppc and ppc64 are mostly the same, so they share a template specialzation
5486 //
5487 template <typename A>
5488 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
5489 {
5490 uint32_t instruction;
5491 uint32_t newInstruction;
5492 int64_t displacement;
5493 uint64_t targetAddr = 0;
5494 uint64_t picBaseAddr;
5495 uint16_t instructionLowHalf;
5496 uint16_t instructionHighHalf;
5497 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
5498 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
5499 bool relocateableExternal = false;
5500 const int64_t picbase_twoGigLimit = 0x80000000;
5501
5502 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
5503 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
5504 if ( finalLinkedImage )
5505 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
5506 else
5507 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
5508 }
5509
5510 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
5511 case A::kNoFixUp:
5512 case A::kFollowOn:
5513 case A::kGroupSubordinate:
5514 // do nothing
5515 break;
5516 case A::kPointerWeakImport:
5517 case A::kPointer:
5518 {
5519 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
5520 if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers
5521 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
5522 switch (ref->getTarget().getDefinitionKind()) {
5523 case ObjectFile::Atom::kExternalDefinition:
5524 case ObjectFile::Atom::kExternalWeakDefinition:
5525 // prebound lazy pointer to another dylib ==> pointer contains zero
5526 P::setP(*fixUpPointer, 0);
5527 break;
5528 case ObjectFile::Atom::kTentativeDefinition:
5529 case ObjectFile::Atom::kRegularDefinition:
5530 case ObjectFile::Atom::kWeakDefinition:
5531 case ObjectFile::Atom::kAbsoluteSymbol:
5532 // prebound lazy pointer to withing this dylib ==> pointer contains address
5533 P::setP(*fixUpPointer, targetAddr);
5534 break;
5535 }
5536 }
5537 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
5538 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
5539 if ( this->indirectSymbolIsLocal(ref) )
5540 P::setP(*fixUpPointer, targetAddr);
5541 else
5542 P::setP(*fixUpPointer, 0);
5543 }
5544 else if ( relocateableExternal ) {
5545 if ( fOptions.prebind() ) {
5546 switch (ref->getTarget().getDefinitionKind()) {
5547 case ObjectFile::Atom::kExternalDefinition:
5548 case ObjectFile::Atom::kExternalWeakDefinition:
5549 // prebound external relocation ==> pointer contains addend
5550 P::setP(*fixUpPointer, ref->getTargetOffset());
5551 break;
5552 case ObjectFile::Atom::kTentativeDefinition:
5553 case ObjectFile::Atom::kRegularDefinition:
5554 case ObjectFile::Atom::kWeakDefinition:
5555 // prebound external relocation to internal atom ==> pointer contains target address + addend
5556 P::setP(*fixUpPointer, targetAddr);
5557 break;
5558 case ObjectFile::Atom::kAbsoluteSymbol:
5559 break;
5560 }
5561 }
5562 else {
5563 // external relocation ==> pointer contains addend
5564 P::setP(*fixUpPointer, ref->getTargetOffset());
5565 }
5566 }
5567 else {
5568 // internal relocation
5569 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
5570 // pointer contains target address
5571 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
5572 P::setP(*fixUpPointer, targetAddr);
5573 }
5574 else {
5575 // pointer contains addend
5576 P::setP(*fixUpPointer, ref->getTargetOffset());
5577 }
5578 }
5579 }
5580 break;
5581 case A::kPointerDiff64:
5582 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5583 break;
5584 case A::kPointerDiff32:
5585 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5586 break;
5587 case A::kPointerDiff16:
5588 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
5589 break;
5590 case A::kDtraceProbeSite:
5591 if ( finalLinkedImage ) {
5592 // change call site to a NOP
5593 BigEndian::set32(*fixUp, 0x60000000);
5594 }
5595 else {
5596 // set bl instuction to branch to address zero in .o file
5597 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
5598 instruction = BigEndian::get32(*fixUp);
5599 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
5600 BigEndian::set32(*fixUp, newInstruction);
5601 }
5602 break;
5603 case A::kDtraceIsEnabledSite:
5604 if ( finalLinkedImage ) {
5605 // change call site to a li r3,0
5606 BigEndian::set32(*fixUp, 0x38600000);
5607 }
5608 else {
5609 // set bl instuction to branch to address zero in .o file
5610 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
5611 instruction = BigEndian::get32(*fixUp);
5612 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
5613 BigEndian::set32(*fixUp, newInstruction);
5614 }
5615 break;
5616 case A::kBranch24WeakImport:
5617 case A::kBranch24:
5618 {
5619 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
5620 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
5621 if ( relocateableExternal ) {
5622 // doing "ld -r" to an external symbol
5623 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
5624 displacement -= ref->getTarget().getAddress();
5625 }
5626 else {
5627 const int64_t bl_eightMegLimit = 0x00FFFFFF;
5628 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
5629 //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());
5630 throwf("bl out of range (%lld max is +/-16M) from %s at 0x%08llX in %s of %s to %s at 0x%08llX in %s of %s",
5631 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
5632 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
5633 }
5634 }
5635 instruction = BigEndian::get32(*fixUp);
5636 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
5637 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
5638 BigEndian::set32(*fixUp, newInstruction);
5639 }
5640 break;
5641 case A::kBranch14:
5642 {
5643 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
5644 if ( relocateableExternal ) {
5645 // doing "ld -r" to an external symbol
5646 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
5647 displacement -= ref->getTarget().getAddress();
5648 }
5649 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
5650 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
5651 //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());
5652 throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
5653 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
5654 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
5655 }
5656
5657 //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
5658 instruction = BigEndian::get32(*fixUp);
5659 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
5660 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
5661 BigEndian::set32(*fixUp, newInstruction);
5662 }
5663 break;
5664 case A::kPICBaseLow16:
5665 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
5666 displacement = targetAddr - picBaseAddr;
5667 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
5668 throw "32-bit pic-base out of range";
5669 instructionLowHalf = (displacement & 0xFFFF);
5670 instruction = BigEndian::get32(*fixUp);
5671 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
5672 BigEndian::set32(*fixUp, newInstruction);
5673 break;
5674 case A::kPICBaseLow14:
5675 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
5676 displacement = targetAddr - picBaseAddr;
5677 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
5678 throw "32-bit pic-base out of range";
5679 if ( (displacement & 0x3) != 0 )
5680 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
5681 instructionLowHalf = (displacement & 0xFFFC);
5682 instruction = BigEndian::get32(*fixUp);
5683 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
5684 BigEndian::set32(*fixUp, newInstruction);
5685 break;
5686 case A::kPICBaseHigh16:
5687 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
5688 displacement = targetAddr - picBaseAddr;
5689 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
5690 throw "32-bit pic-base out of range";
5691 instructionLowHalf = displacement >> 16;
5692 if ( (displacement & 0x00008000) != 0 )
5693 ++instructionLowHalf;
5694 instruction = BigEndian::get32(*fixUp);
5695 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
5696 BigEndian::set32(*fixUp, newInstruction);
5697 break;
5698 case A::kAbsLow16:
5699 if ( relocateableExternal && !finalLinkedImage )
5700 targetAddr -= ref->getTarget().getAddress();
5701 instructionLowHalf = (targetAddr & 0xFFFF);
5702 instruction = BigEndian::get32(*fixUp);
5703 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
5704 BigEndian::set32(*fixUp, newInstruction);
5705 break;
5706 case A::kAbsLow14:
5707 if ( relocateableExternal && !finalLinkedImage )
5708 targetAddr -= ref->getTarget().getAddress();
5709 if ( (targetAddr & 0x3) != 0 )
5710 throw "bad address for absolute lo14 instruction fix-up";
5711 instructionLowHalf = (targetAddr & 0xFFFF);
5712 instruction = BigEndian::get32(*fixUp);
5713 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
5714 BigEndian::set32(*fixUp, newInstruction);
5715 break;
5716 case A::kAbsHigh16:
5717 if ( relocateableExternal ) {
5718 if ( finalLinkedImage ) {
5719 switch (ref->getTarget().getDefinitionKind()) {
5720 case ObjectFile::Atom::kExternalDefinition:
5721 case ObjectFile::Atom::kExternalWeakDefinition:
5722 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
5723 break;
5724 case ObjectFile::Atom::kTentativeDefinition:
5725 case ObjectFile::Atom::kRegularDefinition:
5726 case ObjectFile::Atom::kWeakDefinition:
5727 // use target address
5728 break;
5729 case ObjectFile::Atom::kAbsoluteSymbol:
5730 targetAddr = ref->getTarget().getSectionOffset();
5731 break;
5732 }
5733 }
5734 else {
5735 targetAddr -= ref->getTarget().getAddress();
5736 }
5737 }
5738 instructionHighHalf = (targetAddr >> 16);
5739 instruction = BigEndian::get32(*fixUp);
5740 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
5741 BigEndian::set32(*fixUp, newInstruction);
5742 break;
5743 case A::kAbsHigh16AddLow:
5744 if ( relocateableExternal ) {
5745 if ( finalLinkedImage ) {
5746 switch (ref->getTarget().getDefinitionKind()) {
5747 case ObjectFile::Atom::kExternalDefinition:
5748 case ObjectFile::Atom::kExternalWeakDefinition:
5749 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
5750 break;
5751 case ObjectFile::Atom::kTentativeDefinition:
5752 case ObjectFile::Atom::kRegularDefinition:
5753 case ObjectFile::Atom::kWeakDefinition:
5754 // use target address
5755 break;
5756 case ObjectFile::Atom::kAbsoluteSymbol:
5757 targetAddr = ref->getTarget().getSectionOffset();
5758 break;
5759 }
5760 }
5761 else {
5762 targetAddr -= ref->getTarget().getAddress();
5763 }
5764 }
5765 if ( targetAddr & 0x00008000 )
5766 targetAddr += 0x00010000;
5767 instruction = BigEndian::get32(*fixUp);
5768 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
5769 BigEndian::set32(*fixUp, newInstruction);
5770 break;
5771 case A::kDtraceTypeReference:
5772 case A::kDtraceProbe:
5773 // nothing to fix up
5774 break;
5775 }
5776 }
5777
5778 template <>
5779 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5780 {
5781 uint8_t kind = ref->getKind();
5782 switch ( (ppc::ReferenceKinds)kind ) {
5783 case ppc::kNoFixUp:
5784 case ppc::kFollowOn:
5785 case ppc::kGroupSubordinate:
5786 case ppc::kPointer:
5787 case ppc::kPointerWeakImport:
5788 case ppc::kPointerDiff16:
5789 case ppc::kPointerDiff32:
5790 case ppc::kPointerDiff64:
5791 case ppc::kDtraceProbe:
5792 case ppc::kDtraceProbeSite:
5793 case ppc::kDtraceIsEnabledSite:
5794 case ppc::kDtraceTypeReference:
5795 // these are never used to call external functions
5796 return false;
5797 case ppc::kBranch24:
5798 case ppc::kBranch24WeakImport:
5799 case ppc::kBranch14:
5800 // these are used to call external functions
5801 return true;
5802 case ppc::kPICBaseLow16:
5803 case ppc::kPICBaseLow14:
5804 case ppc::kPICBaseHigh16:
5805 case ppc::kAbsLow16:
5806 case ppc::kAbsLow14:
5807 case ppc::kAbsHigh16:
5808 case ppc::kAbsHigh16AddLow:
5809 // these are only used to call external functions
5810 // in -mlong-branch stubs
5811 switch ( ref->getTarget().getDefinitionKind() ) {
5812 case ObjectFile::Atom::kExternalDefinition:
5813 case ObjectFile::Atom::kExternalWeakDefinition:
5814 // if the .o file this atom came from has long-branch stubs,
5815 // then assume these instructions in a stub.
5816 // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
5817 return ( inAtom->getFile()->hasLongBranchStubs() );
5818 case ObjectFile::Atom::kTentativeDefinition:
5819 case ObjectFile::Atom::kRegularDefinition:
5820 case ObjectFile::Atom::kWeakDefinition:
5821 case ObjectFile::Atom::kAbsoluteSymbol:
5822 return false;
5823 }
5824 break;
5825 }
5826 return false;
5827 }
5828
5829 template <>
5830 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5831 {
5832 uint8_t kind = ref->getKind();
5833 switch ( (arm::ReferenceKinds)kind ) {
5834 case arm::kBranch24:
5835 case arm::kBranch24WeakImport:
5836 case arm::kThumbBranch22:
5837 case arm::kThumbBranch22WeakImport:
5838 return true;
5839 case arm::kNoFixUp:
5840 case arm::kFollowOn:
5841 case arm::kGroupSubordinate:
5842 case arm::kPointer:
5843 case arm::kReadOnlyPointer:
5844 case arm::kPointerWeakImport:
5845 case arm::kPointerDiff:
5846 case arm::kDtraceProbe:
5847 case arm::kDtraceProbeSite:
5848 case arm::kDtraceIsEnabledSite:
5849 case arm::kDtraceTypeReference:
5850 return false;
5851 }
5852 return false;
5853 }
5854
5855 template <>
5856 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5857 {
5858 uint8_t kind = ref->getKind();
5859 switch ( (ppc64::ReferenceKinds)kind ) {
5860 case ppc::kNoFixUp:
5861 case ppc::kFollowOn:
5862 case ppc::kGroupSubordinate:
5863 case ppc::kPointer:
5864 case ppc::kPointerWeakImport:
5865 case ppc::kPointerDiff16:
5866 case ppc::kPointerDiff32:
5867 case ppc::kPointerDiff64:
5868 case ppc::kPICBaseLow16:
5869 case ppc::kPICBaseLow14:
5870 case ppc::kPICBaseHigh16:
5871 case ppc::kAbsLow16:
5872 case ppc::kAbsLow14:
5873 case ppc::kAbsHigh16:
5874 case ppc::kAbsHigh16AddLow:
5875 case ppc::kDtraceProbe:
5876 case ppc::kDtraceProbeSite:
5877 case ppc::kDtraceIsEnabledSite:
5878 case ppc::kDtraceTypeReference:
5879 // these are never used to call external functions
5880 return false;
5881 case ppc::kBranch24:
5882 case ppc::kBranch24WeakImport:
5883 case ppc::kBranch14:
5884 // these are used to call external functions
5885 return true;
5886 }
5887 return false;
5888 }
5889
5890 template <>
5891 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5892 {
5893 uint8_t kind = ref->getKind();
5894 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
5895 }
5896
5897 template <>
5898 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
5899 {
5900 uint8_t kind = ref->getKind();
5901 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
5902 }
5903
5904
5905 template <>
5906 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
5907 {
5908 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
5909 }
5910
5911 template <>
5912 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
5913 {
5914 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
5915 }
5916
5917 template <>
5918 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
5919 {
5920 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
5921 }
5922
5923 template <>
5924 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
5925 {
5926 switch ( kind ) {
5927 case x86_64::kPointerWeakImport:
5928 case x86_64::kBranchPCRel32WeakImport:
5929 case x86_64::kPCRel32GOTWeakImport:
5930 case x86_64::kPCRel32GOTLoadWeakImport:
5931 return true;
5932 }
5933 return false;
5934 }
5935
5936 template <>
5937 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
5938 {
5939 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
5940 kind == arm::kPointerWeakImport);
5941 }
5942
5943 template <>
5944 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
5945 {
5946 return false;
5947 }
5948
5949 template <>
5950 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
5951 {
5952 return false;
5953 }
5954
5955 template <>
5956 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
5957 {
5958 return false;
5959 }
5960
5961 template <>
5962 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
5963 {
5964 switch ( kind ) {
5965 case x86_64::kPCRel32GOT:
5966 case x86_64::kPCRel32GOTWeakImport:
5967 case x86_64::kPCRel32GOTLoad:
5968 case x86_64::kPCRel32GOTLoadWeakImport:
5969 return true;
5970 }
5971 return false;
5972 }
5973
5974 template <>
5975 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
5976 {
5977 return false;
5978 }
5979
5980 template <>
5981 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
5982 {
5983 return false;
5984 }
5985
5986 template <>
5987 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
5988 {
5989 return false;
5990 }
5991
5992 template <>
5993 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
5994 {
5995 return false;
5996 }
5997
5998 template <>
5999 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
6000 {
6001 switch ( kind ) {
6002 case x86_64::kPCRel32GOTLoad:
6003 case x86_64::kPCRel32GOTLoadWeakImport:
6004 return true;
6005 }
6006 return false;
6007 }
6008
6009 template <>
6010 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
6011 {
6012 return false;
6013 }
6014
6015 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
6016 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
6017 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
6018 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
6019
6020
6021 template <typename A>
6022 void Writer<A>::optimizeDylibReferences()
6023 {
6024 //fprintf(stderr, "original ordinals table:\n");
6025 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
6026 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
6027 //}
6028 // find unused dylibs that can be removed
6029 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
6030 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
6031 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
6032 ObjectFile::Reader* reader = it->first;
6033 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
6034 if ( aliasPos != fLibraryAliases.end() ) {
6035 // already noticed that this reader has same install name as another reader
6036 readerAliases[reader] = aliasPos->second;
6037 }
6038 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || fOptions.deadStripDylibs()) ) {
6039 // this reader can be optimized away
6040 it->second = 0xFFFFFFFF;
6041 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
6042 if ( pos != fLibraryToLoadCommand.end() )
6043 pos->second->optimizeAway();
6044 }
6045 else {
6046 // mark this reader as using it ordinal
6047 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
6048 if ( pos == ordinalToReader.end() )
6049 ordinalToReader[it->second] = reader;
6050 else
6051 readerAliases[reader] = pos->second;
6052 }
6053 }
6054 // renumber ordinals (depends on iterator walking in ordinal order)
6055 // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
6056 uint32_t newOrdinal = 0;
6057 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
6058 if ( it->first <= fLibraryToOrdinal.size() ) {
6059 if ( ! it->second->isLazyLoadedDylib() )
6060 fLibraryToOrdinal[it->second] = ++newOrdinal;
6061 }
6062 }
6063 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
6064 if ( it->first <= fLibraryToOrdinal.size() ) {
6065 if ( it->second->isLazyLoadedDylib() ) {
6066 fLibraryToOrdinal[it->second] = ++newOrdinal;
6067 }
6068 }
6069 }
6070
6071 // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
6072 if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
6073 throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
6074
6075 // add aliases (e.g. -lm points to libSystem.dylib)
6076 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
6077 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
6078 }
6079
6080 //fprintf(stderr, "new ordinals table:\n");
6081 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
6082 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
6083 //}
6084 }
6085
6086
6087 template <>
6088 void Writer<arm>::scanForAbsoluteReferences()
6089 {
6090 // arm codegen never has absolute references. FIXME: Is this correct?
6091 }
6092
6093 template <>
6094 void Writer<x86_64>::scanForAbsoluteReferences()
6095 {
6096 // x86_64 codegen never has absolute references
6097 }
6098
6099 template <>
6100 void Writer<x86>::scanForAbsoluteReferences()
6101 {
6102 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
6103 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
6104 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6105 ObjectFile::Atom* atom = *it;
6106 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6107 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6108 ObjectFile::Reference* ref = *rit;
6109 switch (ref->getKind()) {
6110 case x86::kAbsolute32:
6111 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
6112 return;
6113 }
6114 }
6115 }
6116 }
6117 }
6118
6119 template <>
6120 void Writer<ppc>::scanForAbsoluteReferences()
6121 {
6122 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
6123 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
6124 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6125 ObjectFile::Atom* atom = *it;
6126 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6127 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6128 ObjectFile::Reference* ref = *rit;
6129 switch (ref->getKind()) {
6130 case ppc::kAbsLow16:
6131 case ppc::kAbsLow14:
6132 case ppc::kAbsHigh16:
6133 case ppc::kAbsHigh16AddLow:
6134 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
6135 return;
6136 }
6137 }
6138 }
6139 }
6140 }
6141
6142
6143 // for ppc64 look for any -mdynamic-no-pic codegen
6144 template <>
6145 void Writer<ppc64>::scanForAbsoluteReferences()
6146 {
6147 // only do this for main executable
6148 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
6149 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6150 ObjectFile::Atom* atom = *it;
6151 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6152 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6153 ObjectFile::Reference* ref = *rit;
6154 switch (ref->getKind()) {
6155 case ppc64::kAbsLow16:
6156 case ppc64::kAbsLow14:
6157 case ppc64::kAbsHigh16:
6158 case ppc64::kAbsHigh16AddLow:
6159 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
6160 // shrink page-zero and add pad segment to compensate
6161 fPadSegmentInfo = new SegmentInfo();
6162 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
6163 fPageZeroAtom->setSize(0x1000);
6164 return;
6165 }
6166 }
6167 }
6168 }
6169 }
6170
6171
6172 template <typename A>
6173 void Writer<A>::insertDummyStubs()
6174 {
6175 // only needed for x86
6176 }
6177
6178 template <>
6179 void Writer<x86>::insertDummyStubs()
6180 {
6181 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
6182 std::vector<class StubAtom<x86>*> betterStubs;
6183 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
6184 switch (betterStubs.size() % 64 ) {
6185 case 12:// stub would occupy 0x3C->0x41
6186 case 25:// stub would occupy 0x7D->0x82
6187 case 38:// stub would occupy 0xBE->0xC3
6188 case 51:// stub would occupy 0xFF->0x04
6189 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
6190 break;
6191 }
6192 betterStubs.push_back(*it);
6193 }
6194 // replace
6195 fAllSynthesizedStubs.clear();
6196 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
6197 }
6198
6199 template <typename A>
6200 void Writer<A>::synthesizeStubs()
6201 {
6202 switch ( fOptions.outputKind() ) {
6203 case Options::kObjectFile:
6204 // these output kinds never have stubs
6205 return;
6206 case Options::kStaticExecutable:
6207 case Options::kDyld:
6208 case Options::kDynamicLibrary:
6209 case Options::kDynamicBundle:
6210 case Options::kDynamicExecutable:
6211 // try to synthesize stubs for these
6212 break;
6213 }
6214
6215 // walk every atom and reference
6216 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6217 ObjectFile::Atom* atom = *it;
6218 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6219 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6220 ObjectFile::Reference* ref = *rit;
6221 switch ( ref->getTargetBinding()) {
6222 case ObjectFile::Reference::kUnboundByName:
6223 case ObjectFile::Reference::kDontBind:
6224 break;
6225 case ObjectFile::Reference::kBoundByName:
6226 case ObjectFile::Reference::kBoundDirectly:
6227 ObjectFile::Atom& target = ref->getTarget();
6228 // build map of which symbols need weak importing
6229 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
6230 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
6231 bool weakImport = this->weakImportReferenceKind(ref->getKind());
6232 // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
6233 // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
6234 // in dylibs that are weakly linked.
6235 if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
6236 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
6237 pos = fLibraryToLoadCommand.find(target.getFile());
6238 if ( pos != fLibraryToLoadCommand.end() ) {
6239 if ( pos->second->linkedWeak() )
6240 weakImport = true;
6241 }
6242 }
6243 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
6244 if ( pos == fWeakImportMap.end() ) {
6245 // target not in fWeakImportMap, so add
6246 fWeakImportMap[&target] = weakImport;
6247 }
6248 else {
6249 // target in fWeakImportMap, check for weakness mismatch
6250 if ( pos->second != weakImport ) {
6251 // found mismatch
6252 switch ( fOptions.weakReferenceMismatchTreatment() ) {
6253 case Options::kWeakReferenceMismatchError:
6254 throwf("mismatching weak references for symbol: %s", target.getName());
6255 case Options::kWeakReferenceMismatchWeak:
6256 pos->second = true;
6257 break;
6258 case Options::kWeakReferenceMismatchNonWeak:
6259 pos->second = false;
6260 break;
6261 }
6262 }
6263 }
6264 // update if we use a weak_import or a strong import from this dylib
6265 if ( fWeakImportMap[&target] )
6266 fDylibReadersWithWeakImports.insert(target.getFile());
6267 else
6268 fDylibReadersWithNonWeakImports.insert(target.getFile());
6269 }
6270 // create stubs as needed
6271 if ( this->stubableReference(atom, ref)
6272 && (ref->getTargetOffset() == 0)
6273 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
6274 ObjectFile::Atom* stub = NULL;
6275 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
6276 if ( pos == fStubsMap.end() ) {
6277 bool forLazyDylib = false;
6278 switch ( target.getDefinitionKind() ) {
6279 case ObjectFile::Atom::kRegularDefinition:
6280 case ObjectFile::Atom::kWeakDefinition:
6281 case ObjectFile::Atom::kAbsoluteSymbol:
6282 case ObjectFile::Atom::kTentativeDefinition:
6283 break;
6284 case ObjectFile::Atom::kExternalDefinition:
6285 case ObjectFile::Atom::kExternalWeakDefinition:
6286 if ( target.getFile()->isLazyLoadedDylib() )
6287 forLazyDylib = true;
6288 break;
6289 }
6290 stub = new StubAtom<A>(*this, target, forLazyDylib);
6291 fStubsMap[&target] = stub;
6292 }
6293 else {
6294 stub = pos->second;
6295 }
6296 // alter reference to use stub instead
6297 ref->setTarget(*stub, 0);
6298 }
6299 else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
6300 throwf("illegal reference to %s in lazy loaded dylib from %s in %s",
6301 target.getDisplayName(), atom->getDisplayName(),
6302 atom->getFile()->getPath());
6303 }
6304 // create GOT slots (non-lazy pointers) as needed
6305 else if ( this->GOTReferenceKind(ref->getKind()) ) {
6306 //
6307 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
6308 bool useGOT;
6309 if ( fBiggerThanTwoGigs ) {
6310 // in big images use GOT for all zero fill atoms
6311 // this is just a heuristic and may need to be re-examined
6312 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
6313 }
6314 else {
6315 // < 2GB image so remove all GOT entries that we can
6316 useGOT = mustUseGOT;
6317 }
6318 // if this GOT usage cannot be optimized away then make a GOT enry
6319 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
6320 useGOT = true;
6321 if ( useGOT ) {
6322 ObjectFile::Atom* nlp = NULL;
6323 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
6324 if ( pos == fGOTMap.end() ) {
6325 nlp = new NonLazyPointerAtom<A>(*this, target);
6326 fGOTMap[&target] = nlp;
6327 }
6328 else {
6329 nlp = pos->second;
6330 }
6331 // alter reference to use non lazy pointer instead
6332 ref->setTarget(*nlp, ref->getTargetOffset());
6333 }
6334 }
6335 }
6336 }
6337 }
6338
6339 // sort stubs
6340 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
6341
6342 // add dummy fast stubs (x86 only)
6343 if ( !fOptions.slowx86Stubs() )
6344 this->insertDummyStubs();
6345
6346 // sort lazy pointers
6347 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
6348 std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
6349
6350
6351 // add stubs to fAllAtoms
6352 if ( fAllSynthesizedStubs.size() != 0 ) {
6353 std::vector<ObjectFile::Atom*> textStubs;
6354 std::vector<ObjectFile::Atom*> importStubs;
6355 for (typename std::vector<class StubAtom<A>*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) {
6356 ObjectFile::Atom* stubAtom = *sit;
6357 if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 )
6358 textStubs.push_back(stubAtom);
6359 else
6360 importStubs.push_back(stubAtom);
6361 }
6362 // any helper stubs go right after regular stubs
6363 if ( fAllSynthesizedStubHelpers.size() != 0 )
6364 textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
6365 // insert text stubs right after __text section
6366 ObjectFile::Section* curSection = NULL;
6367 ObjectFile::Atom* prevAtom = NULL;
6368 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6369 ObjectFile::Atom* atom = *it;
6370 ObjectFile::Section* nextSection = atom->getSection();
6371 if ( nextSection != curSection ) {
6372 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
6373 // found end of __text section, insert stubs here
6374 fAllAtoms->insert(it, textStubs.begin(), textStubs.end());
6375 break;
6376 }
6377 curSection = nextSection;
6378 }
6379 prevAtom = atom;
6380 }
6381 if ( importStubs.size() != 0 ) {
6382 // insert __IMPORTS stubs right before __LINKEDIT
6383 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6384 ObjectFile::Atom* atom = *it;
6385 ObjectFile::Section* nextSection = atom->getSection();
6386 if ( nextSection != curSection ) {
6387 // for i386 where stubs are not in __TEXT segment
6388 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
6389 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
6390 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
6391 fAllAtoms->insert(it, importStubs.begin(), importStubs.end());
6392 break;
6393 }
6394 curSection = nextSection;
6395 }
6396 prevAtom = atom;
6397 }
6398 }
6399 }
6400
6401
6402 // add lazy dylib pointers to fAllAtoms
6403 if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) {
6404 ObjectFile::Section* curSection = NULL;
6405 ObjectFile::Atom* prevAtom = NULL;
6406 bool inserted = false;
6407 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6408 ObjectFile::Atom* atom = *it;
6409 ObjectFile::Section* nextSection = atom->getSection();
6410 if ( nextSection != curSection ) {
6411 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
6412 // found end of __dyld section, insert lazy pointers here
6413 fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
6414 inserted = true;
6415 break;
6416 }
6417 curSection = nextSection;
6418 }
6419 prevAtom = atom;
6420 }
6421 if ( !inserted ) {
6422 throw "can't insert lazy pointers, __dyld section not found";
6423 }
6424 }
6425
6426 // add lazy pointers to fAllAtoms
6427 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
6428 ObjectFile::Section* curSection = NULL;
6429 ObjectFile::Atom* prevAtom = NULL;
6430 bool inserted = false;
6431 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6432 ObjectFile::Atom* atom = *it;
6433 ObjectFile::Section* nextSection = atom->getSection();
6434 if ( nextSection != curSection ) {
6435 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
6436 // found end of __dyld section, insert lazy pointers here
6437 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
6438 inserted = true;
6439 break;
6440 }
6441 curSection = nextSection;
6442 }
6443 prevAtom = atom;
6444 }
6445 if ( !inserted ) {
6446 throw "can't insert lazy pointers, __dyld section not found";
6447 }
6448 }
6449
6450 // add non-lazy pointers to fAllAtoms
6451 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
6452 ObjectFile::Section* curSection = NULL;
6453 ObjectFile::Atom* prevAtom = NULL;
6454 bool inserted = false;
6455 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6456 ObjectFile::Atom* atom = *it;
6457 ObjectFile::Section* nextSection = atom->getSection();
6458 if ( nextSection != curSection ) {
6459 if ( (prevAtom != NULL)
6460 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
6461 || ((strcmp(prevAtom->getSectionName(), "__data") == 0) &&
6462 ((fOptions.outputKind() == Options::kDyld) || (fOptions.outputKind() == Options::kStaticExecutable))) ) ) {
6463 // found end of __dyld section, insert lazy pointers here
6464 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
6465 inserted = true;
6466 break;
6467 }
6468 curSection = nextSection;
6469 }
6470 prevAtom = atom;
6471 }
6472 if ( !inserted ) {
6473 throw "can't insert non-lazy pointers, __dyld section not found";
6474 }
6475 }
6476
6477 // build LC_SEGMENT_SPLIT_INFO content now that all atoms exist
6478 if ( fSplitCodeToDataContentAtom != NULL ) {
6479 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6480 ObjectFile::Atom* atom = *it;
6481 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6482 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6483 ObjectFile::Reference* ref = *rit;
6484 switch ( ref->getTargetBinding()) {
6485 case ObjectFile::Reference::kUnboundByName:
6486 case ObjectFile::Reference::kDontBind:
6487 break;
6488 case ObjectFile::Reference::kBoundByName:
6489 case ObjectFile::Reference::kBoundDirectly:
6490 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
6491 this->addCrossSegmentRef(atom, ref);
6492 }
6493 break;
6494 }
6495 }
6496 }
6497 }
6498
6499 }
6500
6501
6502 template <typename A>
6503 void Writer<A>::partitionIntoSections()
6504 {
6505 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
6506
6507 // for every atom, set its sectionInfo object and section offset
6508 // build up fSegmentInfos along the way
6509 ObjectFile::Section* curSection = NULL;
6510 SectionInfo* currentSectionInfo = NULL;
6511 SegmentInfo* currentSegmentInfo = NULL;
6512 SectionInfo* cstringSectionInfo = NULL;
6513 unsigned int sectionIndex = 1;
6514 fSegmentInfos.reserve(8);
6515 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
6516 ObjectFile::Atom* atom = (*fAllAtoms)[i];
6517 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
6518 if ( oneSegmentCommand ) {
6519 if ( currentSegmentInfo == NULL ) {
6520 currentSegmentInfo = new SegmentInfo();
6521 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6522 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6523 this->fSegmentInfos.push_back(currentSegmentInfo);
6524 }
6525 currentSectionInfo = new SectionInfo();
6526 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
6527 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
6528 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
6529 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
6530 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
6531 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
6532 currentSectionInfo->setIndex(sectionIndex++);
6533 currentSegmentInfo->fSections.push_back(currentSectionInfo);
6534 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
6535 cstringSectionInfo = currentSectionInfo;
6536 }
6537 else {
6538 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
6539 currentSegmentInfo = new SegmentInfo();
6540 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
6541 uint32_t initprot = 0;
6542 if ( atom->getSegment().isContentReadable() )
6543 initprot |= VM_PROT_READ;
6544 if ( atom->getSegment().isContentWritable() )
6545 initprot |= VM_PROT_WRITE;
6546 if ( atom->getSegment().isContentExecutable() )
6547 initprot |= VM_PROT_EXECUTE;
6548 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
6549 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
6550 currentSegmentInfo->fInitProtection = initprot;
6551 if ( initprot == 0 )
6552 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
6553 else
6554 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
6555 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
6556 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
6557 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
6558 currentSegmentInfo->fInitProtection = it->init;
6559 currentSegmentInfo->fMaxProtection = it->max;
6560 }
6561 }
6562 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
6563 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
6564 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
6565 currentSegmentInfo->fIndependentAddress = true;
6566 this->fSegmentInfos.push_back(currentSegmentInfo);
6567 }
6568 currentSectionInfo = new SectionInfo();
6569 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
6570 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
6571 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
6572 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
6573 // check for -sectalign override
6574 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
6575 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
6576 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
6577 currentSectionInfo->fAlignment = it->alignment;
6578 }
6579 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
6580 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
6581 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
6582 currentSectionInfo->setIndex(sectionIndex++);
6583 currentSegmentInfo->fSections.push_back(currentSectionInfo);
6584 }
6585 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
6586 fLoadCommandsSection = currentSectionInfo;
6587 fLoadCommandsSegment = currentSegmentInfo;
6588 }
6589 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
6590 currentSectionInfo->fAllLazyPointers = true;
6591 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
6592 currentSectionInfo->fAllLazyPointers = true;
6593 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) )
6594 currentSectionInfo->fAllLazyDylibPointers = true;
6595 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
6596 currentSectionInfo->fAllNonLazyPointers = true;
6597 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
6598 currentSectionInfo->fAllNonLazyPointers = true;
6599 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
6600 currentSectionInfo->fAllNonLazyPointers = true;
6601 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
6602 currentSectionInfo->fAllStubs = true;
6603 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
6604 currentSectionInfo->fAllStubs = true;
6605 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
6606 currentSectionInfo->fAllStubs = true;
6607 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
6608 currentSectionInfo->fAllStubs = true;
6609 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) )
6610 currentSectionInfo->fAllStubs = true;
6611 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) )
6612 currentSectionInfo->fAllStubs = true;
6613 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
6614 currentSectionInfo->fAllSelfModifyingStubs = true;
6615 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
6616 }
6617 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) )
6618 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
6619 curSection = atom->getSection();
6620 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers
6621 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) {
6622 fSymbolTableCommands->needDynamicTable();
6623 }
6624 }
6625 // any non-zero fill atoms make whole section marked not-zero-fill
6626 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
6627 currentSectionInfo->fAllZeroFill = false;
6628 // change section object to be Writer's SectionInfo object
6629 atom->setSection(currentSectionInfo);
6630 // section alignment is that of a contained atom with the greatest alignment
6631 uint8_t atomAlign = atom->getAlignment().powerOf2;
6632 if ( currentSectionInfo->fAlignment < atomAlign )
6633 currentSectionInfo->fAlignment = atomAlign;
6634 // calculate section offset for this atom
6635 uint64_t offset = currentSectionInfo->fSize;
6636 uint64_t alignment = 1 << atomAlign;
6637 uint64_t currentModulus = (offset % alignment);
6638 uint64_t requiredModulus = atom->getAlignment().modulus;
6639 if ( currentModulus != requiredModulus ) {
6640 if ( requiredModulus > currentModulus )
6641 offset += requiredModulus-currentModulus;
6642 else
6643 offset += requiredModulus+alignment-currentModulus;
6644 }
6645 atom->setSectionOffset(offset);
6646 uint64_t curAtomSize = atom->getSize();
6647 currentSectionInfo->fSize = offset + curAtomSize;
6648 // add atom to section vector
6649 currentSectionInfo->fAtoms.push_back(atom);
6650 // update largest size
6651 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
6652 fLargestAtomSize = curAtomSize;
6653 }
6654 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
6655 // when merging cstring sections in .o files, all strings need to use the max alignment
6656 uint64_t offset = 0;
6657 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
6658 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
6659 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
6660 ObjectFile::Atom* atom = *it;
6661 atom->setSectionOffset(offset);
6662 offset += atom->getSize();
6663 }
6664 cstringSectionInfo->fSize = offset;
6665 }
6666 }
6667
6668
6669 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
6670 class TargetAndOffsetComparor
6671 {
6672 public:
6673 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
6674 {
6675 if ( left.atom != right.atom )
6676 return ( left.atom < right.atom );
6677 return ( left.offset < right.offset );
6678 }
6679 };
6680
6681 template <>
6682 bool Writer<ppc>::addBranchIslands()
6683 {
6684 return this->addPPCBranchIslands();
6685 }
6686
6687 template <>
6688 bool Writer<ppc64>::addBranchIslands()
6689 {
6690 return this->addPPCBranchIslands();
6691 }
6692
6693 template <>
6694 bool Writer<x86>::addBranchIslands()
6695 {
6696 // x86 branches can reach entire 4G address space, so no need for branch islands
6697 return false;
6698 }
6699
6700 template <>
6701 bool Writer<x86_64>::addBranchIslands()
6702 {
6703 // x86 branches can reach entire 4G size of largest image
6704 return false;
6705 }
6706
6707 template <>
6708 bool Writer<arm>::addBranchIslands()
6709 {
6710 // arm branch islands not (yet) supported
6711 // you can instead compile with -mlong-call
6712 return false;
6713 }
6714
6715 template <>
6716 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
6717 {
6718 switch (kind) {
6719 case ppc::kBranch24:
6720 case ppc::kBranch24WeakImport:
6721 return true;
6722 }
6723 return false;
6724 }
6725
6726 template <>
6727 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
6728 {
6729 switch (kind) {
6730 case ppc64::kBranch24:
6731 case ppc64::kBranch24WeakImport:
6732 return true;
6733 }
6734 return false;
6735 }
6736
6737 //
6738 // PowerPC can do PC relative branches as far as +/-16MB.
6739 // If a branch target is >16MB then we insert one or more
6740 // "branch islands" between the branch and its target that
6741 // allows island hoping to the target.
6742 //
6743 // Branch Island Algorithm
6744 //
6745 // If the __TEXT segment < 16MB, then no branch islands needed
6746 // Otherwise, every 15MB into the __TEXT segment is region is
6747 // added which can contain branch islands. Every out of range
6748 // bl instruction is checked. If it crosses a region, an island
6749 // is added to that region with the same target and the bl is
6750 // adjusted to target the island instead.
6751 //
6752 // In theory, if too many islands are added to one region, it
6753 // could grow the __TEXT enough that other previously in-range
6754 // bl branches could be pushed out of range. We reduce the
6755 // probability this could happen by placing the ranges every
6756 // 15MB which means the region would have to be 1MB (256K islands)
6757 // before any branches could be pushed out of range.
6758 //
6759 template <typename A>
6760 bool Writer<A>::addPPCBranchIslands()
6761 {
6762 bool log = false;
6763 bool result = false;
6764 // Can only possibly need branch islands if __TEXT segment > 16M
6765 if ( fLoadCommandsSegment->fSize > 16000000 ) {
6766 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
6767 const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section
6768 SectionInfo* textSection = NULL;
6769 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
6770 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
6771 textSection = *it;
6772 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
6773 break;
6774 }
6775 }
6776 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
6777 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
6778 AtomToIsland regionsMap[kIslandRegionsCount];
6779 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
6780 unsigned int islandCount = 0;
6781 if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
6782
6783 // create islands for branch references that are out of range
6784 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
6785 ObjectFile::Atom* atom = *it;
6786 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
6787 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
6788 ObjectFile::Reference* ref = *rit;
6789 if ( this->isBranch24Reference(ref->getKind()) ) {
6790 ObjectFile::Atom& target = ref->getTarget();
6791 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
6792 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
6793 int64_t displacement = dstAddr - srcAddr;
6794 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
6795 const int64_t kFifteenMegLimit = kBetweenRegions;
6796 if ( displacement > kFifteenMegLimit ) {
6797 // create forward branch chain
6798 ObjectFile::Atom* nextTarget = &target;
6799 uint64_t nextTargetOffset = ref->getTargetOffset();
6800 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
6801 AtomToIsland* region = &regionsMap[i];
6802 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
6803 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
6804 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
6805 if ( pos == region->end() ) {
6806 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
6807 island->setSection(textSection);
6808 (*region)[finalTargetAndOffset] = island;
6809 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
6810 regionsIslands[i].push_back(island);
6811 ++islandCount;
6812 nextTarget = island;
6813 nextTargetOffset = 0;
6814 }
6815 else {
6816 nextTarget = pos->second;
6817 nextTargetOffset = 0;
6818 }
6819 }
6820 }
6821 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
6822 ref->setTarget(*nextTarget, nextTargetOffset);
6823 }
6824 else if ( displacement < (-kFifteenMegLimit) ) {
6825 // create back branching chain
6826 ObjectFile::Atom* prevTarget = &target;
6827 uint64_t prevTargetOffset = ref->getTargetOffset();
6828 for (int i=0; i < kIslandRegionsCount ; ++i) {
6829 AtomToIsland* region = &regionsMap[i];
6830 int64_t islandRegionAddr = kBetweenRegions * (i+1);
6831 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
6832 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
6833 if ( pos == region->end() ) {
6834 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
6835 island->setSection(textSection);
6836 (*region)[finalTargetAndOffset] = island;
6837 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
6838 regionsIslands[i].push_back(island);
6839 ++islandCount;
6840 prevTarget = island;
6841 prevTargetOffset = 0;
6842 }
6843 else {
6844 prevTarget = pos->second;
6845 prevTargetOffset = 0;
6846 }
6847 }
6848 }
6849 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
6850 ref->setTarget(*prevTarget, prevTargetOffset);
6851 }
6852 }
6853 }
6854 }
6855
6856 // insert islands into __text section and adjust section offsets
6857 if ( islandCount > 0 ) {
6858 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
6859 std::vector<ObjectFile::Atom*> newAtomList;
6860 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
6861 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
6862 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
6863 int regionIndex = 0;
6864 uint64_t atomSlide = 0;
6865 uint64_t sectionOffset = 0;
6866 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
6867 ObjectFile::Atom* atom = *it;
6868 if ( atom->getAddress() > islandRegionAddr ) {
6869 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
6870 sectionOffset = islandStartOffset;
6871 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
6872 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
6873 ObjectFile::Atom* islandAtom = *rit;
6874 newAtomList.push_back(islandAtom);
6875 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
6876 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
6877 islandAtom->setSectionOffset(sectionOffset);
6878 sectionOffset += islandAtom->getSize();
6879 }
6880 ++regionIndex;
6881 islandRegionAddr += kBetweenRegions;
6882 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
6883 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
6884 }
6885 newAtomList.push_back(atom);
6886 if ( atomSlide != 0 )
6887 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
6888 }
6889 sectionOffset = textSection->fSize+atomSlide;
6890 // put any remaining islands at end of __text section
6891 if ( regionIndex < kIslandRegionsCount ) {
6892 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
6893 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
6894 ObjectFile::Atom* islandAtom = *rit;
6895 newAtomList.push_back(islandAtom);
6896 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
6897 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
6898 islandAtom->setSectionOffset(sectionOffset);
6899 sectionOffset += islandAtom->getSize();
6900 }
6901 }
6902
6903 textSection->fAtoms = newAtomList;
6904 textSection->fSize = sectionOffset;
6905 result = true;
6906 }
6907
6908 }
6909 return result;
6910 }
6911
6912
6913 template <typename A>
6914 void Writer<A>::adjustLoadCommandsAndPadding()
6915 {
6916 fSegmentCommands->computeSize();
6917
6918 // recompute load command section offsets
6919 uint64_t offset = 0;
6920 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
6921 const unsigned int atomCount = loadCommandAtoms.size();
6922 for (unsigned int i=0; i < atomCount; ++i) {
6923 ObjectFile::Atom* atom = loadCommandAtoms[i];
6924 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
6925 offset = ( (offset+alignment-1) & (-alignment) );
6926 atom->setSectionOffset(offset);
6927 uint32_t atomSize = atom->getSize();
6928 if ( atomSize > fLargestAtomSize )
6929 fLargestAtomSize = atomSize;
6930 offset += atomSize;
6931 fLoadCommandsSection->fSize = offset;
6932 }
6933
6934 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
6935 const int sectionCount = sectionInfos.size();
6936 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
6937 for(int j=0; j < sectionCount; ++j) {
6938 SectionInfo* curSection = sectionInfos[j];
6939 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
6940 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
6941 break;
6942 }
6943 uint64_t paddingSize = 0;
6944 if ( fOptions.outputKind() == Options::kDyld ) {
6945 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
6946 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
6947 }
6948 else if ( fOptions.outputKind() == Options::kObjectFile ) {
6949 // mach-o .o files need no padding between load commands and first section
6950 paddingSize = 0;
6951 }
6952 else if ( fOptions.makeEncryptable() ) {
6953 // want load commands to end on a page boundary, so __text starts on page boundary
6954 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
6955 fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfHeaderAndLoadCommands+paddingSize);
6956 }
6957 else {
6958 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
6959 uint64_t addr = 0;
6960 for(int j=sectionCount-1; j >=0; --j) {
6961 SectionInfo* curSection = sectionInfos[j];
6962 addr -= curSection->fSize;
6963 addr = addr & (0 - (1 << curSection->fAlignment));
6964 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
6965 addr -= totalSizeOfHeaderAndLoadCommands;
6966 paddingSize = addr % 4096;
6967 break;
6968 }
6969 }
6970
6971 // if command line requires more padding than this
6972 uint32_t minPad = fOptions.minimumHeaderPad();
6973 if ( fOptions.maxMminimumHeaderPad() ) {
6974 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
6975 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
6976 if ( fOptions.outputKind() == Options::kDynamicLibrary )
6977 altMin += MAXPATHLEN;
6978 if ( altMin > minPad )
6979 minPad = altMin;
6980 }
6981 if ( paddingSize < minPad ) {
6982 int extraPages = (minPad - paddingSize + 4095)/4096;
6983 paddingSize += extraPages * 4096;
6984 }
6985 }
6986
6987 // adjust atom size and update section size
6988 fHeaderPadding->setSize(paddingSize);
6989 for(int j=0; j < sectionCount; ++j) {
6990 SectionInfo* curSection = sectionInfos[j];
6991 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
6992 curSection->fSize = paddingSize;
6993 }
6994 }
6995
6996 // assign file offsets and logical address to all segments
6997 template <typename A>
6998 void Writer<A>::assignFileOffsets()
6999 {
7000 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
7001 bool haveFixedSegments = false;
7002 uint64_t fileOffset = 0;
7003 uint64_t nextContiguousAddress = fOptions.baseAddress();
7004 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
7005 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
7006
7007 // process segments with fixed addresses (-segaddr)
7008 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
7009 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7010 SegmentInfo* curSegment = *segit;
7011 if ( strcmp(curSegment->fName, it->name) == 0 ) {
7012 curSegment->fBaseAddress = it->address;
7013 curSegment->fFixedAddress = true;
7014 break;
7015 }
7016 }
7017 }
7018
7019 // Run through the segments and each segment's sections to assign addresses
7020 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7021 SegmentInfo* curSegment = *segit;
7022
7023 if ( fOptions.splitSeg() ) {
7024 if ( curSegment->fInitProtection & VM_PROT_WRITE )
7025 nextContiguousAddress = nextWritableAddress;
7026 else
7027 nextContiguousAddress = nextReadOnlyAddress;
7028 }
7029
7030 fileOffset = (fileOffset+4095) & (-4096);
7031 curSegment->fFileOffset = fileOffset;
7032
7033 // Set the segment base address
7034 if ( curSegment->fFixedAddress )
7035 haveFixedSegments = true;
7036 else
7037 curSegment->fBaseAddress = nextContiguousAddress;
7038
7039 // We've set the segment address, now run through each section.
7040 uint64_t address = curSegment->fBaseAddress;
7041 SectionInfo* firstZeroFillSection = NULL;
7042 SectionInfo* prevSection = NULL;
7043
7044 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
7045
7046 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
7047 SectionInfo* curSection = *it;
7048
7049 // adjust section address based on alignment
7050 uint64_t alignment = 1 << curSection->fAlignment;
7051 address = ( (address+alignment-1) & (-alignment) );
7052
7053 // adjust file offset to match address
7054 if ( prevSection != NULL ) {
7055 if ( finalLinkedImage || !prevSection->fVirtualSection )
7056 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
7057 else
7058 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
7059 }
7060
7061 // update section info
7062 curSection->fFileOffset = fileOffset;
7063 curSection->setBaseAddress(address);
7064 //fprintf(stderr, "%s %s %llX\n", curSegment->fName, curSection->fSectionName, address);
7065
7066 // keep track of trailing zero fill sections
7067 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
7068 firstZeroFillSection = curSection;
7069 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
7070 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
7071
7072 // update running pointers
7073 if ( finalLinkedImage || !curSection->fVirtualSection )
7074 address += curSection->fSize;
7075 fileOffset += curSection->fSize;
7076
7077 // sanity check size of 32-bit binaries
7078 if ( address > maxAddress() )
7079 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
7080
7081 // update segment info
7082 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
7083 curSegment->fSize = curSegment->fFileSize;
7084 prevSection = curSection;
7085 }
7086
7087 if ( fOptions.outputKind() == Options::kObjectFile ) {
7088 // don't page align .o files
7089 }
7090 else {
7091 // optimize trailing zero-fill sections to not occupy disk space
7092 if ( firstZeroFillSection != NULL ) {
7093 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
7094 fileOffset = firstZeroFillSection->fFileOffset;
7095 }
7096 // page align segment size
7097 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
7098 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
7099 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
7100 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
7101 if ( curSegment->fInitProtection & VM_PROT_WRITE )
7102 nextWritableAddress = nextContiguousAddress;
7103 else
7104 nextReadOnlyAddress = nextContiguousAddress;
7105 }
7106 }
7107 }
7108
7109 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
7110 if ( haveFixedSegments ) {
7111 int segCount = fSegmentInfos.size();
7112 for(int i=0; i < segCount; ++i) {
7113 SegmentInfo* segment1 = fSegmentInfos[i];
7114
7115 for(int j=0; j < segCount; ++j) {
7116 if ( i != j ) {
7117 SegmentInfo* segment2 = fSegmentInfos[j];
7118
7119 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
7120 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
7121 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7122 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7123 }
7124 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
7125 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
7126 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7127 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7128 }
7129 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
7130 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
7131 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
7132 }
7133 }
7134 }
7135 }
7136 }
7137
7138 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
7139 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7140 SegmentInfo* curSegment = *segit;
7141 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
7142 if ( fFirstWritableSegment == NULL )
7143 fFirstWritableSegment = curSegment;
7144 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
7145 fWritableSegmentPastFirst4GB = true;
7146 }
7147 }
7148
7149 // record size of encrypted part of __TEXT segment
7150 if ( fOptions.makeEncryptable() ) {
7151 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
7152 SegmentInfo* curSegment = *segit;
7153 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
7154 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
7155 break;
7156 }
7157 }
7158 }
7159
7160 }
7161
7162 template <typename A>
7163 void Writer<A>::adjustLinkEditSections()
7164 {
7165 // link edit content is always in last segment
7166 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
7167 unsigned int firstLinkEditSectionIndex = 0;
7168 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
7169 ++firstLinkEditSectionIndex;
7170
7171 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
7172 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
7173 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
7174 if ( fPadSegmentInfo != NULL ) {
7175 // insert __4GBFILL segment into segments vector before LINKEDIT
7176 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
7177 if ( *it == lastSeg ) {
7178 fSegmentInfos.insert(it, fPadSegmentInfo);
7179 break;
7180 }
7181 }
7182 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
7183 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
7184 fPadSegmentInfo->fBaseAddress = address;
7185 // adjust LINKEDIT to start at zeroPageSize
7186 address = fOptions.zeroPageSize();
7187 lastSeg->fBaseAddress = fOptions.zeroPageSize();
7188 }
7189 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
7190 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
7191 // adjust section address based on alignment
7192 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
7193 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
7194 address += pad;
7195 fileOffset += pad; // adjust file offset to match address
7196 lastSeg->fSections[i]->setBaseAddress(address);
7197 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
7198 lastSeg->fSections[i]->setBaseAddress(0);
7199 lastSeg->fSections[i]->fFileOffset = fileOffset;
7200 uint64_t sectionOffset = 0;
7201 for (unsigned int j=0; j < atoms.size(); ++j) {
7202 ObjectFile::Atom* atom = atoms[j];
7203 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
7204 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
7205 atom->setSectionOffset(sectionOffset);
7206 uint64_t size = atom->getSize();
7207 sectionOffset += size;
7208 if ( size > fLargestAtomSize )
7209 fLargestAtomSize = size;
7210 }
7211 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
7212 lastSeg->fSections[i]->fSize = sectionOffset;
7213 fileOffset += sectionOffset;
7214 address += sectionOffset;
7215 }
7216 if ( fOptions.outputKind() == Options::kObjectFile ) {
7217 //lastSeg->fBaseAddress = 0;
7218 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
7219 //lastSeg->fFileOffset = 0;
7220 //lastSeg->fFileSize =
7221 }
7222 else {
7223 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
7224 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
7225 }
7226 }
7227
7228
7229 template <typename A>
7230 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
7231 {
7232 switch ( fWriter.fOptions.outputKind() ) {
7233 case Options::kDynamicExecutable:
7234 case Options::kStaticExecutable:
7235 return ObjectFile::Atom::scopeGlobal;
7236 case Options::kDynamicLibrary:
7237 case Options::kDynamicBundle:
7238 case Options::kDyld:
7239 case Options::kObjectFile:
7240 return ObjectFile::Atom::scopeLinkageUnit;
7241 }
7242 throw "unknown header type";
7243 }
7244
7245 template <typename A>
7246 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
7247 {
7248 switch ( fWriter.fOptions.outputKind() ) {
7249 case Options::kDynamicExecutable:
7250 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
7251 case Options::kStaticExecutable:
7252 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
7253 case Options::kDynamicLibrary:
7254 case Options::kDynamicBundle:
7255 case Options::kDyld:
7256 return ObjectFile::Atom::kSymbolTableIn;
7257 case Options::kObjectFile:
7258 return ObjectFile::Atom::kSymbolTableNotIn;
7259 }
7260 throw "unknown header type";
7261 }
7262
7263 template <typename A>
7264 const char* MachHeaderAtom<A>::getName() const
7265 {
7266 switch ( fWriter.fOptions.outputKind() ) {
7267 case Options::kDynamicExecutable:
7268 case Options::kStaticExecutable:
7269 return "__mh_execute_header";
7270 case Options::kDynamicLibrary:
7271 return "__mh_dylib_header";
7272 case Options::kDynamicBundle:
7273 return "__mh_bundle_header";
7274 case Options::kObjectFile:
7275 return NULL;
7276 case Options::kDyld:
7277 return "__mh_dylinker_header";
7278 }
7279 throw "unknown header type";
7280 }
7281
7282 template <typename A>
7283 const char* MachHeaderAtom<A>::getDisplayName() const
7284 {
7285 switch ( fWriter.fOptions.outputKind() ) {
7286 case Options::kDynamicExecutable:
7287 case Options::kStaticExecutable:
7288 case Options::kDynamicLibrary:
7289 case Options::kDynamicBundle:
7290 case Options::kDyld:
7291 return this->getName();
7292 case Options::kObjectFile:
7293 return "mach header";
7294 }
7295 throw "unknown header type";
7296 }
7297
7298 template <typename A>
7299 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
7300 {
7301 // get file type
7302 uint32_t fileType = 0;
7303 switch ( fWriter.fOptions.outputKind() ) {
7304 case Options::kDynamicExecutable:
7305 case Options::kStaticExecutable:
7306 fileType = MH_EXECUTE;
7307 break;
7308 case Options::kDynamicLibrary:
7309 fileType = MH_DYLIB;
7310 break;
7311 case Options::kDynamicBundle:
7312 fileType = MH_BUNDLE;
7313 break;
7314 case Options::kObjectFile:
7315 fileType = MH_OBJECT;
7316 break;
7317 case Options::kDyld:
7318 fileType = MH_DYLINKER;
7319 break;
7320 }
7321
7322 // get flags
7323 uint32_t flags = 0;
7324 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
7325 if ( fWriter.fCanScatter )
7326 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
7327 }
7328 else {
7329 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
7330 flags |= MH_NOUNDEFS;
7331 }
7332 else {
7333 flags = MH_DYLDLINK;
7334 if ( fWriter.fOptions.bindAtLoad() )
7335 flags |= MH_BINDATLOAD;
7336 switch ( fWriter.fOptions.nameSpace() ) {
7337 case Options::kTwoLevelNameSpace:
7338 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
7339 break;
7340 case Options::kFlatNameSpace:
7341 break;
7342 case Options::kForceFlatNameSpace:
7343 flags |= MH_FORCE_FLAT;
7344 break;
7345 }
7346 if ( fWriter.fHasWeakExports )
7347 flags |= MH_WEAK_DEFINES;
7348 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
7349 flags |= MH_BINDS_TO_WEAK;
7350 if ( fWriter.fOptions.prebind() )
7351 flags |= MH_PREBOUND;
7352 if ( fWriter.fOptions.splitSeg() )
7353 flags |= MH_SPLIT_SEGS;
7354 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
7355 flags |= MH_NO_REEXPORTED_DYLIBS;
7356 if ( fWriter.fOptions.positionIndependentExecutable() )
7357 flags |= MH_PIE;
7358 }
7359 if ( fWriter.fOptions.hasExecutableStack() )
7360 flags |= MH_ALLOW_STACK_EXECUTION;
7361 if ( fWriter.fOptions.readerOptions().fRootSafe )
7362 flags |= MH_ROOT_SAFE;
7363 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
7364 flags |= MH_SETUID_SAFE;
7365 }
7366
7367 // get commands info
7368 uint32_t commandsSize = 0;
7369 uint32_t commandsCount = 0;
7370
7371 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
7372 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
7373 ObjectFile::Atom* atom = *it;
7374 commandsSize += atom->getSize();
7375 // segment and symbol table atoms can contain more than one load command
7376 if ( atom == fWriter.fSegmentCommands )
7377 commandsCount += fWriter.fSegmentCommands->commandCount();
7378 else if ( atom == fWriter.fSymbolTableCommands )
7379 commandsCount += fWriter.fSymbolTableCommands->commandCount();
7380 else if ( atom->getSize() != 0 )
7381 ++commandsCount;
7382 }
7383
7384 // fill out mach_header
7385 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
7386 setHeaderInfo(*mh);
7387 mh->set_filetype(fileType);
7388 mh->set_ncmds(commandsCount);
7389 mh->set_sizeofcmds(commandsSize);
7390 mh->set_flags(flags);
7391 }
7392
7393 template <>
7394 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
7395 {
7396 header.set_magic(MH_MAGIC);
7397 header.set_cputype(CPU_TYPE_POWERPC);
7398 header.set_cpusubtype(fWriter.fCpuConstraint);
7399 }
7400
7401 template <>
7402 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
7403 {
7404 header.set_magic(MH_MAGIC_64);
7405 header.set_cputype(CPU_TYPE_POWERPC64);
7406 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7407 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
7408 else
7409 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
7410 header.set_reserved(0);
7411 }
7412
7413 template <>
7414 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
7415 {
7416 header.set_magic(MH_MAGIC);
7417 header.set_cputype(CPU_TYPE_I386);
7418 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
7419 }
7420
7421 template <>
7422 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
7423 {
7424 header.set_magic(MH_MAGIC_64);
7425 header.set_cputype(CPU_TYPE_X86_64);
7426 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7427 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
7428 else
7429 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
7430 header.set_reserved(0);
7431 }
7432
7433 template <>
7434 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
7435 {
7436 header.set_magic(MH_MAGIC);
7437 header.set_cputype(CPU_TYPE_ARM);
7438 header.set_cpusubtype(fWriter.fCpuConstraint);
7439 }
7440
7441 template <typename A>
7442 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
7443 : WriterAtom<A>(writer, Segment::fgStackSegment)
7444 {
7445 if ( stackGrowsDown() )
7446 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
7447 else
7448 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
7449 }
7450
7451
7452 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
7453 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
7454 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
7455 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
7456 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
7457
7458 template <typename A>
7459 void SegmentLoadCommandsAtom<A>::computeSize()
7460 {
7461 uint64_t size = 0;
7462 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
7463 const int segCount = segmentInfos.size();
7464 for(int i=0; i < segCount; ++i) {
7465 size += sizeof(macho_segment_command<P>);
7466 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
7467 const int sectionCount = sectionInfos.size();
7468 for(int j=0; j < sectionCount; ++j) {
7469 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
7470 size += sizeof(macho_section<P>);
7471 }
7472 }
7473 fSize = size;
7474 fCommandCount = segCount;
7475 if ( fWriter.fPadSegmentInfo != NULL ) {
7476 ++fCommandCount;
7477 fSize += sizeof(macho_segment_command<P>);
7478 }
7479 }
7480
7481 template <>
7482 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
7483 {
7484 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7485 }
7486
7487 template <>
7488 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
7489 {
7490 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
7491 }
7492
7493 template <>
7494 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
7495 {
7496 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7497 }
7498
7499 template <>
7500 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
7501 {
7502 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
7503 }
7504
7505 template <>
7506 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
7507 {
7508 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
7509 }
7510
7511 template <typename A>
7512 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7513 {
7514 uint64_t size = this->getSize();
7515 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
7516 bzero(buffer, size);
7517 uint8_t* p = buffer;
7518 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
7519 const int segCount = segmentInfos.size();
7520 for(int i=0; i < segCount; ++i) {
7521 SegmentInfo* segInfo = segmentInfos[i];
7522 const int sectionCount = segInfo->fSections.size();
7523 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
7524 cmd->set_cmd(macho_segment_command<P>::CMD);
7525 cmd->set_segname(segInfo->fName);
7526 cmd->set_vmaddr(segInfo->fBaseAddress);
7527 cmd->set_vmsize(segInfo->fSize);
7528 cmd->set_fileoff(segInfo->fFileOffset);
7529 cmd->set_filesize(segInfo->fFileSize);
7530 cmd->set_maxprot(segInfo->fMaxProtection);
7531 cmd->set_initprot(segInfo->fInitProtection);
7532 // add sections array
7533 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
7534 unsigned int sectionsEmitted = 0;
7535 for (int j=0; j < sectionCount; ++j) {
7536 SectionInfo* sectInfo = segInfo->fSections[j];
7537 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
7538 macho_section<P>* sect = &sections[sectionsEmitted++];
7539 if ( oneSegment ) {
7540 // .o file segment does not cover load commands, so recalc at first real section
7541 if ( sectionsEmitted == 1 ) {
7542 cmd->set_vmaddr(sectInfo->getBaseAddress());
7543 cmd->set_fileoff(sectInfo->fFileOffset);
7544 }
7545 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
7546 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
7547 }
7548 sect->set_sectname(sectInfo->fSectionName);
7549 sect->set_segname(sectInfo->fSegmentName);
7550 sect->set_addr(sectInfo->getBaseAddress());
7551 sect->set_size(sectInfo->fSize);
7552 sect->set_offset(sectInfo->fFileOffset);
7553 sect->set_align(sectInfo->fAlignment);
7554 if ( sectInfo->fRelocCount != 0 ) {
7555 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
7556 sect->set_nreloc(sectInfo->fRelocCount);
7557 }
7558 if ( sectInfo->fAllZeroFill ) {
7559 sect->set_flags(S_ZEROFILL);
7560 sect->set_offset(0);
7561 }
7562 else if ( sectInfo->fAllLazyPointers ) {
7563 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
7564 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7565 }
7566 else if ( sectInfo->fAllLazyDylibPointers ) {
7567 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
7568 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7569 }
7570 else if ( sectInfo->fAllNonLazyPointers ) {
7571 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
7572 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7573 }
7574 else if ( sectInfo->fAllStubs ) {
7575 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
7576 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7577 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
7578 }
7579 else if ( sectInfo->fAllSelfModifyingStubs ) {
7580 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
7581 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
7582 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
7583 }
7584 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7585 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
7586 }
7587 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7588 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
7589 }
7590 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7591 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
7592 }
7593 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7594 sect->set_flags(S_COALESCED);
7595 }
7596 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7597 sect->set_flags(S_COALESCED);
7598 }
7599 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7600 sect->set_flags(S_INTERPOSING);
7601 }
7602 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7603 sect->set_flags(S_CSTRING_LITERALS);
7604 }
7605 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7606 sect->set_flags(S_4BYTE_LITERALS);
7607 }
7608 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7609 sect->set_flags(S_8BYTE_LITERALS);
7610 }
7611 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7612 sect->set_flags(S_16BYTE_LITERALS);
7613 }
7614 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
7615 sect->set_flags(S_LITERAL_POINTERS);
7616 }
7617 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
7618 sect->set_flags(S_LITERAL_POINTERS);
7619 }
7620 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7621 sect->set_flags(S_DTRACE_DOF);
7622 }
7623 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
7624 sect->set_flags(S_DTRACE_DOF);
7625 }
7626 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
7627 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
7628 if ( sectInfo->fHasTextLocalRelocs )
7629 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
7630 if ( sectInfo->fHasTextExternalRelocs )
7631 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
7632 }
7633 }
7634 }
7635 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
7636 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
7637 cmd->set_nsects(sectionsEmitted);
7638 }
7639 }
7640
7641
7642 template <typename A>
7643 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
7644 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
7645 {
7646 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
7647 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
7648 switch ( fWriter.fOptions.outputKind() ) {
7649 case Options::kDynamicExecutable:
7650 case Options::kDynamicLibrary:
7651 case Options::kDynamicBundle:
7652 case Options::kDyld:
7653 fNeedsDynamicSymbolTable = true;
7654 break;
7655 case Options::kObjectFile:
7656 case Options::kStaticExecutable:
7657 fNeedsDynamicSymbolTable = false;
7658 break;
7659 }
7660 writer.fSymbolTableCommands = this;
7661 }
7662
7663
7664
7665 template <typename A>
7666 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
7667 {
7668 fNeedsDynamicSymbolTable = true;
7669 }
7670
7671
7672 template <typename A>
7673 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
7674 {
7675 if ( fNeedsDynamicSymbolTable )
7676 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
7677 else
7678 return this->alignedSize(sizeof(macho_symtab_command<P>));
7679 }
7680
7681 template <typename A>
7682 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7683 {
7684 // build LC_DYSYMTAB command
7685 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
7686 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
7687 symbolTableCmd->set_cmd(LC_SYMTAB);
7688 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
7689 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
7690 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
7691 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
7692 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
7693
7694 // build LC_DYSYMTAB command
7695 if ( fNeedsDynamicSymbolTable ) {
7696 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
7697 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
7698 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
7699 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
7700 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
7701 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
7702 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
7703 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
7704 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
7705 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
7706 if ( fWriter.fModuleInfoAtom != NULL ) {
7707 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
7708 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
7709 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
7710 dynamicSymbolTableCmd->set_nmodtab(1);
7711 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
7712 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
7713 }
7714 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
7715 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
7716 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
7717 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
7718 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
7719 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
7720 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
7721 }
7722 }
7723 }
7724
7725
7726 template <typename A>
7727 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
7728 {
7729 return fNeedsDynamicSymbolTable ? 2 : 1;
7730 }
7731
7732 template <typename A>
7733 uint64_t DyldLoadCommandsAtom<A>::getSize() const
7734 {
7735 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
7736 }
7737
7738 template <typename A>
7739 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7740 {
7741 uint64_t size = this->getSize();
7742 bzero(buffer, size);
7743 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
7744 if ( fWriter.fOptions.outputKind() == Options::kDyld )
7745 cmd->set_cmd(LC_ID_DYLINKER);
7746 else
7747 cmd->set_cmd(LC_LOAD_DYLINKER);
7748 cmd->set_cmdsize(this->getSize());
7749 cmd->set_name_offset();
7750 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
7751 }
7752
7753 template <typename A>
7754 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
7755 {
7756 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
7757 }
7758
7759 template <typename A>
7760 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7761 {
7762 uint64_t size = this->getSize();
7763
7764 bzero(buffer, size);
7765 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
7766 cmd->set_cmd(LC_SUB_CLIENT);
7767 cmd->set_cmdsize(size);
7768 cmd->set_client_offset();
7769 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
7770
7771 }
7772
7773 template <typename A>
7774 uint64_t DylibLoadCommandsAtom<A>::getSize() const
7775 {
7776 if ( fOptimizedAway ) {
7777 return 0;
7778 }
7779 else {
7780 const char* path = fInfo.reader->getInstallPath();
7781 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
7782 }
7783 }
7784
7785 template <typename A>
7786 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7787 {
7788 if ( fOptimizedAway )
7789 return;
7790 uint64_t size = this->getSize();
7791 bzero(buffer, size);
7792 const char* path = fInfo.reader->getInstallPath();
7793 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
7794 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
7795 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
7796 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
7797 if ( fInfo.options.fLazyLoad )
7798 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
7799 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
7800 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
7801 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
7802 cmd->set_cmd(LC_REEXPORT_DYLIB);
7803 else
7804 cmd->set_cmd(LC_LOAD_DYLIB);
7805 cmd->set_cmdsize(this->getSize());
7806 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
7807 cmd->set_current_version(fInfo.reader->getCurrentVersion());
7808 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
7809 cmd->set_name_offset();
7810 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
7811 }
7812
7813
7814
7815 template <typename A>
7816 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
7817 {
7818 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
7819 }
7820
7821 template <typename A>
7822 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7823 {
7824 uint64_t size = this->getSize();
7825 bzero(buffer, size);
7826 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
7827 cmd->set_cmd(LC_ID_DYLIB);
7828 cmd->set_cmdsize(this->getSize());
7829 cmd->set_name_offset();
7830 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
7831 cmd->set_current_version(fWriter.fOptions.currentVersion());
7832 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
7833 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
7834 }
7835
7836
7837 template <typename A>
7838 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7839 {
7840 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7841 if (fWriter.fEntryPoint->isThumb())
7842 initAddr |= 1ULL;
7843 bzero(buffer, sizeof(macho_routines_command<P>));
7844 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
7845 cmd->set_cmd(macho_routines_command<P>::CMD);
7846 cmd->set_cmdsize(this->getSize());
7847 cmd->set_init_address(initAddr);
7848 }
7849
7850
7851 template <typename A>
7852 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
7853 {
7854 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
7855 }
7856
7857 template <typename A>
7858 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7859 {
7860 uint64_t size = this->getSize();
7861 bzero(buffer, size);
7862 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
7863 cmd->set_cmd(LC_SUB_UMBRELLA);
7864 cmd->set_cmdsize(this->getSize());
7865 cmd->set_sub_umbrella_offset();
7866 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
7867 }
7868
7869 template <typename A>
7870 void UUIDLoadCommandAtom<A>::generate()
7871 {
7872 switch ( fWriter.fOptions.getUUIDMode() ) {
7873 case Options::kUUIDNone:
7874 fEmit = false;
7875 break;
7876 case Options::kUUIDRandom:
7877 ::uuid_generate_random(fUUID);
7878 fEmit = true;
7879 break;
7880 case Options::kUUIDContent:
7881 bzero(fUUID, 16);
7882 fEmit = true;
7883 break;
7884 }
7885 }
7886
7887 template <typename A>
7888 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
7889 {
7890 memcpy(fUUID, uuid, 16);
7891 }
7892
7893 template <typename A>
7894 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
7895 {
7896 if (fEmit) {
7897 uint64_t size = this->getSize();
7898 bzero(buffer, size);
7899 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
7900 cmd->set_cmd(LC_UUID);
7901 cmd->set_cmdsize(this->getSize());
7902 cmd->set_uuid((uint8_t*)fUUID);
7903 }
7904 }
7905
7906
7907 template <typename A>
7908 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
7909 {
7910 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
7911 }
7912
7913 template <typename A>
7914 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7915 {
7916 uint64_t size = this->getSize();
7917 bzero(buffer, size);
7918 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
7919 cmd->set_cmd(LC_SUB_LIBRARY);
7920 cmd->set_cmdsize(this->getSize());
7921 cmd->set_sub_library_offset();
7922 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
7923 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
7924 }
7925
7926 template <typename A>
7927 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
7928 {
7929 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
7930 }
7931
7932 template <typename A>
7933 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7934 {
7935 uint64_t size = this->getSize();
7936 bzero(buffer, size);
7937 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
7938 cmd->set_cmd(LC_SUB_FRAMEWORK);
7939 cmd->set_cmdsize(this->getSize());
7940 cmd->set_umbrella_offset();
7941 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
7942 }
7943
7944 template <>
7945 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
7946 {
7947 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
7948 }
7949
7950 template <>
7951 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
7952 {
7953 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
7954 }
7955
7956 template <>
7957 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
7958 {
7959 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
7960 }
7961
7962 template <>
7963 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
7964 {
7965 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
7966 }
7967
7968 // We should be picking it up from a header
7969 template <>
7970 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
7971 {
7972 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
7973 }
7974
7975 template <>
7976 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
7977 {
7978 uint64_t size = this->getSize();
7979 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7980 bzero(buffer, size);
7981 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
7982 cmd->set_cmd(LC_UNIXTHREAD);
7983 cmd->set_cmdsize(size);
7984 cmd->set_flavor(1); // PPC_THREAD_STATE
7985 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
7986 cmd->set_thread_register(0, start);
7987 if ( fWriter.fOptions.hasCustomStack() )
7988 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
7989 }
7990
7991
7992 template <>
7993 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
7994 {
7995 uint64_t size = this->getSize();
7996 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
7997 bzero(buffer, size);
7998 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
7999 cmd->set_cmd(LC_UNIXTHREAD);
8000 cmd->set_cmdsize(size);
8001 cmd->set_flavor(5); // PPC_THREAD_STATE64
8002 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
8003 cmd->set_thread_register(0, start);
8004 if ( fWriter.fOptions.hasCustomStack() )
8005 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
8006 }
8007
8008 template <>
8009 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
8010 {
8011 uint64_t size = this->getSize();
8012 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8013 bzero(buffer, size);
8014 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
8015 cmd->set_cmd(LC_UNIXTHREAD);
8016 cmd->set_cmdsize(size);
8017 cmd->set_flavor(1); // i386_THREAD_STATE
8018 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
8019 cmd->set_thread_register(10, start);
8020 if ( fWriter.fOptions.hasCustomStack() )
8021 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
8022 }
8023
8024 template <>
8025 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
8026 {
8027 uint64_t size = this->getSize();
8028 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8029 bzero(buffer, size);
8030 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
8031 cmd->set_cmd(LC_UNIXTHREAD);
8032 cmd->set_cmdsize(size);
8033 cmd->set_flavor(x86_THREAD_STATE64);
8034 cmd->set_count(x86_THREAD_STATE64_COUNT);
8035 cmd->set_thread_register(16, start); // rip
8036 if ( fWriter.fOptions.hasCustomStack() )
8037 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
8038 }
8039
8040 template <>
8041 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
8042 {
8043 uint64_t size = this->getSize();
8044 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
8045 bzero(buffer, size);
8046 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
8047 cmd->set_cmd(LC_UNIXTHREAD);
8048 cmd->set_cmdsize(size);
8049 cmd->set_flavor(1);
8050 cmd->set_count(17);
8051 cmd->set_thread_register(15, start); // pc
8052 if ( fWriter.fOptions.hasCustomStack() )
8053 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
8054 }
8055
8056 template <typename A>
8057 uint64_t RPathLoadCommandsAtom<A>::getSize() const
8058 {
8059 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
8060 }
8061
8062 template <typename A>
8063 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8064 {
8065 uint64_t size = this->getSize();
8066 bzero(buffer, size);
8067 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
8068 cmd->set_cmd(LC_RPATH);
8069 cmd->set_cmdsize(this->getSize());
8070 cmd->set_path_offset();
8071 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
8072 }
8073
8074
8075
8076 template <typename A>
8077 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8078 {
8079 uint64_t size = this->getSize();
8080 bzero(buffer, size);
8081 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
8082 cmd->set_cmd(LC_ENCRYPTION_INFO);
8083 cmd->set_cmdsize(this->getSize());
8084 cmd->set_cryptoff(fStartOffset);
8085 cmd->set_cryptsize(fEndOffset-fStartOffset);
8086 cmd->set_cryptid(0);
8087 }
8088
8089
8090
8091 template <typename A>
8092 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
8093 {
8094 bzero(buffer, fSize);
8095 }
8096
8097 template <typename A>
8098 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
8099 {
8100 fSize = newSize;
8101 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
8102 if ( fWriter.fLargestAtomSize < newSize )
8103 fWriter.fLargestAtomSize = newSize;
8104 }
8105
8106 template <typename A>
8107 uint64_t LinkEditAtom<A>::getFileOffset() const
8108 {
8109 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
8110 }
8111
8112
8113 template <typename A>
8114 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
8115 {
8116 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
8117 }
8118
8119 template <typename A>
8120 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8121 {
8122 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
8123 }
8124
8125
8126 template <typename A>
8127 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
8128 {
8129 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
8130 }
8131
8132 template <typename A>
8133 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8134 {
8135 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
8136 }
8137
8138
8139
8140 template <typename A>
8141 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
8142 {
8143 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
8144 }
8145
8146 template <typename A>
8147 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8148 {
8149 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
8150 }
8151
8152 template <typename A>
8153 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
8154 {
8155 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
8156 }
8157
8158 template <typename A>
8159 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8160 {
8161 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
8162 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
8163 }
8164
8165
8166
8167 template <typename A>
8168 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
8169 {
8170 return fTable.size() * sizeof(uint32_t);
8171 }
8172
8173 template <typename A>
8174 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8175 {
8176 uint64_t size = this->getSize();
8177 bzero(buffer, size);
8178 const uint32_t indirectTableSize = fTable.size();
8179 uint32_t* indirectTable = (uint32_t*)buffer;
8180 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
8181 if ( it->indirectIndex < indirectTableSize ) {
8182 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
8183 }
8184 else {
8185 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
8186 }
8187 }
8188 }
8189
8190
8191
8192 template <typename A>
8193 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
8194 {
8195 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
8196 + sizeof(macho_dylib_module<P>)
8197 + this->getReferencesCount()*sizeof(uint32_t);
8198 }
8199
8200 template <typename A>
8201 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
8202 {
8203 return this->getFileOffset();
8204 }
8205
8206 template <typename A>
8207 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
8208 {
8209 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
8210 }
8211
8212 template <typename A>
8213 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
8214 {
8215 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
8216 }
8217
8218 template <typename A>
8219 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
8220 {
8221 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
8222 }
8223
8224 template <typename A>
8225 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8226 {
8227 uint64_t size = this->getSize();
8228 bzero(buffer, size);
8229 // create toc. The symbols are already sorted, they are all in the smae module
8230 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
8231 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
8232 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
8233 p->set_module_index(0);
8234 }
8235 // create module table (one entry)
8236 uint16_t numInits = 0;
8237 uint16_t numTerms = 0;
8238 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
8239 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
8240 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
8241 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
8242 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
8243 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
8244 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
8245 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
8246 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
8247 }
8248 }
8249 }
8250 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
8251 module->set_module_name(fModuleNameOffset);
8252 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
8253 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
8254 module->set_irefsym(0);
8255 module->set_nrefsym(this->getReferencesCount());
8256 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
8257 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
8258 module->set_iextrel(0);
8259 module->set_nextrel(fWriter.fExternalRelocs.size());
8260 module->set_iinit_iterm(0,0);
8261 module->set_ninit_nterm(numInits,numTerms);
8262 module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years
8263 module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years
8264 // create reference table
8265 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
8266 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
8267 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
8268 ref->set_flags(REFERENCE_FLAG_DEFINED);
8269 }
8270 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
8271 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
8272 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
8273 if ( pos != fWriter.fStubsMap.end() )
8274 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
8275 else
8276 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
8277 }
8278 }
8279
8280
8281
8282 template <typename A>
8283 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
8284 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
8285 {
8286 fCurrentBuffer = new char[kBufferSize];
8287 // burn first byte of string pool (so zero is never a valid string offset)
8288 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
8289 // make offset 1 always point to an empty string
8290 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
8291 }
8292
8293 template <typename A>
8294 uint64_t StringsLinkEditAtom<A>::getSize() const
8295 {
8296 // align size
8297 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
8298 }
8299
8300 template <typename A>
8301 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
8302 {
8303 uint64_t offset = 0;
8304 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
8305 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
8306 offset += kBufferSize;
8307 }
8308 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
8309 // zero fill end to align
8310 offset += fCurrentBufferUsed;
8311 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
8312 buffer[offset++] = 0;
8313 }
8314
8315 template <typename A>
8316 int32_t StringsLinkEditAtom<A>::add(const char* name)
8317 {
8318 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
8319 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
8320 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
8321 fCurrentBufferUsed += lenNeeded;
8322 }
8323 else {
8324 int copied = kBufferSize-fCurrentBufferUsed-1;
8325 // change trailing '\0' that strlcpy added to real char
8326 fCurrentBuffer[kBufferSize-1] = name[copied];
8327 // alloc next buffer
8328 fFullBuffers.push_back(fCurrentBuffer);
8329 fCurrentBuffer = new char[kBufferSize];
8330 fCurrentBufferUsed = 0;
8331 // append rest of string
8332 this->add(&name[copied+1]);
8333 }
8334 return offset;
8335 }
8336
8337
8338 template <typename A>
8339 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
8340 {
8341 StringToOffset::iterator pos = fUniqueStrings.find(name);
8342 if ( pos != fUniqueStrings.end() ) {
8343 return pos->second;
8344 }
8345 else {
8346 int32_t offset = this->add(name);
8347 fUniqueStrings[name] = offset;
8348 return offset;
8349 }
8350 }
8351
8352
8353 template <typename A>
8354 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
8355 {
8356 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
8357 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
8358 // check for out of bounds
8359 if ( index > maxIndex )
8360 return "";
8361 // check for index in fCurrentBuffer
8362 if ( index > currentBufferStartIndex )
8363 return &fCurrentBuffer[index-currentBufferStartIndex];
8364 // otherwise index is in a full buffer
8365 uint32_t fullBufferIndex = index/kBufferSize;
8366 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
8367 }
8368
8369
8370
8371 template <typename A>
8372 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
8373 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
8374 {
8375 char* buf = new char[strlen(name)+32];
8376 if ( targetOffset == 0 ) {
8377 if ( islandRegion == 0 )
8378 sprintf(buf, "%s$island", name);
8379 else
8380 sprintf(buf, "%s$island_%d", name, islandRegion);
8381 }
8382 else {
8383 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
8384 }
8385 fName = buf;
8386 }
8387
8388
8389 template <>
8390 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
8391 {
8392 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
8393 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
8394 OSWriteBigInt32(buffer, 0, branchInstruction);
8395 }
8396
8397 template <>
8398 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
8399 {
8400 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
8401 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
8402 OSWriteBigInt32(buffer, 0, branchInstruction);
8403 }
8404
8405 template <>
8406 uint64_t BranchIslandAtom<ppc>::getSize() const
8407 {
8408 return 4;
8409 }
8410
8411 template <>
8412 uint64_t BranchIslandAtom<ppc64>::getSize() const
8413 {
8414 return 4;
8415 }
8416
8417
8418
8419 template <typename A>
8420 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
8421 {
8422 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
8423 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
8424 else
8425 return 0; // a zero size causes the load command to be suppressed
8426 }
8427
8428 template <typename A>
8429 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
8430 {
8431 uint64_t size = this->getSize();
8432 bzero(buffer, size);
8433 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
8434 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
8435 cmd->set_cmdsize(size);
8436 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
8437 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
8438 }
8439
8440
8441 template <typename A>
8442 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
8443 {
8444 return fEncodedData.size();
8445 }
8446
8447 template <typename A>
8448 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
8449 {
8450 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
8451 }
8452
8453
8454 template <typename A>
8455 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
8456 {
8457 pint_t addr = fWriter.fOptions.baseAddress();
8458 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
8459 pint_t nextAddr = it->atom->getAddress() + it->offset;
8460 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
8461 uint64_t delta = nextAddr - addr;
8462 if ( delta == 0 )
8463 throw "double split seg info for same address";
8464 // uleb128 encode
8465 uint8_t byte;
8466 do {
8467 byte = delta & 0x7F;
8468 delta &= ~0x7F;
8469 if ( delta != 0 )
8470 byte |= 0x80;
8471 fEncodedData.push_back(byte);
8472 delta = delta >> 7;
8473 }
8474 while( byte >= 0x80 );
8475 addr = nextAddr;
8476 }
8477 }
8478
8479 template <typename A>
8480 void SegmentSplitInfoContentAtom<A>::encode()
8481 {
8482 if ( ! fCantEncode ) {
8483 fEncodedData.reserve(8192);
8484
8485 if ( fKind1Locations.size() != 0 ) {
8486 fEncodedData.push_back(1);
8487 //fprintf(stderr, "type 1:\n");
8488 this->uleb128EncodeAddresses(fKind1Locations);
8489 fEncodedData.push_back(0);
8490 }
8491
8492 if ( fKind2Locations.size() != 0 ) {
8493 fEncodedData.push_back(2);
8494 //fprintf(stderr, "type 2:\n");
8495 this->uleb128EncodeAddresses(fKind2Locations);
8496 fEncodedData.push_back(0);
8497 }
8498
8499 if ( fKind3Locations.size() != 0 ) {
8500 fEncodedData.push_back(3);
8501 //fprintf(stderr, "type 3:\n");
8502 this->uleb128EncodeAddresses(fKind3Locations);
8503 fEncodedData.push_back(0);
8504 }
8505
8506 if ( fKind4Locations.size() != 0 ) {
8507 fEncodedData.push_back(4);
8508 //fprintf(stderr, "type 4:\n");
8509 this->uleb128EncodeAddresses(fKind4Locations);
8510 fEncodedData.push_back(0);
8511 }
8512
8513 // always add zero byte to mark end
8514 fEncodedData.push_back(0);
8515
8516 // add zeros to end to align size
8517 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
8518 fEncodedData.push_back(0);
8519 }
8520 }
8521
8522
8523 template <typename A>
8524 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
8525 : WriterAtom<A>(writer, getInfoSegment())
8526 {
8527 fContent[0] = 0;
8528 uint32_t value = 0;
8529 // struct objc_image_info {
8530 // uint32_t version; // initially 0
8531 // uint32_t flags;
8532 // };
8533 // #define OBJC_IMAGE_SUPPORTS_GC 2
8534 // #define OBJC_IMAGE_GC_ONLY 4
8535 //
8536 if ( objcReplacementClasses )
8537 value = 1;
8538 switch ( objcConstraint ) {
8539 case ObjectFile::Reader::kObjcNone:
8540 case ObjectFile::Reader::kObjcRetainRelease:
8541 break;
8542 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
8543 value |= 2;
8544 break;
8545 case ObjectFile::Reader::kObjcGC:
8546 value |= 6;
8547 break;
8548 }
8549 A::P::E::set32(fContent[1], value);
8550 }
8551
8552 template <typename A>
8553 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
8554 {
8555 memcpy(buffer, &fContent[0], 8);
8556 }
8557
8558
8559 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
8560 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
8561 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
8562 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
8563 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
8564 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
8565
8566 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
8567 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
8568 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
8569 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
8570 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
8571
8572
8573 }; // namespace executable
8574 }; // namespace mach_o
8575
8576
8577 #endif // __EXECUTABLE_MACH_O__