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