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