]> git.saurik.com Git - apple/ld64.git/blob - src/ld/MachOWriterExecutable.hpp
ld64-95.2.12.tar.gz
[apple/ld64.git] / src / ld / MachOWriterExecutable.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2009 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 #include "MachOTrie.hpp"
49
50
51 //
52 //
53 // To implement architecture xxx, you must write template specializations for the following methods:
54 // MachHeaderAtom<xxx>::setHeaderInfo()
55 // ThreadsLoadCommandsAtom<xxx>::getSize()
56 // ThreadsLoadCommandsAtom<xxx>::copyRawContent()
57 // Writer<xxx>::addObjectRelocs()
58 // Writer<xxx>::fixUpReferenceRelocatable()
59 // Writer<xxx>::fixUpReferenceFinal()
60 // Writer<xxx>::stubableReference()
61 // Writer<xxx>::weakImportReferenceKind()
62 // Writer<xxx>::GOTReferenceKind()
63 //
64
65
66 namespace mach_o {
67 namespace executable {
68
69 // forward references
70 template <typename A> class WriterAtom;
71 template <typename A> class PageZeroAtom;
72 template <typename A> class CustomStackAtom;
73 template <typename A> class MachHeaderAtom;
74 template <typename A> class SegmentLoadCommandsAtom;
75 template <typename A> class EncryptionLoadCommandsAtom;
76 template <typename A> class SymbolTableLoadCommandsAtom;
77 template <typename A> class DyldInfoLoadCommandsAtom;
78 template <typename A> class ThreadsLoadCommandsAtom;
79 template <typename A> class DylibIDLoadCommandsAtom;
80 template <typename A> class RoutinesLoadCommandsAtom;
81 template <typename A> class DyldLoadCommandsAtom;
82 template <typename A> class UUIDLoadCommandAtom;
83 template <typename A> class LinkEditAtom;
84 template <typename A> class SectionRelocationsLinkEditAtom;
85 template <typename A> class CompressedRebaseInfoLinkEditAtom;
86 template <typename A> class CompressedBindingInfoLinkEditAtom;
87 template <typename A> class CompressedWeakBindingInfoLinkEditAtom;
88 template <typename A> class CompressedLazyBindingInfoLinkEditAtom;
89 template <typename A> class CompressedExportInfoLinkEditAtom;
90 template <typename A> class LocalRelocationsLinkEditAtom;
91 template <typename A> class ExternalRelocationsLinkEditAtom;
92 template <typename A> class SymbolTableLinkEditAtom;
93 template <typename A> class SegmentSplitInfoLoadCommandsAtom;
94 template <typename A> class SegmentSplitInfoContentAtom;
95 template <typename A> class IndirectTableLinkEditAtom;
96 template <typename A> class ModuleInfoLinkEditAtom;
97 template <typename A> class StringsLinkEditAtom;
98 template <typename A> class LoadCommandsPaddingAtom;
99 template <typename A> class UnwindInfoAtom;
100 template <typename A> class StubAtom;
101 template <typename A> class StubHelperAtom;
102 template <typename A> class ClassicStubHelperAtom;
103 template <typename A> class HybridStubHelperAtom;
104 template <typename A> class HybridStubHelperHelperAtom;
105 template <typename A> class FastStubHelperAtom;
106 template <typename A> class FastStubHelperHelperAtom;
107 template <typename A> class LazyPointerAtom;
108 template <typename A> class NonLazyPointerAtom;
109 template <typename A> class DylibLoadCommandsAtom;
110
111
112 // SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
113 class SectionInfo : public ObjectFile::Section {
114 public:
115 SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0),
116 fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false),
117 fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false),
118 fAllSelfModifyingStubs(false), fAllStubHelpers(false),
119 fAllZeroFill(false), fVirtualSection(false),
120 fHasTextLocalRelocs(false), fHasTextExternalRelocs(false)
121 { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
122 void setIndex(unsigned int index) { fIndex=index; }
123 std::vector<ObjectFile::Atom*> fAtoms;
124 char fSegmentName[20];
125 char fSectionName[20];
126 uint64_t fFileOffset;
127 uint64_t fSize;
128 uint32_t fRelocCount;
129 uint32_t fRelocOffset;
130 uint32_t fIndirectSymbolOffset;
131 uint8_t fAlignment;
132 bool fAllLazyPointers;
133 bool fAllLazyDylibPointers;
134 bool fAllNonLazyPointers;
135 bool fAllStubs;
136 bool fAllSelfModifyingStubs;
137 bool fAllStubHelpers;
138 bool fAllZeroFill;
139 bool fVirtualSection;
140 bool fHasTextLocalRelocs;
141 bool fHasTextExternalRelocs;
142 };
143
144 // SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
145 class SegmentInfo
146 {
147 public:
148 SegmentInfo(uint64_t pageSize) : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
149 fBaseAddress(0), fSize(0), fPageSize(pageSize), fFixedAddress(false),
150 fIndependentAddress(false), fHasLoadCommand(true) { fName[0] = '\0'; }
151 std::vector<class SectionInfo*> fSections;
152 char fName[20];
153 uint32_t fInitProtection;
154 uint32_t fMaxProtection;
155 uint64_t fFileOffset;
156 uint64_t fFileSize;
157 uint64_t fBaseAddress;
158 uint64_t fSize;
159 uint64_t fPageSize;
160 bool fFixedAddress;
161 bool fIndependentAddress;
162 bool fHasLoadCommand;
163 };
164
165
166 struct RebaseInfo {
167 RebaseInfo(uint8_t t, uint64_t addr) : fType(t), fAddress(addr) {}
168 uint8_t fType;
169 uint64_t fAddress;
170 // for sorting
171 int operator<(const RebaseInfo& rhs) const {
172 // sort by type, then address
173 if ( this->fType != rhs.fType )
174 return (this->fType < rhs.fType );
175 return (this->fAddress < rhs.fAddress );
176 }
177 };
178
179 struct BindingInfo {
180 BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t addend)
181 : fType(t), fFlags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), fLibraryOrdinal(ord),
182 fSymbolName(sym), fAddress(addr), fAddend(addend) {}
183 BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t addend)
184 : fType(t), fFlags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ), fLibraryOrdinal(0),
185 fSymbolName(sym), fAddress(addr), fAddend(addend) {}
186 uint8_t fType;
187 uint8_t fFlags;
188 int fLibraryOrdinal;
189 const char* fSymbolName;
190 uint64_t fAddress;
191 int64_t fAddend;
192
193 // for sorting
194 int operator<(const BindingInfo& rhs) const {
195 // sort by library, symbol, type, then address
196 if ( this->fLibraryOrdinal != rhs.fLibraryOrdinal )
197 return (this->fLibraryOrdinal < rhs.fLibraryOrdinal );
198 if ( this->fSymbolName != rhs.fSymbolName )
199 return ( strcmp(this->fSymbolName, rhs.fSymbolName) < 0 );
200 if ( this->fType != rhs.fType )
201 return (this->fType < rhs.fType );
202 return (this->fAddress < rhs.fAddress );
203 }
204 };
205
206
207 class ByteStream {
208 private:
209 std::vector<uint8_t> fData;
210 public:
211 std::vector<uint8_t>& bytes() { return fData; }
212 unsigned long size() const { return fData.size(); }
213 void reserve(unsigned long l) { fData.reserve(l); }
214 const uint8_t* start() const { return &fData[0]; }
215
216 void append_uleb128(uint64_t value) {
217 uint8_t byte;
218 do {
219 byte = value & 0x7F;
220 value &= ~0x7F;
221 if ( value != 0 )
222 byte |= 0x80;
223 fData.push_back(byte);
224 value = value >> 7;
225 } while( byte >= 0x80 );
226 }
227
228 void append_sleb128(int64_t value) {
229 bool isNeg = ( value < 0 );
230 uint8_t byte;
231 bool more;
232 do {
233 byte = value & 0x7F;
234 value = value >> 7;
235 if ( isNeg )
236 more = ( (value != -1) || ((byte & 0x40) == 0) );
237 else
238 more = ( (value != 0) || ((byte & 0x40) != 0) );
239 if ( more )
240 byte |= 0x80;
241 fData.push_back(byte);
242 }
243 while( more );
244 }
245
246 void append_string(const char* str) {
247 for (const char* s = str; *s != '\0'; ++s)
248 fData.push_back(*s);
249 fData.push_back('\0');
250 }
251
252 void append_byte(uint8_t byte) {
253 fData.push_back(byte);
254 }
255
256 static unsigned int uleb128_size(uint64_t value) {
257 uint32_t result = 0;
258 do {
259 value = value >> 7;
260 ++result;
261 } while ( value != 0 );
262 return result;
263 }
264
265 void pad_to_size(unsigned int alignment) {
266 while ( (fData.size() % alignment) != 0 )
267 fData.push_back(0);
268 }
269 };
270
271
272 template <typename A>
273 class Writer : public ExecutableFile::Writer
274 {
275 public:
276 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
277 virtual ~Writer();
278
279 virtual const char* getPath() { return fFilePath; }
280 virtual time_t getModificationTime() { return 0; }
281 virtual DebugInfoKind getDebugInfoKind() { return ObjectFile::Reader::kDebugInfoNone; }
282 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return fWriterSynthesizedAtoms; }
283 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
284 virtual std::vector<Stab>* getStabs() { return NULL; }
285
286 virtual ObjectFile::Atom& makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint,
287 bool objcReplacementClasses);
288 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
289 virtual uint64_t write(std::vector<class ObjectFile::Atom*>& atoms,
290 std::vector<class ObjectFile::Reader::Stab>& stabs,
291 class ObjectFile::Atom* entryPointAtom,
292 class ObjectFile::Atom* dyldClassicHelperAtom,
293 class ObjectFile::Atom* dyldCompressedHelperAtom,
294 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
295 bool createUUID, bool canScatter,
296 ObjectFile::Reader::CpuConstraint cpuConstraint,
297 bool biggerThanTwoGigs,
298 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
299 bool hasExternalWeakDefinitions);
300
301 private:
302 typedef typename A::P P;
303 typedef typename A::P::uint_t pint_t;
304
305 enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
306
307 void assignFileOffsets();
308 void synthesizeStubs();
309 void synthesizeKextGOT();
310 void createSplitSegContent();
311 void synthesizeUnwindInfoTable();
312 void insertDummyStubs();
313 void partitionIntoSections();
314 bool addBranchIslands();
315 bool addPPCBranchIslands();
316 bool isBranch24Reference(uint8_t kind);
317 void adjustLoadCommandsAndPadding();
318 void createDynamicLinkerCommand();
319 void createDylibCommands();
320 void buildLinkEdit();
321 const char* getArchString();
322 void writeMap();
323 uint64_t writeAtoms();
324 void writeNoOps(int fd, uint32_t from, uint32_t to);
325 void copyNoOps(uint8_t* from, uint8_t* to);
326 bool segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
327 void addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
328 void collectExportedAndImportedAndLocalAtoms();
329 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
330 void addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
331 void addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
332 void buildSymbolTable();
333 bool stringsNeedLabelsInObjects();
334 const char* symbolTableName(const ObjectFile::Atom* atom);
335 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
336 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
337 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
338 void copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
339 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
340 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
341 bool targetRequiresWeakBinding(const ObjectFile::Atom& target);
342 int compressedOrdinalForImortedAtom(ObjectFile::Atom* target);
343 bool shouldExport(const ObjectFile::Atom& atom) const;
344 void buildFixups();
345 void adjustLinkEditSections();
346 void buildObjectFileFixups();
347 void buildExecutableFixups();
348 bool preboundLazyPointerType(uint8_t* type);
349 uint64_t relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
350 void fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
351 void fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
352 void fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
353 uint8_t buffer[], bool finalLinkedImage) const;
354 uint32_t symbolIndex(ObjectFile::Atom& atom);
355 bool makesExternalRelocatableReference(ObjectFile::Atom& target) const;
356 uint32_t addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
357 uint32_t addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
358 uint8_t getRelocPointerSize();
359 uint64_t maxAddress();
360 bool stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref);
361 bool GOTReferenceKind(uint8_t kind);
362 bool optimizableGOTReferenceKind(uint8_t kind);
363 bool weakImportReferenceKind(uint8_t kind);
364 unsigned int collectStabs();
365 uint64_t valueForStab(const ObjectFile::Reader::Stab& stab);
366 uint32_t stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
367 uint8_t sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
368 void addStabs(uint32_t startIndex);
369 RelocKind relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
370 bool illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
371 bool generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
372 bool generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
373 bool mightNeedPadSegment();
374 void scanForAbsoluteReferences();
375 bool needsModuleTable();
376 void optimizeDylibReferences();
377 bool indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const;
378
379 struct DirectLibrary {
380 class ObjectFile::Reader* fLibrary;
381 bool fWeak;
382 bool fReExport;
383 };
384
385 friend class WriterAtom<A>;
386 friend class PageZeroAtom<A>;
387 friend class CustomStackAtom<A>;
388 friend class MachHeaderAtom<A>;
389 friend class SegmentLoadCommandsAtom<A>;
390 friend class EncryptionLoadCommandsAtom<A>;
391 friend class SymbolTableLoadCommandsAtom<A>;
392 friend class DyldInfoLoadCommandsAtom<A>;
393 friend class ThreadsLoadCommandsAtom<A>;
394 friend class DylibIDLoadCommandsAtom<A>;
395 friend class RoutinesLoadCommandsAtom<A>;
396 friend class DyldLoadCommandsAtom<A>;
397 friend class UUIDLoadCommandAtom<A>;
398 friend class LinkEditAtom<A>;
399 friend class SectionRelocationsLinkEditAtom<A>;
400 friend class CompressedRebaseInfoLinkEditAtom<A>;
401 friend class CompressedBindingInfoLinkEditAtom<A>;
402 friend class CompressedWeakBindingInfoLinkEditAtom<A>;
403 friend class CompressedLazyBindingInfoLinkEditAtom<A>;
404 friend class CompressedExportInfoLinkEditAtom<A>;
405 friend class LocalRelocationsLinkEditAtom<A>;
406 friend class ExternalRelocationsLinkEditAtom<A>;
407 friend class SymbolTableLinkEditAtom<A>;
408 friend class SegmentSplitInfoLoadCommandsAtom<A>;
409 friend class SegmentSplitInfoContentAtom<A>;
410 friend class IndirectTableLinkEditAtom<A>;
411 friend class ModuleInfoLinkEditAtom<A>;
412 friend class StringsLinkEditAtom<A>;
413 friend class LoadCommandsPaddingAtom<A>;
414 friend class UnwindInfoAtom<A>;
415 friend class StubAtom<A>;
416 friend class StubHelperAtom<A>;
417 friend class ClassicStubHelperAtom<A>;
418 friend class HybridStubHelperAtom<A>;
419 friend class FastStubHelperAtom<A>;
420 friend class FastStubHelperHelperAtom<A>;
421 friend class HybridStubHelperHelperAtom<A>;
422 friend class LazyPointerAtom<A>;
423 friend class NonLazyPointerAtom<A>;
424 friend class DylibLoadCommandsAtom<A>;
425
426 const char* fFilePath;
427 Options& fOptions;
428 std::vector<class ObjectFile::Atom*>* fAllAtoms;
429 std::vector<class ObjectFile::Reader::Stab>* fStabs;
430 std::set<const class ObjectFile::Atom*>* fRegularDefAtomsThatOverrideADylibsWeakDef;
431 class SectionInfo* fLoadCommandsSection;
432 class SegmentInfo* fLoadCommandsSegment;
433 class MachHeaderAtom<A>* fMachHeaderAtom;
434 class EncryptionLoadCommandsAtom<A>* fEncryptionLoadCommand;
435 class SegmentLoadCommandsAtom<A>* fSegmentCommands;
436 class SymbolTableLoadCommandsAtom<A>* fSymbolTableCommands;
437 class LoadCommandsPaddingAtom<A>* fHeaderPadding;
438 class UnwindInfoAtom<A>* fUnwindInfoAtom;
439 class UUIDLoadCommandAtom<A>* fUUIDAtom;
440 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
441 std::vector<SegmentInfo*> fSegmentInfos;
442 class SegmentInfo* fPadSegmentInfo;
443 class ObjectFile::Atom* fEntryPoint;
444 class ObjectFile::Atom* fDyldClassicHelperAtom;
445 class ObjectFile::Atom* fDyldCompressedHelperAtom;
446 class ObjectFile::Atom* fDyldLazyDylibHelper;
447 std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*> fLibraryToLoadCommand;
448 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
449 std::map<class ObjectFile::Reader*, class ObjectFile::Reader*> fLibraryAliases;
450 std::set<class ObjectFile::Reader*> fForcedWeakImportReaders;
451 std::vector<class ObjectFile::Atom*> fExportedAtoms;
452 std::vector<class ObjectFile::Atom*> fImportedAtoms;
453 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
454 std::vector<macho_nlist<P> > fLocalExtraLabels;
455 std::vector<macho_nlist<P> > fGlobalExtraLabels;
456 std::map<ObjectFile::Atom*, uint32_t> fAtomToSymbolIndex;
457 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
458 class CompressedRebaseInfoLinkEditAtom<A>* fCompressedRebaseInfoAtom;
459 class CompressedBindingInfoLinkEditAtom<A>* fCompressedBindingInfoAtom;
460 class CompressedWeakBindingInfoLinkEditAtom<A>* fCompressedWeakBindingInfoAtom;
461 class CompressedLazyBindingInfoLinkEditAtom<A>* fCompressedLazyBindingInfoAtom;
462 class CompressedExportInfoLinkEditAtom<A>* fCompressedExportInfoAtom;
463 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
464 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
465 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
466 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
467 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
468 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
469 class StringsLinkEditAtom<A>* fStringsAtom;
470 class PageZeroAtom<A>* fPageZeroAtom;
471 class NonLazyPointerAtom<A>* fFastStubGOTAtom;
472 macho_nlist<P>* fSymbolTable;
473 std::vector<macho_relocation_info<P> > fSectionRelocs;
474 std::vector<macho_relocation_info<P> > fInternalRelocs;
475 std::vector<macho_relocation_info<P> > fExternalRelocs;
476 std::vector<RebaseInfo> fRebaseInfo;
477 std::vector<BindingInfo> fBindingInfo;
478 std::vector<BindingInfo> fWeakBindingInfo;
479 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
480 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
481 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
482 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
483 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
484 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyDylibPointers;
485 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
486 uint32_t fSymbolTableCount;
487 uint32_t fSymbolTableStabsCount;
488 uint32_t fSymbolTableStabsStartIndex;
489 uint32_t fSymbolTableLocalCount;
490 uint32_t fSymbolTableLocalStartIndex;
491 uint32_t fSymbolTableExportCount;
492 uint32_t fSymbolTableExportStartIndex;
493 uint32_t fSymbolTableImportCount;
494 uint32_t fSymbolTableImportStartIndex;
495 uint32_t fLargestAtomSize;
496 bool fEmitVirtualSections;
497 bool fHasWeakExports;
498 bool fReferencesWeakImports;
499 bool fCanScatter;
500 bool fWritableSegmentPastFirst4GB;
501 bool fNoReExportedDylibs;
502 bool fBiggerThanTwoGigs;
503 bool fSlideable;
504 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
505 std::set<const ObjectFile::Reader*> fDylibReadersWithNonWeakImports;
506 std::set<const ObjectFile::Reader*> fDylibReadersWithWeakImports;
507 SegmentInfo* fFirstWritableSegment;
508 ObjectFile::Reader::CpuConstraint fCpuConstraint;
509 uint32_t fAnonNameIndex;
510 };
511
512
513 class Segment : public ObjectFile::Segment
514 {
515 public:
516 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
517 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
518 virtual const char* getName() const { return fName; }
519 virtual bool isContentReadable() const { return fReadable; }
520 virtual bool isContentWritable() const { return fWritable; }
521 virtual bool isContentExecutable() const { return fExecutable; }
522 virtual bool hasFixedAddress() const { return fFixedAddress; }
523
524 static Segment fgTextSegment;
525 static Segment fgPageZeroSegment;
526 static Segment fgLinkEditSegment;
527 static Segment fgStackSegment;
528 static Segment fgImportSegment;
529 static Segment fgROImportSegment;
530 static Segment fgDataSegment;
531 static Segment fgObjCSegment;
532 static Segment fgHeaderSegment;
533
534
535 private:
536 const char* fName;
537 const bool fReadable;
538 const bool fWritable;
539 const bool fExecutable;
540 const bool fFixedAddress;
541 };
542
543 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
544 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
545 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
546 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
547 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
548 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
549 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
550 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
551 Segment Segment::fgHeaderSegment("__HEADER", true, false, true, false);
552
553
554 template <typename A>
555 class WriterAtom : public ObjectFile::Atom
556 {
557 public:
558 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
559 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
560
561 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
562 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
563 virtual const char* getName() const { return NULL; }
564 virtual const char* getDisplayName() const { return this->getName(); }
565 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
566 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
567 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
568 virtual bool dontDeadStrip() const { return true; }
569 virtual bool isZeroFill() const { return false; }
570 virtual bool isThumb() const { return false; }
571 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
572 virtual bool mustRemainInSection() const { return true; }
573 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
574 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
575 virtual uint32_t getOrdinal() const { return 0; }
576 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
577 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
578 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
579 virtual void setScope(Scope) { }
580
581
582 protected:
583 virtual ~WriterAtom() {}
584 typedef typename A::P P;
585 typedef typename A::P::E E;
586
587 static Segment& headerSegment(Writer<A>& writer) { return (writer.fOptions.outputKind()==Options::kPreload)
588 ? Segment::fgHeaderSegment : Segment::fgTextSegment; }
589
590 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
591
592 Writer<A>& fWriter;
593 Segment& fSegment;
594 };
595
596 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
597
598
599 template <typename A>
600 class PageZeroAtom : public WriterAtom<A>
601 {
602 public:
603 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
604 fSize(fWriter.fOptions.zeroPageSize()) {}
605 virtual const char* getDisplayName() const { return "page zero content"; }
606 virtual bool isZeroFill() const { return true; }
607 virtual uint64_t getSize() const { return fSize; }
608 virtual const char* getSectionName() const { return "._zeropage"; }
609 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
610 void setSize(uint64_t size) { fSize = size; }
611 private:
612 using WriterAtom<A>::fWriter;
613 typedef typename A::P P;
614 uint64_t fSize;
615 };
616
617
618 template <typename A>
619 class DsoHandleAtom : public WriterAtom<A>
620 {
621 public:
622 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
623 virtual const char* getName() const { return "___dso_handle"; }
624 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
625 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
626 virtual uint64_t getSize() const { return 0; }
627 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
628 virtual const char* getSectionName() const { return "._mach_header"; }
629 virtual void copyRawContent(uint8_t buffer[]) const {}
630 };
631
632
633 template <typename A>
634 class MachHeaderAtom : public WriterAtom<A>
635 {
636 public:
637 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)) {}
638 virtual const char* getName() const;
639 virtual const char* getDisplayName() const;
640 virtual ObjectFile::Atom::Scope getScope() const;
641 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
642 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
643 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
644 virtual const char* getSectionName() const { return "._mach_header"; }
645 virtual uint32_t getOrdinal() const { return 1; }
646 virtual void copyRawContent(uint8_t buffer[]) const;
647 private:
648 using WriterAtom<A>::fWriter;
649 typedef typename A::P P;
650 void setHeaderInfo(macho_header<typename A::P>& header) const;
651 };
652
653 template <typename A>
654 class CustomStackAtom : public WriterAtom<A>
655 {
656 public:
657 CustomStackAtom(Writer<A>& writer);
658 virtual const char* getDisplayName() const { return "custom stack content"; }
659 virtual bool isZeroFill() const { return true; }
660 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
661 virtual const char* getSectionName() const { return "._stack"; }
662 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
663 private:
664 using WriterAtom<A>::fWriter;
665 typedef typename A::P P;
666 static bool stackGrowsDown();
667 };
668
669 template <typename A>
670 class LoadCommandAtom : public WriterAtom<A>
671 {
672 protected:
673 LoadCommandAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)), fOrdinal(fgCurrentOrdinal++) {}
674 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
675 virtual const char* getSectionName() const { return "._load_commands"; }
676 virtual uint32_t getOrdinal() const { return fOrdinal; }
677 static uint64_t alignedSize(uint64_t size);
678 protected:
679 uint32_t fOrdinal;
680 static uint32_t fgCurrentOrdinal;
681 };
682
683 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
684
685 template <typename A>
686 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
687 {
688 public:
689 SegmentLoadCommandsAtom(Writer<A>& writer)
690 : LoadCommandAtom<A>(writer), fCommandCount(0), fSize(0)
691 { writer.fSegmentCommands = this; }
692 virtual const char* getDisplayName() const { return "segment load commands"; }
693 virtual uint64_t getSize() const { return fSize; }
694 virtual void copyRawContent(uint8_t buffer[]) const;
695
696 void computeSize();
697 void setup();
698 unsigned int commandCount() { return fCommandCount; }
699 private:
700 using WriterAtom<A>::fWriter;
701 typedef typename A::P P;
702 unsigned int fCommandCount;
703 uint32_t fSize;
704 };
705
706
707 template <typename A>
708 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
709 {
710 public:
711 SymbolTableLoadCommandsAtom(Writer<A>&);
712 virtual const char* getDisplayName() const { return "symbol table load commands"; }
713 virtual uint64_t getSize() const;
714 virtual void copyRawContent(uint8_t buffer[]) const;
715 unsigned int commandCount();
716 void needDynamicTable();
717 private:
718 using WriterAtom<A>::fWriter;
719 typedef typename A::P P;
720 bool fNeedsDynamicSymbolTable;
721 macho_symtab_command<typename A::P> fSymbolTable;
722 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
723 };
724
725 template <typename A>
726 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
727 {
728 public:
729 ThreadsLoadCommandsAtom(Writer<A>& writer)
730 : LoadCommandAtom<A>(writer) {}
731 virtual const char* getDisplayName() const { return "thread load commands"; }
732 virtual uint64_t getSize() const;
733 virtual void copyRawContent(uint8_t buffer[]) const;
734 private:
735 using WriterAtom<A>::fWriter;
736 typedef typename A::P P;
737 uint8_t* fBuffer;
738 uint32_t fBufferSize;
739 };
740
741 template <typename A>
742 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
743 {
744 public:
745 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
746 virtual const char* getDisplayName() const { return "dyld load command"; }
747 virtual uint64_t getSize() const;
748 virtual void copyRawContent(uint8_t buffer[]) const;
749 private:
750 using WriterAtom<A>::fWriter;
751 typedef typename A::P P;
752 };
753
754 template <typename A>
755 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
756 {
757 public:
758 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
759 virtual const char* getDisplayName() const { return "segment split info load command"; }
760 virtual uint64_t getSize() const;
761 virtual void copyRawContent(uint8_t buffer[]) const;
762 private:
763 using WriterAtom<A>::fWriter;
764 typedef typename A::P P;
765 };
766
767 template <typename A>
768 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
769 {
770 public:
771 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
772 LoadCommandAtom<A>(writer), clientString(client) {}
773 virtual const char* getDisplayName() const { return "allowable_client load command"; }
774 virtual uint64_t getSize() const;
775 virtual void copyRawContent(uint8_t buffer[]) const;
776 private:
777 using WriterAtom<A>::fWriter;
778 typedef typename A::P P;
779 const char* clientString;
780 };
781
782 template <typename A>
783 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
784 {
785 public:
786 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
787 : LoadCommandAtom<A>(writer), fInfo(info),
788 fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
789 virtual const char* getDisplayName() const { return "dylib load command"; }
790 virtual uint64_t getSize() const;
791 virtual void copyRawContent(uint8_t buffer[]) const;
792 virtual void optimizeAway() { fOptimizedAway = true; }
793 bool linkedWeak() { return fInfo.options.fWeakImport; }
794 private:
795 using WriterAtom<A>::fWriter;
796 typedef typename A::P P;
797 ExecutableFile::DyLibUsed fInfo;
798 bool fOptimizedAway;
799 };
800
801 template <typename A>
802 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
803 {
804 public:
805 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
806 virtual const char* getDisplayName() const { return "dylib ID load command"; }
807 virtual uint64_t getSize() const;
808 virtual void copyRawContent(uint8_t buffer[]) const;
809 private:
810 using WriterAtom<A>::fWriter;
811 typedef typename A::P P;
812 };
813
814 template <typename A>
815 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
816 {
817 public:
818 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
819 virtual const char* getDisplayName() const { return "routines load command"; }
820 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
821 virtual void copyRawContent(uint8_t buffer[]) const;
822 private:
823 using WriterAtom<A>::fWriter;
824 typedef typename A::P P;
825 };
826
827 template <typename A>
828 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
829 {
830 public:
831 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
832 : LoadCommandAtom<A>(writer), fName(name) {}
833 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
834 virtual uint64_t getSize() const;
835 virtual void copyRawContent(uint8_t buffer[]) const;
836 private:
837 typedef typename A::P P;
838 const char* fName;
839 };
840
841 template <typename A>
842 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
843 {
844 public:
845 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
846 : LoadCommandAtom<A>(writer), fNameStart(nameStart), fNameLength(nameLen) {}
847 virtual const char* getDisplayName() const { return "sub-library load command"; }
848 virtual uint64_t getSize() const;
849 virtual void copyRawContent(uint8_t buffer[]) const;
850 private:
851 using WriterAtom<A>::fWriter;
852 typedef typename A::P P;
853 const char* fNameStart;
854 int fNameLength;
855 };
856
857 template <typename A>
858 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
859 {
860 public:
861 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
862 : LoadCommandAtom<A>(writer), fName(name) {}
863 virtual const char* getDisplayName() const { return "umbrella load command"; }
864 virtual uint64_t getSize() const;
865 virtual void copyRawContent(uint8_t buffer[]) const;
866 private:
867 using WriterAtom<A>::fWriter;
868 typedef typename A::P P;
869 const char* fName;
870 };
871
872 template <typename A>
873 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
874 {
875 public:
876 UUIDLoadCommandAtom(Writer<A>& writer)
877 : LoadCommandAtom<A>(writer), fEmit(false) {}
878 virtual const char* getDisplayName() const { return "uuid load command"; }
879 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
880 virtual void copyRawContent(uint8_t buffer[]) const;
881 virtual void generate();
882 void setContent(const uint8_t uuid[16]);
883 const uint8_t* getUUID() { return fUUID; }
884 private:
885 using WriterAtom<A>::fWriter;
886 typedef typename A::P P;
887 uuid_t fUUID;
888 bool fEmit;
889 };
890
891
892 template <typename A>
893 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
894 {
895 public:
896 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
897 : LoadCommandAtom<A>(writer), fPath(path) {}
898 virtual const char* getDisplayName() const { return "rpath load command"; }
899 virtual uint64_t getSize() const;
900 virtual void copyRawContent(uint8_t buffer[]) const;
901 private:
902 using WriterAtom<A>::fWriter;
903 typedef typename A::P P;
904 const char* fPath;
905 };
906
907 template <typename A>
908 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
909 {
910 public:
911 EncryptionLoadCommandsAtom(Writer<A>& writer)
912 : LoadCommandAtom<A>(writer), fStartOffset(0),
913 fEndOffset(0) {}
914 virtual const char* getDisplayName() const { return "encryption info load command"; }
915 virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
916 virtual void copyRawContent(uint8_t buffer[]) const;
917 void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
918 void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
919 private:
920 using WriterAtom<A>::fWriter;
921 typedef typename A::P P;
922 uint32_t fStartOffset;
923 uint32_t fEndOffset;
924 };
925
926 template <typename A>
927 class DyldInfoLoadCommandsAtom : public LoadCommandAtom<A>
928 {
929 public:
930 DyldInfoLoadCommandsAtom(Writer<A>& writer)
931 : LoadCommandAtom<A>(writer) {}
932 virtual const char* getDisplayName() const { return "dyld info load command"; }
933 virtual uint64_t getSize() const { return sizeof(macho_dyld_info_command<typename A::P>); }
934 virtual void copyRawContent(uint8_t buffer[]) const;
935 private:
936 using WriterAtom<A>::fWriter;
937 typedef typename A::P P;
938 };
939
940
941 template <typename A>
942 class LoadCommandsPaddingAtom : public WriterAtom<A>
943 {
944 public:
945 LoadCommandsPaddingAtom(Writer<A>& writer)
946 : WriterAtom<A>(writer, headerSegment(writer)), fSize(0) {}
947 virtual const char* getDisplayName() const { return "header padding"; }
948 virtual uint64_t getSize() const { return fSize; }
949 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
950 virtual void copyRawContent(uint8_t buffer[]) const;
951
952 void setSize(uint64_t newSize);
953 private:
954 using WriterAtom<A>::fWriter;
955 typedef typename A::P P;
956 uint64_t fSize;
957 };
958
959 template <typename A>
960 class UnwindInfoAtom : public WriterAtom<A>
961 {
962 public:
963 UnwindInfoAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment),
964 fHeaderSize(0), fPagesSize(0), fAlignment(4) {}
965 virtual const char* getName() const { return "unwind info"; }
966 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
967 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
968 virtual uint64_t getSize() const { return fHeaderSize+fPagesSize; }
969 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
970 virtual const char* getSectionName() const { return "__unwind_info"; }
971 virtual uint32_t getOrdinal() const { return 1; }
972 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)fReferences; }
973 virtual void copyRawContent(uint8_t buffer[]) const;
974
975 void addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
976 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsda,
977 ObjectFile::Atom* personalityPointer);
978 void generate();
979
980 private:
981 using WriterAtom<A>::fWriter;
982 typedef typename A::P P;
983 struct Info { ObjectFile::Atom* func; ObjectFile::Atom* fde; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; };
984 struct LSDAEntry { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; };
985 struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fde; };
986 struct CompressedFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fromFunc; };
987 struct CompressedEncodingFixUp { uint8_t* contentPointer; ObjectFile::Atom* fde; };
988
989 bool encodingMeansUseDwarf(compact_unwind_encoding_t encoding);
990 void compressDuplicates(std::vector<Info>& uniqueInfos);
991 void findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings);
992 void makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap);
993 unsigned int makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize, unsigned int endIndex,
994 uint8_t*& pageEnd);
995 unsigned int makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
996 const std::map<uint32_t,unsigned int> commonEncodings,
997 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
998 void makePersonalityIndex(std::vector<Info>& uniqueInfos);
999
1000
1001 uint32_t fHeaderSize;
1002 uint32_t fPagesSize;
1003 uint8_t* fHeaderContent;
1004 uint8_t* fPagesContent;
1005 uint8_t* fPagesContentForDelete;
1006 ObjectFile::Alignment fAlignment;
1007 std::vector<Info> fInfos;
1008 std::map<ObjectFile::Atom*, uint32_t> fPersonalityIndexMap;
1009 std::vector<LSDAEntry> fLSDAIndex;
1010 std::vector<RegFixUp> fRegFixUps;
1011 std::vector<CompressedFixUp> fCompressedFixUps;
1012 std::vector<CompressedEncodingFixUp> fCompressedEncodingFixUps;
1013 std::vector<ObjectFile::Reference*> fReferences;
1014 };
1015
1016
1017
1018 template <typename A>
1019 class LinkEditAtom : public WriterAtom<A>
1020 {
1021 public:
1022 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
1023 uint64_t getFileOffset() const;
1024 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
1025 virtual uint32_t getOrdinal() const { return fOrdinal; }
1026 private:
1027 uint32_t fOrdinal;
1028 static uint32_t fgCurrentOrdinal;
1029 private:
1030 typedef typename A::P P;
1031 };
1032
1033 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
1034
1035 template <typename A>
1036 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
1037 {
1038 public:
1039 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1040 virtual const char* getDisplayName() const { return "section relocations"; }
1041 virtual uint64_t getSize() const;
1042 virtual const char* getSectionName() const { return "._section_relocs"; }
1043 virtual void copyRawContent(uint8_t buffer[]) const;
1044 private:
1045 using WriterAtom<A>::fWriter;
1046 typedef typename A::P P;
1047 };
1048
1049 template <typename A>
1050 class CompressedInfoLinkEditAtom : public LinkEditAtom<A>
1051 {
1052 public:
1053 CompressedInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1054 virtual uint64_t getSize() const { return fEncodedData.size(); }
1055 virtual void copyRawContent(uint8_t buffer[]) const { memcpy(buffer, fEncodedData.start(), fEncodedData.size()); }
1056 protected:
1057 typedef typename A::P::uint_t pint_t;
1058 ByteStream fEncodedData;
1059 private:
1060 using WriterAtom<A>::fWriter;
1061 typedef typename A::P P;
1062 };
1063
1064
1065
1066 template <typename A>
1067 class CompressedRebaseInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1068 {
1069 public:
1070 CompressedRebaseInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1071 virtual const char* getDisplayName() const { return "compressed rebase info"; }
1072 virtual const char* getSectionName() const { return "._rebase info"; }
1073 void encode();
1074 private:
1075 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1076 using CompressedInfoLinkEditAtom<A>::fWriter;
1077 typedef typename A::P P;
1078 typedef typename A::P::uint_t pint_t;
1079 };
1080
1081 template <typename A>
1082 class CompressedBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1083 {
1084 public:
1085 CompressedBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1086 virtual const char* getDisplayName() const { return "compressed binding info"; }
1087 virtual const char* getSectionName() const { return "._binding info"; }
1088 void encode();
1089 private:
1090 using CompressedInfoLinkEditAtom<A>::fWriter;
1091 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1092 typedef typename A::P P;
1093 typedef typename A::P::uint_t pint_t;
1094 };
1095
1096 template <typename A>
1097 class CompressedWeakBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1098 {
1099 public:
1100 CompressedWeakBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1101 virtual const char* getDisplayName() const { return "compressed weak binding info"; }
1102 virtual const char* getSectionName() const { return "._wkbinding info"; }
1103 void encode();
1104 private:
1105 using CompressedInfoLinkEditAtom<A>::fWriter;
1106 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1107 typedef typename A::P P;
1108 typedef typename A::P::uint_t pint_t;
1109 };
1110
1111 template <typename A>
1112 class CompressedLazyBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1113 {
1114 public:
1115 CompressedLazyBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1116 virtual const char* getDisplayName() const { return "compressed lazy binding info"; }
1117 virtual const char* getSectionName() const { return "._lzbinding info"; }
1118 void encode();
1119 private:
1120 std::vector<uint32_t> fStarts;
1121
1122 using CompressedInfoLinkEditAtom<A>::fWriter;
1123 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1124 typedef typename A::P P;
1125 typedef typename A::P::uint_t pint_t;
1126 };
1127
1128
1129 template <typename A>
1130 class CompressedExportInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1131 {
1132 public:
1133 CompressedExportInfoLinkEditAtom(Writer<A>& writer)
1134 : CompressedInfoLinkEditAtom<A>(writer), fStartNode(strdup("")) { }
1135 virtual const char* getDisplayName() const { return "compressed export info"; }
1136 virtual const char* getSectionName() const { return "._export info"; }
1137 void encode();
1138 private:
1139 using WriterAtom<A>::fWriter;
1140 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1141 typedef typename A::P P;
1142 typedef typename A::P::uint_t pint_t;
1143 struct node;
1144
1145 struct edge
1146 {
1147 edge(const char* s, struct node* n) : fSubString(s), fChild(n) { }
1148 ~edge() { }
1149 const char* fSubString;
1150 struct node* fChild;
1151
1152 };
1153
1154 struct node
1155 {
1156 node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false),
1157 fHaveExportInfo(false), fTrieOffset(0) {}
1158 ~node() { }
1159 const char* fCummulativeString;
1160 std::vector<edge> fChildren;
1161 uint64_t fAddress;
1162 uint32_t fFlags;
1163 bool fOrdered;
1164 bool fHaveExportInfo;
1165 uint32_t fTrieOffset;
1166
1167 void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
1168 const char* partialStr = &fullStr[strlen(fCummulativeString)];
1169 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1170 edge& e = *it;
1171 int subStringLen = strlen(e.fSubString);
1172 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1173 // already have matching edge, go down that path
1174 e.fChild->addSymbol(fullStr, address, flags);
1175 return;
1176 }
1177 else {
1178 for (int i=subStringLen-1; i > 0; --i) {
1179 if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
1180 // found a common substring, splice in new node
1181 // was A -> C, now A -> B -> C
1182 char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
1183 bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
1184 //node* aNode = this;
1185 node* bNode = new node(bNodeCummStr);
1186 node* cNode = e.fChild;
1187 char* abEdgeStr = strdup(e.fSubString);
1188 abEdgeStr[i] = '\0';
1189 char* bcEdgeStr = strdup(&e.fSubString[i]);
1190 edge& abEdge = e;
1191 abEdge.fSubString = abEdgeStr;
1192 abEdge.fChild = bNode;
1193 edge bcEdge(bcEdgeStr, cNode);
1194 bNode->fChildren.push_back(bcEdge);
1195 bNode->addSymbol(fullStr, address, flags);
1196 return;
1197 }
1198 }
1199 }
1200 }
1201 // no commonality with any existing child, make a new edge that is this whole string
1202 node* newNode = new node(strdup(fullStr));
1203 edge newEdge(strdup(partialStr), newNode);
1204 fChildren.push_back(newEdge);
1205 newNode->fAddress = address;
1206 newNode->fFlags = flags;
1207 newNode->fHaveExportInfo = true;
1208 }
1209
1210 void addOrderedNodes(const char* name, std::vector<node*>& orderedNodes) {
1211 if ( !fOrdered ) {
1212 orderedNodes.push_back(this);
1213 //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
1214 fOrdered = true;
1215 }
1216 const char* partialStr = &name[strlen(fCummulativeString)];
1217 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1218 edge& e = *it;
1219 int subStringLen = strlen(e.fSubString);
1220 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1221 // already have matching edge, go down that path
1222 e.fChild->addOrderedNodes(name, orderedNodes);
1223 return;
1224 }
1225 }
1226 }
1227
1228 // byte for terminal node size in bytes, or 0x00 if not terminal node
1229 // teminal node (uleb128 flags, uleb128 addr)
1230 // byte for child node count
1231 // each child: zero terminated substring, uleb128 node offset
1232 bool updateOffset(uint32_t& offset) {
1233 uint32_t nodeSize = 1; // byte for length of export info
1234 if ( fHaveExportInfo )
1235 nodeSize += ByteStream::uleb128_size(fFlags) + ByteStream::uleb128_size(fAddress);
1236
1237 // add children
1238 ++nodeSize; // byte for count of chidren
1239 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1240 edge& e = *it;
1241 nodeSize += strlen(e.fSubString) + 1 + ByteStream::uleb128_size(e.fChild->fTrieOffset);
1242 }
1243 bool result = (fTrieOffset != offset);
1244 fTrieOffset = offset;
1245 //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
1246 offset += nodeSize;
1247 // return true if fTrieOffset was changed
1248 return result;
1249 }
1250
1251 void appendToStream(ByteStream& out) {
1252 if ( fHaveExportInfo ) {
1253 // nodes with export info: size, flags, address
1254 out.append_byte(out.uleb128_size(fFlags) + out.uleb128_size(fAddress));
1255 out.append_uleb128(fFlags);
1256 out.append_uleb128(fAddress);
1257 }
1258 else {
1259 // no export info
1260 out.append_byte(0);
1261 }
1262 // write number of children
1263 out.append_byte(fChildren.size());
1264 // write each child
1265 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1266 edge& e = *it;
1267 out.append_string(e.fSubString);
1268 out.append_uleb128(e.fChild->fTrieOffset);
1269 }
1270 }
1271
1272 };
1273
1274
1275 struct node fStartNode;
1276 };
1277
1278 template <typename A>
1279 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
1280 {
1281 public:
1282 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1283 virtual const char* getDisplayName() const { return "local relocations"; }
1284 virtual uint64_t getSize() const;
1285 virtual const char* getSectionName() const { return "._local_relocs"; }
1286 virtual void copyRawContent(uint8_t buffer[]) const;
1287 private:
1288 using WriterAtom<A>::fWriter;
1289 typedef typename A::P P;
1290 };
1291
1292 template <typename A>
1293 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
1294 {
1295 public:
1296 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1297 virtual const char* getDisplayName() const { return "symbol table"; }
1298 virtual uint64_t getSize() const;
1299 virtual const char* getSectionName() const { return "._symbol_table"; }
1300 virtual void copyRawContent(uint8_t buffer[]) const;
1301 private:
1302 using WriterAtom<A>::fWriter;
1303 typedef typename A::P P;
1304 };
1305
1306 template <typename A>
1307 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
1308 {
1309 public:
1310 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1311 virtual const char* getDisplayName() const { return "external relocations"; }
1312 virtual uint64_t getSize() const;
1313 virtual const char* getSectionName() const { return "._extern_relocs"; }
1314 virtual void copyRawContent(uint8_t buffer[]) const;
1315 private:
1316 using WriterAtom<A>::fWriter;
1317 typedef typename A::P P;
1318 };
1319
1320 struct IndirectEntry {
1321 uint32_t indirectIndex;
1322 uint32_t symbolIndex;
1323 };
1324
1325
1326 template <typename A>
1327 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
1328 {
1329 public:
1330 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
1331 virtual const char* getDisplayName() const { return "split segment info"; }
1332 virtual uint64_t getSize() const;
1333 virtual const char* getSectionName() const { return "._split_info"; }
1334 virtual void copyRawContent(uint8_t buffer[]) const;
1335 bool canEncode() { return !fCantEncode; }
1336 void setCantEncode() { fCantEncode = true; }
1337 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
1338 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
1339 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
1340 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
1341 void encode();
1342
1343 private:
1344 using WriterAtom<A>::fWriter;
1345 typedef typename A::P P;
1346 typedef typename A::P::uint_t pint_t;
1347 struct AtomAndOffset {
1348 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
1349 const ObjectFile::Atom* atom;
1350 uint32_t offset;
1351 };
1352 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
1353
1354 std::vector<AtomAndOffset> fKind1Locations;
1355 std::vector<AtomAndOffset> fKind2Locations;
1356 std::vector<AtomAndOffset> fKind3Locations;
1357 std::vector<AtomAndOffset> fKind4Locations;
1358 std::vector<uint8_t> fEncodedData;
1359 bool fCantEncode;
1360 };
1361
1362 template <typename A>
1363 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
1364 {
1365 public:
1366 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1367 virtual const char* getDisplayName() const { return "indirect symbol table"; }
1368 virtual uint64_t getSize() const;
1369 virtual const char* getSectionName() const { return "._indirect_syms"; }
1370 virtual void copyRawContent(uint8_t buffer[]) const;
1371
1372 std::vector<IndirectEntry> fTable;
1373
1374 private:
1375 using WriterAtom<A>::fWriter;
1376 typedef typename A::P P;
1377 };
1378
1379 template <typename A>
1380 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
1381 {
1382 public:
1383 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
1384 virtual const char* getDisplayName() const { return "module table"; }
1385 virtual uint64_t getSize() const;
1386 virtual const char* getSectionName() const { return "._module_info"; }
1387 virtual void copyRawContent(uint8_t buffer[]) const;
1388
1389 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
1390 uint32_t getTableOfContentsFileOffset() const;
1391 uint32_t getModuleTableFileOffset() const;
1392 uint32_t getReferencesFileOffset() const;
1393 uint32_t getReferencesCount() const;
1394
1395 private:
1396 using WriterAtom<A>::fWriter;
1397 typedef typename A::P P;
1398 typedef typename A::P::uint_t pint_t;
1399 uint32_t fModuleNameOffset;
1400 };
1401
1402
1403 class CStringEquals
1404 {
1405 public:
1406 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
1407 };
1408
1409 template <typename A>
1410 class StringsLinkEditAtom : public LinkEditAtom<A>
1411 {
1412 public:
1413 StringsLinkEditAtom(Writer<A>& writer);
1414 virtual const char* getDisplayName() const { return "string pool"; }
1415 virtual uint64_t getSize() const;
1416 virtual const char* getSectionName() const { return "._string_pool"; }
1417 virtual void copyRawContent(uint8_t buffer[]) const;
1418
1419 int32_t add(const char* name);
1420 int32_t addUnique(const char* name);
1421 int32_t emptyString() { return 1; }
1422 const char* stringForIndex(int32_t) const;
1423
1424 private:
1425 using WriterAtom<A>::fWriter;
1426 typedef typename A::P P;
1427 enum { kBufferSize = 0x01000000 };
1428 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
1429
1430 std::vector<char*> fFullBuffers;
1431 char* fCurrentBuffer;
1432 uint32_t fCurrentBufferUsed;
1433 StringToOffset fUniqueStrings;
1434 };
1435
1436
1437
1438 template <typename A>
1439 class UndefinedSymbolProxyAtom : public WriterAtom<A>
1440 {
1441 public:
1442 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
1443 virtual const char* getName() const { return fName; }
1444 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
1445 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
1446 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1447 virtual uint64_t getSize() const { return 0; }
1448 virtual const char* getSectionName() const { return "._imports"; }
1449 private:
1450 using WriterAtom<A>::fWriter;
1451 typedef typename A::P P;
1452 const char* fName;
1453 };
1454
1455 template <typename A>
1456 class BranchIslandAtom : public WriterAtom<A>
1457 {
1458 public:
1459 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
1460 virtual const char* getName() const { return fName; }
1461 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1462 virtual uint64_t getSize() const;
1463 virtual const char* getSectionName() const { return "__text"; }
1464 virtual void copyRawContent(uint8_t buffer[]) const;
1465 private:
1466 using WriterAtom<A>::fWriter;
1467 const char* fName;
1468 ObjectFile::Atom& fTarget;
1469 uint32_t fTargetOffset;
1470 };
1471
1472 template <typename A>
1473 class StubAtom : public WriterAtom<A>
1474 {
1475 public:
1476 StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
1477 virtual const char* getName() const { return fName; }
1478 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1479 virtual uint64_t getSize() const;
1480 virtual ObjectFile::Alignment getAlignment() const;
1481 virtual const char* getSectionName() const { return "__symbol_stub1"; }
1482 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1483 virtual void copyRawContent(uint8_t buffer[]) const;
1484 ObjectFile::Atom* getTarget() { return &fTarget; }
1485 private:
1486 static const char* stubName(const char* importName);
1487 bool pic() const { return fWriter.fSlideable; }
1488 using WriterAtom<A>::fWriter;
1489 const char* fName;
1490 ObjectFile::Atom& fTarget;
1491 std::vector<ObjectFile::Reference*> fReferences;
1492 bool fForLazyDylib;
1493 };
1494
1495
1496 template <typename A>
1497 class FastStubHelperHelperAtom : public WriterAtom<A>
1498 {
1499 public:
1500 FastStubHelperHelperAtom(Writer<A>& writer);
1501 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1502 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1503 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1504 virtual uint64_t getSize() const;
1505 virtual const char* getSectionName() const { return "__stub_helper"; }
1506 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1507 virtual void copyRawContent(uint8_t buffer[]) const;
1508 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1509 protected:
1510 using WriterAtom<A>::fWriter;
1511 std::vector<ObjectFile::Reference*> fReferences;
1512 };
1513
1514 template <typename A>
1515 class HybridStubHelperHelperAtom : public WriterAtom<A>
1516 {
1517 public:
1518 HybridStubHelperHelperAtom(Writer<A>& writer);
1519 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1520 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1521 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1522 virtual uint64_t getSize() const;
1523 virtual const char* getSectionName() const { return "__stub_helper"; }
1524 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1525 virtual void copyRawContent(uint8_t buffer[]) const;
1526 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1527 protected:
1528 using WriterAtom<A>::fWriter;
1529 std::vector<ObjectFile::Reference*> fReferences;
1530 };
1531
1532 template <typename A>
1533 class StubHelperAtom : public WriterAtom<A>
1534 {
1535 public:
1536 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1537 LazyPointerAtom<A>& lazyPointer, bool forLazyDylib)
1538 : WriterAtom<A>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1539 fTarget(target), fLazyPointerAtom(lazyPointer) {
1540 writer.fAllSynthesizedStubHelpers.push_back(this);
1541 }
1542
1543 virtual const char* getName() const { return fName; }
1544 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1545 virtual const char* getSectionName() const { return "__stub_helper"; }
1546 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1547 ObjectFile::Atom* getTarget() { return &fTarget; }
1548 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1549 protected:
1550 static const char* stubName(const char* importName);
1551 using WriterAtom<A>::fWriter;
1552 const char* fName;
1553 ObjectFile::Atom& fTarget;
1554 LazyPointerAtom<A>& fLazyPointerAtom;
1555 std::vector<ObjectFile::Reference*> fReferences;
1556 };
1557
1558 template <typename A>
1559 class ClassicStubHelperAtom : public StubHelperAtom<A>
1560 {
1561 public:
1562 ClassicStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1563 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1564
1565 virtual uint64_t getSize() const;
1566 virtual void copyRawContent(uint8_t buffer[]) const;
1567 };
1568
1569
1570 template <typename A>
1571 class HybridStubHelperAtom : public StubHelperAtom<A>
1572 {
1573 public:
1574 HybridStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1575 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1576
1577 virtual uint64_t getSize() const;
1578 virtual void copyRawContent(uint8_t buffer[]) const;
1579 static class HybridStubHelperHelperAtom<A>* fgHelperHelperAtom;
1580 };
1581 template <typename A> class HybridStubHelperHelperAtom<A>* HybridStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1582
1583 template <typename A>
1584 class FastStubHelperAtom : public StubHelperAtom<A>
1585 {
1586 public:
1587 FastStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1588 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1589 virtual uint64_t getSize() const;
1590 virtual void copyRawContent(uint8_t buffer[]) const;
1591 static FastStubHelperHelperAtom<A>* fgHelperHelperAtom;
1592 };
1593 template <typename A> FastStubHelperHelperAtom<A>* FastStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1594
1595
1596
1597 template <typename A>
1598 class LazyPointerAtom : public WriterAtom<A>
1599 {
1600 public:
1601 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target,
1602 StubAtom<A>& stub, bool forLazyDylib);
1603 virtual const char* getName() const { return fName; }
1604 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1605 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1606 virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; }
1607 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1608 virtual void copyRawContent(uint8_t buffer[]) const;
1609 ObjectFile::Atom* getTarget() { return &fExternalTarget; }
1610 void setLazyBindingInfoOffset(uint32_t off) { fLazyBindingOffset = off; }
1611 uint32_t getLazyBindingInfoOffset() { return fLazyBindingOffset; }
1612 private:
1613 using WriterAtom<A>::fWriter;
1614 static const char* lazyPointerName(const char* importName);
1615 const char* fName;
1616 ObjectFile::Atom& fTarget;
1617 ObjectFile::Atom& fExternalTarget;
1618 std::vector<ObjectFile::Reference*> fReferences;
1619 bool fForLazyDylib;
1620 uint32_t fLazyBindingOffset;
1621 };
1622
1623
1624 template <typename A>
1625 class NonLazyPointerAtom : public WriterAtom<A>
1626 {
1627 public:
1628 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1629 NonLazyPointerAtom(Writer<A>& writer, const char* targetName);
1630 NonLazyPointerAtom(Writer<A>& writer);
1631 virtual const char* getName() const { return fName; }
1632 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1633 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1634 virtual const char* getSectionName() const { return (fWriter.fOptions.outputKind() == Options::kKextBundle) ? "__got" : "__nl_symbol_ptr"; }
1635 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1636 virtual void copyRawContent(uint8_t buffer[]) const;
1637 ObjectFile::Atom* getTarget() { return fTarget; }
1638 private:
1639 using WriterAtom<A>::fWriter;
1640 static const char* nonlazyPointerName(const char* importName);
1641 const char* fName;
1642 ObjectFile::Atom* fTarget;
1643 std::vector<ObjectFile::Reference*> fReferences;
1644 };
1645
1646
1647 template <typename A>
1648 class ObjCInfoAtom : public WriterAtom<A>
1649 {
1650 public:
1651 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1652 bool objcReplacementClasses);
1653 virtual const char* getName() const { return "objc$info"; }
1654 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1655 virtual uint64_t getSize() const { return 8; }
1656 virtual const char* getSectionName() const;
1657 virtual void copyRawContent(uint8_t buffer[]) const;
1658 private:
1659 Segment& getInfoSegment() const;
1660 uint32_t fContent[2];
1661 };
1662
1663
1664 template <typename A>
1665 class WriterReference : public ObjectFile::Reference
1666 {
1667 public:
1668 typedef typename A::ReferenceKinds Kinds;
1669
1670 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1671 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1672 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target), fTargetName(target->getName()),
1673 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1674 WriterReference(uint32_t offset, Kinds kind, const char* targetName)
1675 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(NULL), fTargetName(targetName),
1676 fTargetOffset(0), fFromTarget(NULL), fFromTargetOffset(0) {}
1677
1678 virtual ~WriterReference() {}
1679
1680 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return (fTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kUnboundByName; }
1681 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1682 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1683 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1684 virtual const char* getTargetName() const { return fTargetName; }
1685 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1686 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1687 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1688 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1689 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = &target; fTargetOffset = offset; }
1690 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = &target; }
1691 virtual void setFromTargetName(const char* name) { }
1692 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1693 virtual const char* getDescription() const { return "writer reference"; }
1694 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1695
1696 private:
1697 Kinds fKind;
1698 uint32_t fFixUpOffsetInSrc;
1699 ObjectFile::Atom* fTarget;
1700 const char* fTargetName;
1701 uint32_t fTargetOffset;
1702 ObjectFile::Atom* fFromTarget;
1703 uint32_t fFromTargetOffset;
1704 };
1705
1706
1707 template <typename A>
1708 const char* StubHelperAtom<A>::stubName(const char* name)
1709 {
1710 char* buf;
1711 asprintf(&buf, "%s$stubHelper", name);
1712 return buf;
1713 }
1714
1715 template <>
1716 ClassicStubHelperAtom<x86_64>::ClassicStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1717 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1718 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1719 {
1720 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &fLazyPointerAtom));
1721 if ( forLazyDylib ) {
1722 if ( fWriter.fDyldLazyDylibHelper == NULL )
1723 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1724 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldLazyDylibHelper));
1725 }
1726 else {
1727 if ( fWriter.fDyldClassicHelperAtom == NULL )
1728 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1729 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldClassicHelperAtom));
1730 }
1731 }
1732
1733
1734 template <>
1735 uint64_t ClassicStubHelperAtom<x86_64>::getSize() const
1736 {
1737 return 12;
1738 }
1739
1740 template <>
1741 void ClassicStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1742 {
1743 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1744 buffer[1] = 0x8D;
1745 buffer[2] = 0x1D;
1746 buffer[3] = 0x00;
1747 buffer[4] = 0x00;
1748 buffer[5] = 0x00;
1749 buffer[6] = 0x00;
1750 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1751 buffer[8] = 0x00;
1752 buffer[9] = 0x00;
1753 buffer[10] = 0x00;
1754 buffer[11] = 0x00;
1755 }
1756
1757
1758 template <>
1759 FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(Writer<x86_64>& writer)
1760 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1761 {
1762 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1763 fReferences.push_back(new WriterReference<x86_64>(11, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1764 }
1765
1766 template <>
1767 uint64_t FastStubHelperHelperAtom<x86_64>::getSize() const
1768 {
1769 return 16;
1770 }
1771
1772 template <>
1773 void FastStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1774 {
1775 buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
1776 buffer[1] = 0x8D;
1777 buffer[2] = 0x1D;
1778 buffer[3] = 0x00;
1779 buffer[4] = 0x00;
1780 buffer[5] = 0x00;
1781 buffer[6] = 0x00;
1782 buffer[7] = 0x41; // pushq %r11
1783 buffer[8] = 0x53;
1784 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1785 buffer[10] = 0x25;
1786 buffer[11] = 0x00;
1787 buffer[12] = 0x00;
1788 buffer[13] = 0x00;
1789 buffer[14] = 0x00;
1790 buffer[15] = 0x90; // nop
1791 }
1792
1793
1794 template <>
1795 HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(Writer<x86_64>& writer)
1796 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1797 {
1798 if ( writer.fDyldClassicHelperAtom == NULL )
1799 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1800 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32_1, writer.fFastStubGOTAtom));
1801 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1802 fReferences.push_back(new WriterReference<x86_64>(21, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1803 fReferences.push_back(new WriterReference<x86_64>(30, x86_64::kPCRel32, writer.fDyldClassicHelperAtom));
1804 }
1805
1806 template <>
1807 uint64_t HybridStubHelperHelperAtom<x86_64>::getSize() const
1808 {
1809 return 34;
1810 }
1811
1812 template <>
1813 void HybridStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1814 {
1815 buffer[0] = 0x48; // cmpl $0x00,_fast_lazy_bind
1816 buffer[1] = 0x83;
1817 buffer[2] = 0x3D;
1818 buffer[3] = 0x00;
1819 buffer[4] = 0x00;
1820 buffer[5] = 0x00;
1821 buffer[6] = 0x00;
1822 buffer[7] = 0x00;
1823 buffer[8] = 0x74; // je 16
1824 buffer[9] = 0x0F;
1825 buffer[10] = 0x4C; // leaq imageCache(%rip),%r11
1826 buffer[11] = 0x8D;
1827 buffer[12] = 0x1D;
1828 buffer[13] = 0x00;
1829 buffer[14] = 0x00;
1830 buffer[15] = 0x00;
1831 buffer[16] = 0x00;
1832 buffer[17] = 0x41; // pushq %r11
1833 buffer[18] = 0x53;
1834 buffer[19] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1835 buffer[20] = 0x25;
1836 buffer[21] = 0x00;
1837 buffer[22] = 0x00;
1838 buffer[23] = 0x00;
1839 buffer[24] = 0x00;
1840 buffer[25] = 0x48; // addq $8,%rsp
1841 buffer[26] = 0x83;
1842 buffer[27] = 0xC4;
1843 buffer[28] = 0x08;
1844 buffer[29] = 0xE9; // jmp dyld_stub_binding_helper
1845 buffer[30] = 0x00;
1846 buffer[31] = 0x00;
1847 buffer[32] = 0x00;
1848 buffer[33] = 0x00;
1849 }
1850
1851
1852 template <>
1853 HybridStubHelperAtom<x86_64>::HybridStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1854 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1855 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1856 {
1857 if ( fgHelperHelperAtom == NULL ) {
1858 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(fWriter);
1859 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1860 }
1861 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, &fLazyPointerAtom));
1862 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, fgHelperHelperAtom));
1863 }
1864
1865 template <>
1866 uint64_t HybridStubHelperAtom<x86_64>::getSize() const
1867 {
1868 return 18;
1869 }
1870
1871 template <>
1872 void HybridStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1873 {
1874 buffer[0] = 0x68; // pushq $lazy-info-offset
1875 buffer[1] = 0x00;
1876 buffer[2] = 0x00;
1877 buffer[3] = 0x00;
1878 buffer[4] = 0x00;
1879 buffer[5] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1880 buffer[6] = 0x8D;
1881 buffer[7] = 0x1D;
1882 buffer[8] = 0x00;
1883 buffer[9] = 0x00;
1884 buffer[10] = 0x00;
1885 buffer[11] = 0x00;
1886 buffer[12] = 0xE9; // jmp helper-helper
1887 buffer[13] = 0x00;
1888 buffer[14] = 0x00;
1889 buffer[15] = 0x00;
1890 buffer[16] = 0x00;
1891 buffer[17] = 0x90; // nop
1892
1893 // the lazy binding info is created later than this helper atom, so there
1894 // is no Reference to update. Instead we blast the offset here.
1895 uint32_t offset;
1896 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1897 memcpy(&buffer[1], &offset, 4);
1898 }
1899
1900 template <>
1901 FastStubHelperAtom<x86_64>::FastStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1902 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1903 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1904 {
1905 if ( fgHelperHelperAtom == NULL ) {
1906 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(fWriter);
1907 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1908 }
1909 fReferences.push_back(new WriterReference<x86_64>(6, x86_64::kPCRel32, fgHelperHelperAtom));
1910 }
1911
1912 template <>
1913 uint64_t FastStubHelperAtom<x86_64>::getSize() const
1914 {
1915 return 10;
1916 }
1917
1918 template <>
1919 void FastStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1920 {
1921 buffer[0] = 0x68; // pushq $lazy-info-offset
1922 buffer[1] = 0x00;
1923 buffer[2] = 0x00;
1924 buffer[3] = 0x00;
1925 buffer[4] = 0x00;
1926 buffer[5] = 0xE9; // jmp helperhelper
1927 buffer[6] = 0x00;
1928 buffer[7] = 0x00;
1929 buffer[8] = 0x00;
1930 buffer[9] = 0x00;
1931
1932 // the lazy binding info is created later than this helper atom, so there
1933 // is no Reference to update. Instead we blast the offset here.
1934 uint32_t offset;
1935 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1936 memcpy(&buffer[1], &offset, 4);
1937 }
1938
1939 template <>
1940 FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(Writer<x86>& writer)
1941 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1942 {
1943 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1944 fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, writer.fFastStubGOTAtom));
1945 }
1946
1947 template <>
1948 uint64_t FastStubHelperHelperAtom<x86>::getSize() const
1949 {
1950 return 12;
1951 }
1952
1953 template <>
1954 void FastStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1955 {
1956 buffer[0] = 0x68; // pushl $dyld_ImageLoaderCache
1957 buffer[1] = 0x00;
1958 buffer[2] = 0x00;
1959 buffer[3] = 0x00;
1960 buffer[4] = 0x00;
1961 buffer[5] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1962 buffer[6] = 0x25;
1963 buffer[7] = 0x00;
1964 buffer[8] = 0x00;
1965 buffer[9] = 0x00;
1966 buffer[10] = 0x00;
1967 buffer[11] = 0x90; // nop
1968 }
1969
1970
1971 template <>
1972 HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(Writer<x86>& writer)
1973 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1974 {
1975 if ( writer.fDyldClassicHelperAtom == NULL )
1976 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1977 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, writer.fFastStubGOTAtom));
1978 fReferences.push_back(new WriterReference<x86>(18, x86::kPCRel32, writer.fDyldClassicHelperAtom));
1979 fReferences.push_back(new WriterReference<x86>(26, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1980 fReferences.push_back(new WriterReference<x86>(32, x86::kAbsolute32, writer.fFastStubGOTAtom));
1981 }
1982
1983 template <>
1984 uint64_t HybridStubHelperHelperAtom<x86>::getSize() const
1985 {
1986 return 36;
1987 }
1988
1989
1990 template <>
1991 void HybridStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1992 {
1993 buffer[0] = 0x83; // cmpl $0x00,_fast_lazy_bind
1994 buffer[1] = 0x3D;
1995 buffer[2] = 0x00;
1996 buffer[3] = 0x00;
1997 buffer[4] = 0x00;
1998 buffer[5] = 0x00;
1999 buffer[6] = 0x00;
2000 buffer[7] = 0x75; // jne 22
2001 buffer[8] = 0x0D;
2002 buffer[9] = 0x89; // %eax,4(%esp)
2003 buffer[10] = 0x44;
2004 buffer[11] = 0x24;
2005 buffer[12] = 0x04;
2006 buffer[13] = 0x58; // popl %eax
2007 buffer[14] = 0x87; // xchgl (%esp),%eax
2008 buffer[15] = 0x04;
2009 buffer[16] = 0x24;
2010 buffer[17] = 0xE9; // jmpl dyld_stub_binding_helper
2011 buffer[18] = 0x00;
2012 buffer[19] = 0x00;
2013 buffer[20] = 0x00;
2014 buffer[21] = 0x00;
2015 buffer[22] = 0x83; // addl $0x04,%esp
2016 buffer[23] = 0xC4;
2017 buffer[24] = 0x04;
2018 buffer[25] = 0x68; // pushl imageloadercahce
2019 buffer[26] = 0x00;
2020 buffer[27] = 0x00;
2021 buffer[28] = 0x00;
2022 buffer[29] = 0x00;
2023 buffer[30] = 0xFF; // jmp *_fast_lazy_bind(%rip)
2024 buffer[31] = 0x25;
2025 buffer[32] = 0x00;
2026 buffer[33] = 0x00;
2027 buffer[34] = 0x00;
2028 buffer[35] = 0x00;
2029 }
2030
2031
2032 template <>
2033 ClassicStubHelperAtom<x86>::ClassicStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2034 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2035 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2036 {
2037 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, &fLazyPointerAtom));
2038 if ( forLazyDylib ) {
2039 if ( fWriter.fDyldLazyDylibHelper == NULL )
2040 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2041 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldLazyDylibHelper));
2042 }
2043 else {
2044 if ( fWriter.fDyldClassicHelperAtom == NULL )
2045 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2046 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldClassicHelperAtom));
2047 }
2048 }
2049
2050 template <>
2051 uint64_t ClassicStubHelperAtom<x86>::getSize() const
2052 {
2053 return 10;
2054 }
2055
2056 template <>
2057 void ClassicStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2058 {
2059 buffer[0] = 0x68; // pushl $foo$lazy_ptr
2060 buffer[1] = 0x00;
2061 buffer[2] = 0x00;
2062 buffer[3] = 0x00;
2063 buffer[4] = 0x00;
2064 buffer[5] = 0xE9; // jmp helperhelper
2065 buffer[6] = 0x00;
2066 buffer[7] = 0x00;
2067 buffer[8] = 0x00;
2068 buffer[9] = 0x00;
2069 }
2070
2071 template <>
2072 HybridStubHelperAtom<x86>::HybridStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2073 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2074 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2075 {
2076 if ( fgHelperHelperAtom == NULL ) {
2077 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(fWriter);
2078 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2079 }
2080 fReferences.push_back(new WriterReference<x86>(6, x86::kAbsolute32, &fLazyPointerAtom));
2081 fReferences.push_back(new WriterReference<x86>(11, x86::kPCRel32, fgHelperHelperAtom));
2082 }
2083
2084
2085 template <>
2086 uint64_t HybridStubHelperAtom<x86>::getSize() const
2087 {
2088 return 16;
2089 }
2090
2091 template <>
2092 void HybridStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2093 {
2094 buffer[0] = 0x68; // pushl $lazy-info-offset
2095 buffer[1] = 0x00;
2096 buffer[2] = 0x00;
2097 buffer[3] = 0x00;
2098 buffer[4] = 0x00;
2099 buffer[5] = 0x68; // pushl $foo$lazy_ptr
2100 buffer[6] = 0x00;
2101 buffer[7] = 0x00;
2102 buffer[8] = 0x00;
2103 buffer[9] = 0x00;
2104 buffer[10] = 0xE9; // jmp dyld_hybrid_stub_binding_helper
2105 buffer[11] = 0x00;
2106 buffer[12] = 0x00;
2107 buffer[13] = 0x00;
2108 buffer[14] = 0x00;
2109 buffer[15] = 0x90; // nop
2110
2111 // the lazy binding info is created later than this helper atom, so there
2112 // is no Reference to update. Instead we blast the offset here.
2113 uint32_t offset;
2114 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2115 memcpy(&buffer[1], &offset, 4);
2116 }
2117
2118
2119 template <>
2120 FastStubHelperAtom<x86>::FastStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2121 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2122 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2123 {
2124 if ( fgHelperHelperAtom == NULL ) {
2125 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(fWriter);
2126 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2127 }
2128 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fgHelperHelperAtom));
2129 }
2130
2131
2132 template <>
2133 uint64_t FastStubHelperAtom<x86>::getSize() const
2134 {
2135 return 10;
2136 }
2137
2138 template <>
2139 void FastStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2140 {
2141 buffer[0] = 0x68; // pushl $lazy-info-offset
2142 buffer[1] = 0x00;
2143 buffer[2] = 0x00;
2144 buffer[3] = 0x00;
2145 buffer[4] = 0x00;
2146 buffer[5] = 0xE9; // jmp helperhelper
2147 buffer[6] = 0x00;
2148 buffer[7] = 0x00;
2149 buffer[8] = 0x00;
2150 buffer[9] = 0x00;
2151
2152 // the lazy binding info is created later than this helper atom, so there
2153 // is no Reference to update. Instead we blast the offset here.
2154 uint32_t offset;
2155 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2156 memcpy(&buffer[1], &offset, 4);
2157 }
2158
2159
2160
2161 // specialize lazy pointer for x86_64 to initially pointer to stub helper
2162 template <>
2163 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
2164 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2165 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fLazyBindingOffset(0)
2166 {
2167 if ( forLazyDylib )
2168 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2169 else
2170 writer.fAllSynthesizedLazyPointers.push_back(this);
2171
2172 ObjectFile::Atom* helper;
2173 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2174 if ( writer.fOptions.makeClassicDyldInfo() )
2175 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2176 if ( writer.targetRequiresWeakBinding(target) )
2177 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2178 else
2179 helper = new HybridStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2180 else {
2181 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2182 helper = &target;
2183 else
2184 helper = new FastStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2185 }
2186 }
2187 else {
2188 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2189 }
2190 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
2191 }
2192
2193
2194 // specialize lazy pointer for x86 to initially pointer to stub helper
2195 template <>
2196 LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
2197 : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2198 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
2199 {
2200 if ( forLazyDylib )
2201 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2202 else
2203 writer.fAllSynthesizedLazyPointers.push_back(this);
2204
2205 ObjectFile::Atom* helper;
2206 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2207 if ( writer.fOptions.makeClassicDyldInfo() ) {
2208 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2209 if ( writer.targetRequiresWeakBinding(target) )
2210 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2211 else
2212 helper = new HybridStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2213 }
2214 else {
2215 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2216 helper = &target;
2217 else
2218 helper = new FastStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2219 }
2220 }
2221 else {
2222 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2223 }
2224 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, helper));
2225 }
2226
2227 template <typename A>
2228 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
2229 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2230 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
2231 {
2232 if ( forLazyDylib )
2233 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2234 else
2235 writer.fAllSynthesizedLazyPointers.push_back(this);
2236
2237 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2238 }
2239
2240
2241
2242 template <typename A>
2243 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
2244 {
2245 char* buf;
2246 asprintf(&buf, "%s$lazy_pointer", name);
2247 return buf;
2248 }
2249
2250 template <typename A>
2251 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2252 {
2253 bzero(buffer, getSize());
2254 }
2255
2256
2257 template <typename A>
2258 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
2259 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(&target)
2260 {
2261 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2262 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2263 }
2264
2265 template <typename A>
2266 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer)
2267 : WriterAtom<A>(writer, Segment::fgDataSegment), fName("none"), fTarget(NULL)
2268 {
2269 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2270 }
2271
2272 template <typename A>
2273 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, const char* targetName)
2274 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(targetName)), fTarget(NULL)
2275 {
2276 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2277 fReferences.push_back(new WriterReference<A>(0, A::kPointer, targetName));
2278 }
2279
2280 template <typename A>
2281 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
2282 {
2283 char* buf;
2284 asprintf(&buf, "%s$non_lazy_pointer", name);
2285 return buf;
2286 }
2287
2288 template <typename A>
2289 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2290 {
2291 bzero(buffer, getSize());
2292 }
2293
2294
2295
2296 template <>
2297 bool StubAtom<ppc64>::pic() const
2298 {
2299 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
2300 // Usually that only happens if page zero is very large
2301 return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
2302 }
2303
2304
2305 template <>
2306 bool StubAtom<arm>::pic() const
2307 {
2308 return fWriter.fSlideable;
2309 }
2310
2311 template <>
2312 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
2313 {
2314 return 2;
2315 }
2316
2317 template <>
2318 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
2319 {
2320 return 2;
2321 }
2322
2323 template <>
2324 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
2325 {
2326 return 2;
2327 }
2328
2329 template <>
2330 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2331 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2332 fTarget(target), fForLazyDylib(forLazyDylib)
2333 {
2334 writer.fAllSynthesizedStubs.push_back(this);
2335 LazyPointerAtom<ppc>* lp;
2336 if ( fWriter.fOptions.prebind() ) {
2337 // for prebound ppc, lazy pointer starts out pointing to target symbol's address
2338 // if target is a weak definition within this linkage unit or zero if in some dylib
2339 lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
2340 }
2341 else {
2342 // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2343 if ( forLazyDylib ) {
2344 if ( writer.fDyldLazyDylibHelper == NULL )
2345 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2346 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2347 }
2348 else {
2349 if ( writer.fDyldClassicHelperAtom == NULL )
2350 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2351 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2352 }
2353 }
2354 if ( pic() ) {
2355 // picbase is 8 bytes into atom
2356 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
2357 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
2358 }
2359 else {
2360 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
2361 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
2362 }
2363 }
2364
2365 template <>
2366 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2367 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2368 fTarget(target), fForLazyDylib(forLazyDylib)
2369 {
2370 writer.fAllSynthesizedStubs.push_back(this);
2371
2372 LazyPointerAtom<ppc64>* lp;
2373 if ( forLazyDylib ) {
2374 if ( writer.fDyldLazyDylibHelper == NULL )
2375 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2376 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2377 }
2378 else {
2379 if ( writer.fDyldClassicHelperAtom == NULL )
2380 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2381 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2382 }
2383 if ( pic() ) {
2384 // picbase is 8 bytes into atom
2385 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
2386 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
2387 }
2388 else {
2389 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
2390 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
2391 }
2392 }
2393
2394 template <>
2395 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2396 : WriterAtom<x86>(writer, (writer.fOptions.makeCompressedDyldInfo()|| forLazyDylib) ? Segment::fgTextSegment : Segment::fgImportSegment),
2397 fName(NULL), fTarget(target), fForLazyDylib(forLazyDylib)
2398 {
2399 if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) {
2400 fName = stubName(target.getName());
2401 LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
2402 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
2403 writer.fAllSynthesizedStubs.push_back(this);
2404 }
2405 else {
2406 if ( &target == NULL )
2407 fName = "cache-line-crossing-stub";
2408 else {
2409 fName = stubName(target.getName());
2410 writer.fAllSynthesizedStubs.push_back(this);
2411 }
2412 }
2413 }
2414
2415
2416 template <>
2417 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2418 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2419 {
2420 writer.fAllSynthesizedStubs.push_back(this);
2421
2422 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
2423 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
2424 }
2425
2426 template <>
2427 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2428 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2429 {
2430 writer.fAllSynthesizedStubs.push_back(this);
2431
2432 LazyPointerAtom<arm>* lp;
2433 if ( fWriter.fOptions.prebind() && !forLazyDylib ) {
2434 // for prebound arm, lazy pointer starts out pointing to target symbol's address
2435 // if target is a weak definition within this linkage unit or zero if in some dylib
2436 lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
2437 }
2438 else {
2439 // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2440 ObjectFile::Atom* helper;
2441 if ( forLazyDylib ) {
2442 if ( writer.fDyldLazyDylibHelper == NULL )
2443 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2444 helper = writer.fDyldLazyDylibHelper;
2445 }
2446 else {
2447 if ( writer.fDyldClassicHelperAtom == NULL )
2448 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2449 helper = writer.fDyldClassicHelperAtom;
2450 }
2451 lp = new LazyPointerAtom<arm>(writer, *helper, *this, forLazyDylib);
2452 }
2453 if ( pic() )
2454 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
2455 else
2456 fReferences.push_back(new WriterReference<arm>(8, arm::kPointer, lp));
2457 }
2458
2459 template <typename A>
2460 const char* StubAtom<A>::stubName(const char* name)
2461 {
2462 char* buf;
2463 asprintf(&buf, "%s$stub", name);
2464 return buf;
2465 }
2466
2467 template <>
2468 uint64_t StubAtom<ppc>::getSize() const
2469 {
2470 return ( pic() ? 32 : 16 );
2471 }
2472
2473 template <>
2474 uint64_t StubAtom<ppc64>::getSize() const
2475 {
2476 return ( pic() ? 32 : 16 );
2477 }
2478
2479
2480 template <>
2481 uint64_t StubAtom<arm>::getSize() const
2482 {
2483 return ( pic() ? 16 : 12 );
2484 }
2485
2486 template <>
2487 uint64_t StubAtom<x86>::getSize() const
2488 {
2489 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2490 return 6;
2491 else
2492 return 5;
2493 }
2494
2495 template <>
2496 uint64_t StubAtom<x86_64>::getSize() const
2497 {
2498 return 6;
2499 }
2500
2501 template <>
2502 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
2503 {
2504 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2505 return 1;
2506 else
2507 return 0; // special case x86 self-modifying stubs to be byte aligned
2508 }
2509
2510 template <>
2511 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
2512 {
2513 if ( pic() ) {
2514 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
2515 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2516 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2517 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2518 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2519 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2520 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2521 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2522 }
2523 else {
2524 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2525 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
2526 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2527 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2528 }
2529 }
2530
2531 template <>
2532 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
2533 {
2534 if ( pic() ) {
2535 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
2536 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2537 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2538 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2539 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2540 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2541 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2542 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2543 }
2544 else {
2545 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2546 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
2547 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2548 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2549 }
2550 }
2551
2552 template <>
2553 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
2554 {
2555 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) {
2556 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
2557 buffer[1] = 0x25;
2558 buffer[2] = 0x00;
2559 buffer[3] = 0x00;
2560 buffer[4] = 0x00;
2561 buffer[5] = 0x00;
2562 }
2563 else {
2564 if ( fWriter.fOptions.prebind() ) {
2565 uint32_t address = this->getAddress();
2566 int32_t rel32 = 0 - (address+5);
2567 buffer[0] = 0xE9;
2568 buffer[1] = rel32 & 0xFF;
2569 buffer[2] = (rel32 >> 8) & 0xFF;
2570 buffer[3] = (rel32 >> 16) & 0xFF;
2571 buffer[4] = (rel32 >> 24) & 0xFF;
2572 }
2573 else {
2574 buffer[0] = 0xF4;
2575 buffer[1] = 0xF4;
2576 buffer[2] = 0xF4;
2577 buffer[3] = 0xF4;
2578 buffer[4] = 0xF4;
2579 }
2580 }
2581 }
2582
2583 template <>
2584 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
2585 {
2586 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
2587 buffer[1] = 0x25;
2588 buffer[2] = 0x00;
2589 buffer[3] = 0x00;
2590 buffer[4] = 0x00;
2591 buffer[5] = 0x00;
2592 }
2593
2594 template <>
2595 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
2596 {
2597 if ( pic() ) {
2598 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
2599 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
2600 OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
2601 OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
2602 }
2603 else {
2604 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
2605 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
2606 OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
2607 }
2608 }
2609
2610 // x86_64 stubs are 6 bytes
2611 template <>
2612 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
2613 {
2614 return 1;
2615 }
2616
2617 template <>
2618 const char* StubAtom<ppc>::getSectionName() const
2619 {
2620 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
2621 }
2622
2623 template <>
2624 const char* StubAtom<ppc64>::getSectionName() const
2625 {
2626 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
2627 }
2628
2629 template <>
2630 const char* StubAtom<arm>::getSectionName() const
2631 {
2632 return ( pic() ? "__picsymbolstub4" : "__symbol_stub4");
2633 }
2634
2635 template <>
2636 const char* StubAtom<x86>::getSectionName() const
2637 {
2638 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2639 return "__symbol_stub";
2640 else
2641 return "__jump_table";
2642 }
2643
2644
2645
2646
2647 struct AtomByNameSorter
2648 {
2649 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2650 {
2651 return (strcmp(left->getName(), right->getName()) < 0);
2652 }
2653 };
2654
2655 template <typename P>
2656 struct ExternalRelocSorter
2657 {
2658 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
2659 {
2660 // sort first by symbol number
2661 if ( left.r_symbolnum() != right.r_symbolnum() )
2662 return (left.r_symbolnum() < right.r_symbolnum());
2663 // then sort all uses of the same symbol by address
2664 return (left.r_address() < right.r_address());
2665 }
2666 };
2667
2668
2669 template <typename A>
2670 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
2671 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
2672 fAllAtoms(NULL), fStabs(NULL), fRegularDefAtomsThatOverrideADylibsWeakDef(NULL), fLoadCommandsSection(NULL),
2673 fLoadCommandsSegment(NULL), fMachHeaderAtom(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
2674 fSymbolTableCommands(NULL), fHeaderPadding(NULL), fUnwindInfoAtom(NULL),
2675 fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL),
2676 fDyldClassicHelperAtom(NULL), fDyldCompressedHelperAtom(NULL), fDyldLazyDylibHelper(NULL),
2677 fSectionRelocationsAtom(NULL), fCompressedRebaseInfoAtom(NULL), fCompressedBindingInfoAtom(NULL),
2678 fCompressedWeakBindingInfoAtom(NULL), fCompressedLazyBindingInfoAtom(NULL), fCompressedExportInfoAtom(NULL),
2679 fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
2680 fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
2681 fStringsAtom(NULL), fPageZeroAtom(NULL), fFastStubGOTAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0),
2682 fSymbolTableStabsCount(0), fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
2683 fLargestAtomSize(1),
2684 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
2685 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
2686 fBiggerThanTwoGigs(false), fSlideable(false),
2687 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
2688 {
2689 switch ( fOptions.outputKind() ) {
2690 case Options::kDynamicExecutable:
2691 case Options::kStaticExecutable:
2692 if ( fOptions.zeroPageSize() != 0 )
2693 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
2694 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2695 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2696 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2697 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2698 if ( fOptions.makeCompressedDyldInfo() )
2699 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2700 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2701 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2702 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2703 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2704 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2705 if ( fOptions.hasCustomStack() )
2706 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
2707 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2708 if ( fOptions.needsUnwindInfoSection() )
2709 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2710 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2711 if ( fOptions.makeCompressedDyldInfo() ) {
2712 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2713 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2714 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2715 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2716 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2717 }
2718 if ( fOptions.makeClassicDyldInfo() )
2719 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2720 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2721 if ( fOptions.makeClassicDyldInfo() )
2722 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2723 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2724 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2725 break;
2726 case Options::kPreload:
2727 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2728 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2729 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2730 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2731 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2732 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2733 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2734 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2735 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2736 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2737 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2738 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2739 break;
2740 case Options::kDynamicLibrary:
2741 case Options::kDynamicBundle:
2742 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2743 case Options::kKextBundle:
2744 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2745 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2746 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
2747 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
2748 if ( fOptions.initFunctionName() != NULL )
2749 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
2750 }
2751 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2752 if ( fOptions.makeCompressedDyldInfo() )
2753 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2754 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2755 if ( fOptions.sharedRegionEligible() )
2756 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
2757 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2758 if ( fOptions.needsUnwindInfoSection() )
2759 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2760 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2761 if ( fOptions.makeCompressedDyldInfo() ) {
2762 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2763 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2764 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2765 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2766 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2767 }
2768 if ( fOptions.makeClassicDyldInfo() )
2769 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2770 if ( fOptions.sharedRegionEligible() ) {
2771 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
2772 }
2773 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2774 if ( fOptions.makeClassicDyldInfo() )
2775 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2776 if ( fOptions.outputKind() != Options::kKextBundle )
2777 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2778 if ( this->needsModuleTable() )
2779 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
2780 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2781 break;
2782 case Options::kObjectFile:
2783 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2784 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2785 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2786 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2787 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2788 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2789 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2790 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2791 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2792 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2793 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2794 break;
2795 case Options::kDyld:
2796 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2797 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2798 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2799 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2800 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2801 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2802 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2803 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2804 if ( fOptions.needsUnwindInfoSection() )
2805 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2806 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2807 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2808 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2809 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2810 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2811 break;
2812 }
2813
2814 // add extra commmands
2815 bool hasReExports = false;
2816 uint32_t ordinal = 1;
2817 switch ( fOptions.outputKind() ) {
2818 case Options::kDynamicExecutable:
2819 if ( fOptions.makeEncryptable() ) {
2820 fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
2821 fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
2822 }
2823 // fall through
2824 case Options::kDynamicLibrary:
2825 case Options::kDynamicBundle:
2826 {
2827 // add dylib load command atoms for all dynamic libraries
2828 const unsigned int libCount = dynamicLibraries.size();
2829 for (unsigned int i=0; i < libCount; ++i) {
2830 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
2831 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
2832
2833 if ( dylibInfo.options.fReExport ) {
2834 hasReExports = true;
2835 }
2836 else {
2837 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
2838 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
2839 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
2840 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
2841 hasReExports = true;
2842 }
2843 }
2844
2845 if ( dylibInfo.options.fWeakImport ) {
2846 fForcedWeakImportReaders.insert(dylibInfo.reader);
2847 }
2848
2849 if ( dylibInfo.options.fBundleLoader ) {
2850 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
2851 }
2852 else {
2853 // see if a DylibLoadCommandsAtom has already been created for this install path
2854 bool newDylib = true;
2855 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
2856 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
2857 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
2858 if ( !seenDylibInfo.options.fBundleLoader ) {
2859 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
2860 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
2861 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
2862 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
2863 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
2864 newDylib = false;
2865 break;
2866 }
2867 }
2868 }
2869
2870 if ( newDylib ) {
2871 // assign new ordinal and check for other paired load commands
2872 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
2873 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
2874 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
2875 fWriterSynthesizedAtoms.push_back(dyliblc);
2876 if ( dylibInfo.options.fReExport
2877 && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
2878 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
2879 // see if child has sub-framework that is this
2880 bool isSubFramework = false;
2881 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
2882 if ( childInUmbrella != NULL ) {
2883 const char* myLeaf = strrchr(fOptions.installPath(), '/');
2884 if ( myLeaf != NULL ) {
2885 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
2886 isSubFramework = true;
2887 }
2888 }
2889 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
2890 if ( ! isSubFramework ) {
2891 // this dylib also needs a sub_x load command
2892 bool isFrameworkReExport = false;
2893 const char* lastSlash = strrchr(dylibInstallPath, '/');
2894 if ( lastSlash != NULL ) {
2895 char frameworkName[strlen(lastSlash)+20];
2896 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
2897 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
2898 }
2899 if ( isFrameworkReExport ) {
2900 // needs a LC_SUB_UMBRELLA command
2901 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
2902 }
2903 else {
2904 // needs a LC_SUB_LIBRARY command
2905 const char* nameStart = &lastSlash[1];
2906 if ( lastSlash == NULL )
2907 nameStart = dylibInstallPath;
2908 int len = strlen(nameStart);
2909 const char* dot = strchr(nameStart, '.');
2910 if ( dot != NULL )
2911 len = dot - nameStart;
2912 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
2913 }
2914 }
2915 }
2916 }
2917 }
2918 }
2919 // add umbrella command if needed
2920 if ( fOptions.umbrellaName() != NULL ) {
2921 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
2922 }
2923 // add allowable client commands if used
2924 std::vector<const char*>& allowableClients = fOptions.allowableClients();
2925 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
2926 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
2927 }
2928 break;
2929 case Options::kStaticExecutable:
2930 case Options::kObjectFile:
2931 case Options::kDyld:
2932 case Options::kPreload:
2933 case Options::kKextBundle:
2934 break;
2935 }
2936 fNoReExportedDylibs = !hasReExports;
2937
2938 // add any rpath load commands
2939 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
2940 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
2941 }
2942
2943 // set up fSlideable
2944 switch ( fOptions.outputKind() ) {
2945 case Options::kObjectFile:
2946 case Options::kStaticExecutable:
2947 fSlideable = false;
2948 break;
2949 case Options::kDynamicExecutable:
2950 fSlideable = fOptions.positionIndependentExecutable();
2951 break;
2952 case Options::kDyld:
2953 case Options::kDynamicLibrary:
2954 case Options::kDynamicBundle:
2955 case Options::kPreload:
2956 case Options::kKextBundle:
2957 fSlideable = true;
2958 break;
2959 }
2960
2961 //fprintf(stderr, "ordinals table:\n");
2962 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
2963 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
2964 //}
2965 }
2966
2967 template <typename A>
2968 Writer<A>::~Writer()
2969 {
2970 if ( fFilePath != NULL )
2971 free((void*)fFilePath);
2972 if ( fSymbolTable != NULL )
2973 delete [] fSymbolTable;
2974 }
2975
2976
2977 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
2978 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
2979 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
2980
2981
2982 template <typename A>
2983 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
2984 {
2985 if ( fOptions.outputKind() == Options::kKextBundle ) {
2986 return new UndefinedSymbolProxyAtom<A>(*this, name);
2987 }
2988 else if ( fOptions.outputKind() == Options::kObjectFile ) {
2989 // when doing -r -exported_symbols_list, don't create proxy for a symbol
2990 // that is supposed to be exported. We want an error instead
2991 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
2992 if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) )
2993 return NULL;
2994 else
2995 return new UndefinedSymbolProxyAtom<A>(*this, name);
2996 }
2997 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
2998 return new UndefinedSymbolProxyAtom<A>(*this, name);
2999 else
3000 return NULL;
3001 }
3002
3003 template <typename A>
3004 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
3005 {
3006 // flat namespace images use zero for all ordinals
3007 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3008 return 0;
3009
3010 // is an UndefinedSymbolProxyAtom
3011 if ( lib == this )
3012 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3013 return DYNAMIC_LOOKUP_ORDINAL;
3014
3015 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
3016 if ( pos != fLibraryToOrdinal.end() )
3017 return pos->second;
3018
3019 throw "can't find ordinal for imported symbol";
3020 }
3021
3022 template <typename A>
3023 bool Writer<A>::targetRequiresWeakBinding(const ObjectFile::Atom& target)
3024 {
3025 switch ( target.getDefinitionKind() ) {
3026 case ObjectFile::Atom::kExternalWeakDefinition:
3027 case ObjectFile::Atom::kWeakDefinition:
3028 return true;
3029 case ObjectFile::Atom::kExternalDefinition:
3030 case ObjectFile::Atom::kAbsoluteSymbol:
3031 case ObjectFile::Atom::kRegularDefinition:
3032 case ObjectFile::Atom::kTentativeDefinition:
3033 break;
3034 }
3035 return false;
3036 }
3037
3038 template <typename A>
3039 int Writer<A>::compressedOrdinalForImortedAtom(ObjectFile::Atom* target)
3040 {
3041 // flat namespace images use zero for all ordinals
3042 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3043 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3044
3045 // is an UndefinedSymbolProxyAtom
3046 ObjectFile::Reader* lib = target->getFile();
3047 if ( lib == this )
3048 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3049 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3050
3051 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos;
3052 switch ( target->getDefinitionKind() ) {
3053 case ObjectFile::Atom::kExternalDefinition:
3054 case ObjectFile::Atom::kExternalWeakDefinition:
3055 pos = fLibraryToOrdinal.find(lib);
3056 if ( pos != fLibraryToOrdinal.end() ) {
3057 if ( pos->second == EXECUTABLE_ORDINAL )
3058 return BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
3059 else
3060 return pos->second;
3061 }
3062 break;
3063 case ObjectFile::Atom::kWeakDefinition:
3064 throw "compressedOrdinalForImortedAtom() should not have been called on a weak definition";
3065 case ObjectFile::Atom::kAbsoluteSymbol:
3066 case ObjectFile::Atom::kRegularDefinition:
3067 case ObjectFile::Atom::kTentativeDefinition:
3068 return BIND_SPECIAL_DYLIB_SELF;
3069 }
3070
3071 throw "can't find ordinal for imported symbol";
3072 }
3073
3074
3075 template <typename A>
3076 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
3077 {
3078 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
3079 }
3080
3081
3082 template <typename A>
3083 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
3084 std::vector<class ObjectFile::Reader::Stab>& stabs,
3085 class ObjectFile::Atom* entryPointAtom,
3086 class ObjectFile::Atom* dyldClassicHelperAtom,
3087 class ObjectFile::Atom* dyldCompressedHelperAtom,
3088 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
3089 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
3090 bool biggerThanTwoGigs,
3091 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
3092 bool hasExternalWeakDefinitions)
3093 {
3094 fAllAtoms = &atoms;
3095 fStabs = &stabs;
3096 fEntryPoint = entryPointAtom;
3097 fDyldClassicHelperAtom = dyldClassicHelperAtom;
3098 fDyldCompressedHelperAtom = dyldCompressedHelperAtom;
3099 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
3100 fCanScatter = canScatter;
3101 fCpuConstraint = cpuConstraint;
3102 fBiggerThanTwoGigs = biggerThanTwoGigs;
3103 fHasWeakExports = hasExternalWeakDefinitions; // dyld needs to search this image as if it had weak exports
3104 fRegularDefAtomsThatOverrideADylibsWeakDef = &atomsThatOverrideWeak;
3105
3106
3107 try {
3108 // Set for create UUID
3109 if (createUUID)
3110 fUUIDAtom->generate();
3111
3112 // remove uneeded dylib load commands
3113 optimizeDylibReferences();
3114
3115 // check for mdynamic-no-pic codegen
3116 scanForAbsoluteReferences();
3117
3118 // create inter-library stubs
3119 synthesizeStubs();
3120
3121 // create table of unwind info
3122 synthesizeUnwindInfoTable();
3123
3124 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
3125 partitionIntoSections();
3126
3127 // segment load command can now be sized and padding can be set
3128 adjustLoadCommandsAndPadding();
3129
3130 // assign each section a file offset
3131 assignFileOffsets();
3132
3133 // if need to add branch islands, reassign file offsets
3134 if ( addBranchIslands() )
3135 assignFileOffsets();
3136
3137 // now that addresses are assigned, create unwind info
3138 if ( fUnwindInfoAtom != NULL ) {
3139 fUnwindInfoAtom->generate();
3140 // re-layout
3141 adjustLoadCommandsAndPadding();
3142 assignFileOffsets();
3143 }
3144
3145 // make spit-seg info now that all atoms exist
3146 createSplitSegContent();
3147
3148 // build symbol table and relocations
3149 buildLinkEdit();
3150
3151 // write map file if requested
3152 writeMap();
3153
3154 // write everything
3155 return writeAtoms();
3156 } catch (...) {
3157 // clean up if any errors
3158 (void)unlink(fFilePath);
3159 throw;
3160 }
3161 }
3162
3163 template <typename A>
3164 void Writer<A>::buildLinkEdit()
3165 {
3166 this->collectExportedAndImportedAndLocalAtoms();
3167 this->buildSymbolTable();
3168 this->buildFixups();
3169 this->adjustLinkEditSections();
3170 }
3171
3172
3173
3174 template <typename A>
3175 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
3176 {
3177 return atom->getAddress();
3178 // SectionInfo* info = (SectionInfo*)atom->getSection();
3179 // return info->getBaseAddress() + atom->getSectionOffset();
3180 }
3181
3182 template <>
3183 bool Writer<x86_64>::stringsNeedLabelsInObjects()
3184 {
3185 return true;
3186 }
3187
3188 template <typename A>
3189 bool Writer<A>::stringsNeedLabelsInObjects()
3190 {
3191 return false;
3192 }
3193
3194 template <typename A>
3195 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
3196 {
3197 static unsigned int counter = 0;
3198 const char* name;
3199 if ( stringsNeedLabelsInObjects()
3200 && (atom->getContentType() == ObjectFile::Atom::kCStringType)
3201 && (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) )
3202 asprintf((char**)&name, "LC%u", counter++);
3203 else
3204 name = atom->getName();
3205 return name;
3206 return atom->getName();
3207 }
3208
3209 template <typename A>
3210 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3211 {
3212 // set n_strx
3213 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
3214
3215 // set n_type
3216 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
3217 entry->set_n_type(N_EXT | N_ABS);
3218 }
3219 else {
3220 entry->set_n_type(N_EXT | N_SECT);
3221 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
3222 if ( fOptions.keepPrivateExterns() )
3223 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
3224 }
3225 }
3226
3227 // set n_sect (section number of implementation )
3228 uint8_t sectionIndex = atom->getSection()->getIndex();
3229 entry->set_n_sect(sectionIndex);
3230
3231 // the __mh_execute_header is magic and must be an absolute symbol
3232 if ( (sectionIndex==0)
3233 && (fOptions.outputKind() == Options::kDynamicExecutable)
3234 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
3235 entry->set_n_type(N_EXT | N_ABS);
3236
3237 // set n_desc
3238 uint16_t desc = 0;
3239 if ( atom->isThumb() )
3240 desc |= N_ARM_THUMB_DEF;
3241 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3242 desc |= REFERENCED_DYNAMICALLY;
3243 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3244 desc |= N_NO_DEAD_STRIP;
3245 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
3246 desc |= N_WEAK_DEF;
3247 fHasWeakExports = true;
3248 }
3249 entry->set_n_desc(desc);
3250
3251 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3252 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3253 entry->set_n_value(atom->getSectionOffset());
3254 else
3255 entry->set_n_value(this->getAtomLoadAddress(atom));
3256 }
3257
3258 template <typename A>
3259 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3260 {
3261 // set n_strx
3262 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
3263
3264 // set n_type
3265 if ( fOptions.outputKind() == Options::kObjectFile ) {
3266 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3267 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
3268 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
3269 else
3270 entry->set_n_type(N_UNDF | N_EXT);
3271 }
3272 else {
3273 if ( fOptions.prebind() )
3274 entry->set_n_type(N_PBUD | N_EXT);
3275 else
3276 entry->set_n_type(N_UNDF | N_EXT);
3277 }
3278
3279 // set n_sect
3280 entry->set_n_sect(0);
3281
3282 uint16_t desc = 0;
3283 if ( fOptions.outputKind() != Options::kObjectFile ) {
3284 // set n_desc ( high byte is library ordinal, low byte is reference type )
3285 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
3286 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
3287 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
3288 else
3289 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
3290 try {
3291 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
3292 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
3293 SET_LIBRARY_ORDINAL(desc, ordinal);
3294 }
3295 catch (const char* msg) {
3296 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3297 }
3298 }
3299 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
3300 uint8_t align = atom->getAlignment().powerOf2;
3301 // always record custom alignment of common symbols to match what compiler does
3302 SET_COMM_ALIGN(desc, align);
3303 }
3304 if ( atom->isThumb() )
3305 desc |= N_ARM_THUMB_DEF;
3306 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3307 desc |= REFERENCED_DYNAMICALLY;
3308 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
3309 desc |= N_REF_TO_WEAK;
3310 fReferencesWeakImports = true;
3311 }
3312 // set weak_import attribute
3313 if ( fWeakImportMap[atom] )
3314 desc |= N_WEAK_REF;
3315 entry->set_n_desc(desc);
3316
3317 // set n_value, zero for import proxy and size for tentative definition
3318 entry->set_n_value(atom->getSize());
3319 }
3320
3321
3322 template <typename A>
3323 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3324 {
3325 // set n_strx
3326 const char* symbolName = this->symbolTableName(atom);
3327 char anonName[32];
3328 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
3329 if ( stringsNeedLabelsInObjects() && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3330 // don't use 'l' labels for x86_64 strings
3331 // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
3332 }
3333 else {
3334 sprintf(anonName, "l%u", fAnonNameIndex++);
3335 symbolName = anonName;
3336 }
3337 }
3338 entry->set_n_strx(this->fStringsAtom->add(symbolName));
3339
3340 // set n_type
3341 uint8_t type = N_SECT;
3342 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3343 type = N_ABS;
3344 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
3345 type |= N_PEXT;
3346 entry->set_n_type(type);
3347
3348 // set n_sect (section number of implementation )
3349 uint8_t sectIndex = atom->getSection()->getIndex();
3350 if ( sectIndex == 0 ) {
3351 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
3352 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
3353 sectIndex = 1;
3354 }
3355 entry->set_n_sect(sectIndex);
3356
3357 // set n_desc
3358 uint16_t desc = 0;
3359 if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
3360 desc |= N_NO_DEAD_STRIP;
3361 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
3362 desc |= N_WEAK_DEF;
3363 if ( atom->isThumb() )
3364 desc |= N_ARM_THUMB_DEF;
3365 entry->set_n_desc(desc);
3366
3367 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3368 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3369 entry->set_n_value(atom->getSectionOffset());
3370 else
3371 entry->set_n_value(this->getAtomLoadAddress(atom));
3372 }
3373
3374
3375 template <typename A>
3376 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3377 {
3378 macho_nlist<P> entry;
3379
3380 // set n_strx
3381 entry.set_n_strx(fStringsAtom->add(name));
3382
3383 // set n_type
3384 entry.set_n_type(N_SECT);
3385
3386 // set n_sect (section number of implementation )
3387 entry.set_n_sect(atom.getSection()->getIndex());
3388
3389 // set n_desc
3390 entry.set_n_desc(0);
3391
3392 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3393 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3394
3395 // add
3396 fLocalExtraLabels.push_back(entry);
3397 }
3398
3399
3400
3401 template <typename A>
3402 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3403 {
3404 macho_nlist<P> entry;
3405
3406 // set n_strx
3407 entry.set_n_strx(fStringsAtom->add(name));
3408
3409 // set n_type
3410 entry.set_n_type(N_SECT|N_EXT);
3411
3412 // set n_sect (section number of implementation )
3413 entry.set_n_sect(atom.getSection()->getIndex());
3414
3415 // set n_desc
3416 entry.set_n_desc(0);
3417
3418 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3419 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3420
3421 // add
3422 fGlobalExtraLabels.push_back(entry);
3423 }
3424
3425 template <typename A>
3426 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
3427 {
3428 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3429 for (uint32_t i=0; i < count; ++i, ++entry) {
3430 ObjectFile::Atom* atom = atoms[i];
3431 if ( &atoms == &fExportedAtoms ) {
3432 this->setExportNlist(atom, entry);
3433 }
3434 else if ( &atoms == &fImportedAtoms ) {
3435 this->setImportNlist(atom, entry);
3436 }
3437 else {
3438 this->setLocalNlist(atom, entry);
3439 }
3440 }
3441 }
3442
3443 template <typename A>
3444 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
3445 {
3446 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
3447 fSymbolTable[startIndex++] = *it;
3448 }
3449
3450
3451 template <typename A>
3452 struct NListNameSorter
3453 {
3454 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
3455
3456 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
3457 {
3458 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
3459 }
3460 private:
3461 StringsLinkEditAtom<A>* fStringPool;
3462 };
3463
3464
3465 template <typename A>
3466 void Writer<A>::buildSymbolTable()
3467 {
3468 fSymbolTableStabsStartIndex = 0;
3469 fSymbolTableStabsCount = fStabs->size();
3470 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
3471 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
3472 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
3473 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
3474 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
3475 fSymbolTableImportCount = fImportedAtoms.size();
3476
3477 // allocate symbol table
3478 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
3479 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
3480
3481 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
3482 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
3483 if ( fLocalExtraLabels.size() != 0 )
3484 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
3485 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
3486 if ( fGlobalExtraLabels.size() != 0 ) {
3487 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
3488 // re-sort combined range
3489 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
3490 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
3491 NListNameSorter<A>(fStringsAtom) );
3492 }
3493 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
3494 addStabs(fSymbolTableStabsStartIndex);
3495
3496 // set up module table
3497 if ( fModuleInfoAtom != NULL )
3498 fModuleInfoAtom->setName();
3499
3500 // create atom to symbol index map
3501 // imports
3502 int i = 0;
3503 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
3504 fAtomToSymbolIndex[*it] = i + fSymbolTableImportStartIndex;
3505 ++i;
3506 }
3507 // locals
3508 i = 0;
3509 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
3510 fAtomToSymbolIndex[*it] = i + fSymbolTableLocalStartIndex;
3511 ++i;
3512 }
3513 // exports
3514 i = 0;
3515 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
3516 fAtomToSymbolIndex[*it] = i + fSymbolTableExportStartIndex;
3517 ++i;
3518 }
3519
3520 }
3521
3522
3523
3524 template <typename A>
3525 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
3526 {
3527 switch ( atom.getSymbolTableInclusion() ) {
3528 case ObjectFile::Atom::kSymbolTableNotIn:
3529 return false;
3530 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3531 return true;
3532 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3533 case ObjectFile::Atom::kSymbolTableIn:
3534 switch ( atom.getScope() ) {
3535 case ObjectFile::Atom::scopeGlobal:
3536 return true;
3537 case ObjectFile::Atom::scopeLinkageUnit:
3538 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
3539 default:
3540 return false;
3541 }
3542 break;
3543 }
3544 return false;
3545 }
3546
3547 template <typename A>
3548 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
3549 {
3550 const int atomCount = fAllAtoms->size();
3551 // guess at sizes of each bucket to minimize re-allocations
3552 fImportedAtoms.reserve(100);
3553 fExportedAtoms.reserve(atomCount/2);
3554 fLocalSymbolAtoms.reserve(atomCount);
3555 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3556 ObjectFile::Atom* atom = *it;
3557 // only named atoms go in symbol table
3558 if ( atom->getName() != NULL ) {
3559 // put atom into correct bucket: imports, exports, locals
3560 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
3561 switch ( atom->getDefinitionKind() ) {
3562 case ObjectFile::Atom::kExternalDefinition:
3563 case ObjectFile::Atom::kExternalWeakDefinition:
3564 fImportedAtoms.push_back(atom);
3565 break;
3566 case ObjectFile::Atom::kTentativeDefinition:
3567 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
3568 fImportedAtoms.push_back(atom);
3569 break;
3570 }
3571 // else fall into
3572 case ObjectFile::Atom::kWeakDefinition:
3573 if ( stringsNeedLabelsInObjects()
3574 && (fOptions.outputKind() == Options::kObjectFile)
3575 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn)
3576 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3577 && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3578 fLocalSymbolAtoms.push_back(atom);
3579 break;
3580 }
3581 // else fall into
3582 case ObjectFile::Atom::kRegularDefinition:
3583 case ObjectFile::Atom::kAbsoluteSymbol:
3584 if ( this->shouldExport(*atom) )
3585 fExportedAtoms.push_back(atom);
3586 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
3587 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
3588 fLocalSymbolAtoms.push_back(atom);
3589 break;
3590 }
3591 }
3592 // when geneating a .o file, dtrace static probes become local labels
3593 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
3594 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3595 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3596 ObjectFile::Reference* ref = *rit;
3597 if ( ref->getKind() == A::kDtraceProbe ) {
3598 // dtrace probe points to be add back into generated .o file
3599 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3600 }
3601 }
3602 }
3603 // when linking kernel, old style dtrace static probes become global labels
3604 else if ( fOptions.readerOptions().fForStatic ) {
3605 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3606 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3607 ObjectFile::Reference* ref = *rit;
3608 if ( ref->getKind() == A::kDtraceProbe ) {
3609 // dtrace probe points to be add back into generated .o file
3610 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3611 }
3612 }
3613 }
3614 }
3615
3616 // sort exported atoms by name
3617 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
3618 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
3619 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
3620 }
3621
3622
3623 template <typename A>
3624 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
3625 {
3626 switch ( stab.type ) {
3627 case N_FUN:
3628 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3629 // end of function N_FUN has size
3630 return stab.atom->getSize();
3631 }
3632 else {
3633 // start of function N_FUN has address
3634 return getAtomLoadAddress(stab.atom);
3635 }
3636 case N_LBRAC:
3637 case N_RBRAC:
3638 case N_SLINE:
3639 if ( stab.atom == NULL )
3640 // some weird assembly files have slines not associated with a function
3641 return stab.value;
3642 else
3643 // all these stab types need their value changed from an offset in the atom to an address
3644 return getAtomLoadAddress(stab.atom) + stab.value;
3645 case N_STSYM:
3646 case N_LCSYM:
3647 case N_BNSYM:
3648 // all these need address of atom
3649 return getAtomLoadAddress(stab.atom);;
3650 case N_ENSYM:
3651 return stab.atom->getSize();
3652 case N_SO:
3653 if ( stab.atom == NULL ) {
3654 return 0;
3655 }
3656 else {
3657 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3658 // end of translation unit N_SO has address of end of last atom
3659 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
3660 }
3661 else {
3662 // start of translation unit N_SO has address of end of first atom
3663 return getAtomLoadAddress(stab.atom);
3664 }
3665 }
3666 break;
3667 default:
3668 return stab.value;
3669 }
3670 }
3671
3672 template <typename A>
3673 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
3674 {
3675 switch (stab.type) {
3676 case N_SO:
3677 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
3678 return this->fStringsAtom->emptyString();
3679 break;
3680 }
3681 // fall into uniquing case
3682 case N_SOL:
3683 case N_BINCL:
3684 case N_EXCL:
3685 return this->fStringsAtom->addUnique(stab.string);
3686 break;
3687 default:
3688 if ( stab.string == NULL )
3689 return 0;
3690 else if ( stab.string[0] == '\0' )
3691 return this->fStringsAtom->emptyString();
3692 else
3693 return this->fStringsAtom->add(stab.string);
3694 }
3695 return 0;
3696 }
3697
3698 template <typename A>
3699 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
3700 {
3701 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
3702 if ( stab.type == N_FUN )
3703 return stab.other;
3704 else if ( stab.atom != NULL )
3705 return stab.atom->getSection()->getIndex();
3706 else
3707 return stab.other;
3708 }
3709
3710 template <typename A>
3711 void Writer<A>::addStabs(uint32_t startIndex)
3712 {
3713 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3714 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
3715 const ObjectFile::Reader::Stab& stab = *it;
3716 entry->set_n_type(stab.type);
3717 entry->set_n_sect(sectionIndexForStab(stab));
3718 entry->set_n_desc(stab.desc);
3719 entry->set_n_value(valueForStab(stab));
3720 entry->set_n_strx(stringOffsetForStab(stab));
3721 }
3722 }
3723
3724
3725
3726 template <typename A>
3727 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
3728 {
3729 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fAtomToSymbolIndex.find(&atom);
3730 if ( pos != fAtomToSymbolIndex.end() )
3731 return pos->second;
3732 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
3733 }
3734
3735
3736 template <>
3737 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3738 {
3739 switch ( target.getSymbolTableInclusion() ) {
3740 case ObjectFile::Atom::kSymbolTableNotIn:
3741 return false;
3742 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3743 case ObjectFile::Atom::kSymbolTableIn:
3744 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3745 return true;
3746 };
3747 return false;
3748 }
3749
3750 template <typename A>
3751 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3752 {
3753 switch ( target.getDefinitionKind() ) {
3754 case ObjectFile::Atom::kRegularDefinition:
3755 case ObjectFile::Atom::kWeakDefinition:
3756 case ObjectFile::Atom::kAbsoluteSymbol:
3757 return false;
3758 case ObjectFile::Atom::kTentativeDefinition:
3759 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
3760 return false;
3761 else
3762 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
3763 case ObjectFile::Atom::kExternalDefinition:
3764 case ObjectFile::Atom::kExternalWeakDefinition:
3765 return shouldExport(target);
3766 }
3767 return false;
3768 }
3769
3770 template <typename A>
3771 void Writer<A>::buildFixups()
3772 {
3773 if ( fOptions.outputKind() == Options::kObjectFile ) {
3774 this->buildObjectFileFixups();
3775 }
3776 else {
3777 if ( fOptions.keepRelocations() )
3778 this->buildObjectFileFixups();
3779 this->buildExecutableFixups();
3780 }
3781 }
3782
3783 template <>
3784 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3785 {
3786 ObjectFile::Atom& target = ref->getTarget();
3787 bool external = this->makesExternalRelocatableReference(target);
3788 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
3789 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3790 macho_relocation_info<P> reloc1;
3791 macho_relocation_info<P> reloc2;
3792 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
3793
3794 switch ( kind ) {
3795 case x86_64::kNoFixUp:
3796 case x86_64::kGOTNoFixUp:
3797 case x86_64::kFollowOn:
3798 case x86_64::kGroupSubordinate:
3799 return 0;
3800
3801 case x86_64::kPointer:
3802 case x86_64::kPointerWeakImport:
3803 reloc1.set_r_address(address);
3804 reloc1.set_r_symbolnum(symbolIndex);
3805 reloc1.set_r_pcrel(false);
3806 reloc1.set_r_length(3);
3807 reloc1.set_r_extern(external);
3808 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3809 fSectionRelocs.push_back(reloc1);
3810 return 1;
3811
3812 case x86_64::kPointer32:
3813 reloc1.set_r_address(address);
3814 reloc1.set_r_symbolnum(symbolIndex);
3815 reloc1.set_r_pcrel(false);
3816 reloc1.set_r_length(2);
3817 reloc1.set_r_extern(external);
3818 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3819 fSectionRelocs.push_back(reloc1);
3820 return 1;
3821
3822 case x86_64::kPointerDiff32:
3823 case x86_64::kPointerDiff:
3824 {
3825 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3826 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
3827 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
3828 reloc1.set_r_address(address);
3829 reloc1.set_r_symbolnum(symbolIndex);
3830 reloc1.set_r_pcrel(false);
3831 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
3832 reloc1.set_r_extern(external);
3833 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3834 reloc2.set_r_address(address);
3835 reloc2.set_r_symbolnum(fromSymbolIndex);
3836 reloc2.set_r_pcrel(false);
3837 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
3838 reloc2.set_r_extern(fromExternal);
3839 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
3840 fSectionRelocs.push_back(reloc1);
3841 fSectionRelocs.push_back(reloc2);
3842 return 2;
3843 }
3844
3845 case x86_64::kBranchPCRel32:
3846 case x86_64::kBranchPCRel32WeakImport:
3847 case x86_64::kDtraceProbeSite:
3848 case x86_64::kDtraceIsEnabledSite:
3849 reloc1.set_r_address(address);
3850 reloc1.set_r_symbolnum(symbolIndex);
3851 reloc1.set_r_pcrel(true);
3852 reloc1.set_r_length(2);
3853 reloc1.set_r_extern(external);
3854 reloc1.set_r_type(X86_64_RELOC_BRANCH);
3855 fSectionRelocs.push_back(reloc1);
3856 return 1;
3857
3858 case x86_64::kPCRel32:
3859 reloc1.set_r_address(address);
3860 reloc1.set_r_symbolnum(symbolIndex);
3861 reloc1.set_r_pcrel(true);
3862 reloc1.set_r_length(2);
3863 reloc1.set_r_extern(external);
3864 reloc1.set_r_type(X86_64_RELOC_SIGNED);
3865 fSectionRelocs.push_back(reloc1);
3866 return 1;
3867
3868 case x86_64::kPCRel32_1:
3869 reloc1.set_r_address(address);
3870 reloc1.set_r_symbolnum(symbolIndex);
3871 reloc1.set_r_pcrel(true);
3872 reloc1.set_r_length(2);
3873 reloc1.set_r_extern(external);
3874 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
3875 fSectionRelocs.push_back(reloc1);
3876 return 1;
3877
3878 case x86_64::kPCRel32_2:
3879 reloc1.set_r_address(address);
3880 reloc1.set_r_symbolnum(symbolIndex);
3881 reloc1.set_r_pcrel(true);
3882 reloc1.set_r_length(2);
3883 reloc1.set_r_extern(external);
3884 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
3885 fSectionRelocs.push_back(reloc1);
3886 return 1;
3887
3888 case x86_64::kPCRel32_4:
3889 reloc1.set_r_address(address);
3890 reloc1.set_r_symbolnum(symbolIndex);
3891 reloc1.set_r_pcrel(true);
3892 reloc1.set_r_length(2);
3893 reloc1.set_r_extern(external);
3894 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
3895 fSectionRelocs.push_back(reloc1);
3896 return 1;
3897
3898 case x86_64::kBranchPCRel8:
3899 reloc1.set_r_address(address);
3900 reloc1.set_r_symbolnum(symbolIndex);
3901 reloc1.set_r_pcrel(true);
3902 reloc1.set_r_length(0);
3903 reloc1.set_r_extern(external);
3904 reloc1.set_r_type(X86_64_RELOC_BRANCH);
3905 fSectionRelocs.push_back(reloc1);
3906 return 1;
3907
3908 case x86_64::kPCRel32GOT:
3909 case x86_64::kPCRel32GOTWeakImport:
3910 reloc1.set_r_address(address);
3911 reloc1.set_r_symbolnum(symbolIndex);
3912 reloc1.set_r_pcrel(true);
3913 reloc1.set_r_length(2);
3914 reloc1.set_r_extern(external);
3915 reloc1.set_r_type(X86_64_RELOC_GOT);
3916 fSectionRelocs.push_back(reloc1);
3917 return 1;
3918
3919 case x86_64::kPCRel32GOTLoad:
3920 case x86_64::kPCRel32GOTLoadWeakImport:
3921 reloc1.set_r_address(address);
3922 reloc1.set_r_symbolnum(symbolIndex);
3923 reloc1.set_r_pcrel(true);
3924 reloc1.set_r_length(2);
3925 reloc1.set_r_extern(external);
3926 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
3927 fSectionRelocs.push_back(reloc1);
3928 return 1;
3929
3930 case x86_64::kPointerDiff24:
3931 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
3932
3933 case x86_64::kImageOffset32:
3934 throw "internal linker error, kImageOffset32 can't be encoded into object files";
3935
3936 case x86_64::kSectionOffset24:
3937 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
3938
3939 case x86_64::kDtraceTypeReference:
3940 case x86_64::kDtraceProbe:
3941 // generates no relocs
3942 return 0;
3943 }
3944 return 0;
3945 }
3946
3947
3948 template <>
3949 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3950 {
3951 ObjectFile::Atom& target = ref->getTarget();
3952 bool isExtern = this->makesExternalRelocatableReference(target);
3953 uint32_t symbolIndex = 0;
3954 if ( isExtern )
3955 symbolIndex = this->symbolIndex(target);
3956 uint32_t sectionNum = target.getSection()->getIndex();
3957 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3958 macho_relocation_info<P> reloc1;
3959 macho_relocation_info<P> reloc2;
3960 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
3961 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
3962 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
3963
3964 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
3965 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
3966 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
3967
3968
3969 switch ( kind ) {
3970 case x86::kNoFixUp:
3971 case x86::kFollowOn:
3972 case x86::kGroupSubordinate:
3973 return 0;
3974
3975 case x86::kPointer:
3976 case x86::kPointerWeakImport:
3977 case x86::kAbsolute32:
3978 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
3979 // use scattered reloc is target offset is non-zero
3980 sreloc1->set_r_scattered(true);
3981 sreloc1->set_r_pcrel(false);
3982 sreloc1->set_r_length(2);
3983 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
3984 sreloc1->set_r_address(address);
3985 sreloc1->set_r_value(target.getAddress());
3986 }
3987 else {
3988 reloc1.set_r_address(address);
3989 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3990 reloc1.set_r_pcrel(false);
3991 reloc1.set_r_length(2);
3992 reloc1.set_r_extern(isExtern);
3993 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3994 }
3995 fSectionRelocs.push_back(reloc1);
3996 return 1;
3997
3998 case x86::kPointerDiff16:
3999 case x86::kPointerDiff:
4000 {
4001 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4002 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
4003 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
4004 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
4005 sreloc1->set_r_scattered(true);
4006 sreloc1->set_r_pcrel(false);
4007 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4008 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4009 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
4010 else
4011 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
4012 sreloc1->set_r_address(address);
4013 sreloc1->set_r_value(target.getAddress());
4014
4015 sreloc2->set_r_scattered(true);
4016 sreloc2->set_r_pcrel(false);
4017 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4018 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
4019 sreloc2->set_r_address(0);
4020 if ( &ref->getFromTarget() == atom )
4021 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4022 else
4023 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4024 fSectionRelocs.push_back(reloc2);
4025 fSectionRelocs.push_back(reloc1);
4026 return 2;
4027 }
4028
4029 case x86::kPCRel32WeakImport:
4030 case x86::kPCRel32:
4031 case x86::kPCRel16:
4032 case x86::kPCRel8:
4033 case x86::kDtraceProbeSite:
4034 case x86::kDtraceIsEnabledSite:
4035 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4036 // use scattered reloc is target offset is non-zero
4037 sreloc1->set_r_scattered(true);
4038 sreloc1->set_r_pcrel(true);
4039 sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4040 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4041 sreloc1->set_r_address(address);
4042 sreloc1->set_r_value(target.getAddress());
4043 }
4044 else {
4045 reloc1.set_r_address(address);
4046 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4047 reloc1.set_r_pcrel(true);
4048 reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4049 reloc1.set_r_extern(isExtern);
4050 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4051 }
4052 fSectionRelocs.push_back(reloc1);
4053 return 1;
4054
4055 case x86::kPointerDiff24:
4056 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4057
4058 case x86::kImageOffset32:
4059 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4060
4061 case x86::kSectionOffset24:
4062 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
4063
4064 case x86::kDtraceTypeReference:
4065 case x86::kDtraceProbe:
4066 // generates no relocs
4067 return 0;
4068
4069 }
4070 return 0;
4071 }
4072
4073 template <>
4074 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4075 {
4076 ObjectFile::Atom& target = ref->getTarget();
4077 bool isExtern = this->makesExternalRelocatableReference(target);
4078 uint32_t symbolIndex = 0;
4079 if ( isExtern )
4080 symbolIndex = this->symbolIndex(target);
4081 uint32_t sectionNum = target.getSection()->getIndex();
4082 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4083 macho_relocation_info<P> reloc1;
4084 macho_relocation_info<P> reloc2;
4085 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4086 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4087 arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
4088
4089 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
4090 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
4091 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
4092
4093
4094 switch ( kind ) {
4095 case arm::kNoFixUp:
4096 case arm::kFollowOn:
4097 case arm::kGroupSubordinate:
4098 return 0;
4099
4100 case arm::kPointer:
4101 case arm::kReadOnlyPointer:
4102 case arm::kPointerWeakImport:
4103 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4104 // use scattered reloc is target offset is non-zero
4105 sreloc1->set_r_scattered(true);
4106 sreloc1->set_r_pcrel(false);
4107 sreloc1->set_r_length(2);
4108 sreloc1->set_r_type(ARM_RELOC_VANILLA);
4109 sreloc1->set_r_address(address);
4110 sreloc1->set_r_value(target.getAddress());
4111 }
4112 else {
4113 reloc1.set_r_address(address);
4114 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4115 reloc1.set_r_pcrel(false);
4116 reloc1.set_r_length(2);
4117 reloc1.set_r_extern(isExtern);
4118 reloc1.set_r_type(ARM_RELOC_VANILLA);
4119 }
4120 fSectionRelocs.push_back(reloc1);
4121 return 1;
4122
4123 case arm::kPointerDiff:
4124 {
4125 sreloc1->set_r_scattered(true);
4126 sreloc1->set_r_pcrel(false);
4127 sreloc1->set_r_length(2);
4128 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4129 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
4130 else
4131 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
4132 sreloc1->set_r_address(address);
4133 sreloc1->set_r_value(target.getAddress());
4134 sreloc2->set_r_scattered(true);
4135 sreloc2->set_r_pcrel(false);
4136 sreloc2->set_r_length(2);
4137 sreloc2->set_r_type(ARM_RELOC_PAIR);
4138 sreloc2->set_r_address(0);
4139 if ( &ref->getFromTarget() == atom )
4140 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4141 else
4142 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4143 fSectionRelocs.push_back(reloc2);
4144 fSectionRelocs.push_back(reloc1);
4145 return 2;
4146 }
4147
4148 case arm::kBranch24WeakImport:
4149 case arm::kBranch24:
4150 case arm::kDtraceProbeSite:
4151 case arm::kDtraceIsEnabledSite:
4152 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4153 // use scattered reloc is target offset is non-zero
4154 sreloc1->set_r_scattered(true);
4155 sreloc1->set_r_pcrel(true);
4156 sreloc1->set_r_length(2);
4157 sreloc1->set_r_type(ARM_RELOC_BR24);
4158 sreloc1->set_r_address(address);
4159 sreloc1->set_r_value(target.getAddress());
4160 }
4161 else {
4162 reloc1.set_r_address(address);
4163 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4164 reloc1.set_r_pcrel(true);
4165 reloc1.set_r_length(2);
4166 reloc1.set_r_extern(isExtern);
4167 reloc1.set_r_type(ARM_RELOC_BR24);
4168 }
4169 fSectionRelocs.push_back(reloc1);
4170 return 1;
4171
4172 case arm::kThumbBranch22WeakImport:
4173 case arm::kThumbBranch22:
4174 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4175 // use scattered reloc if target offset is non-zero
4176 sreloc1->set_r_scattered(true);
4177 sreloc1->set_r_pcrel(true);
4178 sreloc1->set_r_length(2);
4179 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
4180 sreloc1->set_r_address(address);
4181 sreloc1->set_r_value(target.getAddress());
4182 }
4183 else {
4184 reloc1.set_r_address(address);
4185 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4186 reloc1.set_r_pcrel(true);
4187 reloc1.set_r_length(2);
4188 reloc1.set_r_extern(isExtern);
4189 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
4190 }
4191 fSectionRelocs.push_back(reloc1);
4192 return 1;
4193
4194 case arm::kDtraceTypeReference:
4195 case arm::kDtraceProbe:
4196 // generates no relocs
4197 return 0;
4198
4199 }
4200 return 0;
4201 }
4202
4203 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
4204 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4205 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
4206 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4207 template <> uint64_t Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
4208
4209 template <>
4210 uint8_t Writer<ppc>::getRelocPointerSize()
4211 {
4212 return 2;
4213 }
4214
4215 template <>
4216 uint8_t Writer<ppc64>::getRelocPointerSize()
4217 {
4218 return 3;
4219 }
4220
4221 template <>
4222 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4223 {
4224 return addObjectRelocs_powerpc(atom, ref);
4225 }
4226
4227 template <>
4228 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4229 {
4230 return addObjectRelocs_powerpc(atom, ref);
4231 }
4232
4233 //
4234 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
4235 // they use a common addObjectRelocs_powerpc() method.
4236 //
4237 template <typename A>
4238 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4239 {
4240 ObjectFile::Atom& target = ref->getTarget();
4241 bool isExtern = this->makesExternalRelocatableReference(target);
4242 uint32_t symbolIndex = 0;
4243 if ( isExtern )
4244 symbolIndex = this->symbolIndex(target);
4245 uint32_t sectionNum = target.getSection()->getIndex();
4246 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4247 macho_relocation_info<P> reloc1;
4248 macho_relocation_info<P> reloc2;
4249 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4250 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4251 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
4252
4253 switch ( kind ) {
4254 case A::kNoFixUp:
4255 case A::kFollowOn:
4256 case A::kGroupSubordinate:
4257 return 0;
4258
4259 case A::kPointer:
4260 case A::kPointerWeakImport:
4261 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
4262 // use scattered reloc is target offset is outside target
4263 sreloc1->set_r_scattered(true);
4264 sreloc1->set_r_pcrel(false);
4265 sreloc1->set_r_length(getRelocPointerSize());
4266 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4267 sreloc1->set_r_address(address);
4268 sreloc1->set_r_value(target.getAddress());
4269 }
4270 else {
4271 reloc1.set_r_address(address);
4272 if ( isExtern )
4273 reloc1.set_r_symbolnum(symbolIndex);
4274 else
4275 reloc1.set_r_symbolnum(sectionNum);
4276 reloc1.set_r_pcrel(false);
4277 reloc1.set_r_length(getRelocPointerSize());
4278 reloc1.set_r_extern(isExtern);
4279 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4280 }
4281 fSectionRelocs.push_back(reloc1);
4282 return 1;
4283
4284 case A::kPointerDiff16:
4285 case A::kPointerDiff32:
4286 case A::kPointerDiff64:
4287 {
4288 sreloc1->set_r_scattered(true);
4289 sreloc1->set_r_pcrel(false);
4290 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
4291 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4292 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
4293 else
4294 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
4295 sreloc1->set_r_address(address);
4296 sreloc1->set_r_value(target.getAddress());
4297 sreloc2->set_r_scattered(true);
4298 sreloc2->set_r_pcrel(false);
4299 sreloc2->set_r_length(sreloc1->r_length());
4300 sreloc2->set_r_type(PPC_RELOC_PAIR);
4301 sreloc2->set_r_address(0);
4302 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4303 fSectionRelocs.push_back(reloc2);
4304 fSectionRelocs.push_back(reloc1);
4305 return 2;
4306 }
4307
4308 case A::kBranch24WeakImport:
4309 case A::kBranch24:
4310 case A::kDtraceProbeSite:
4311 case A::kDtraceIsEnabledSite:
4312 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4313 reloc1.set_r_address(address);
4314 if ( isExtern )
4315 reloc1.set_r_symbolnum(symbolIndex);
4316 else
4317 reloc1.set_r_symbolnum(sectionNum);
4318 reloc1.set_r_pcrel(true);
4319 reloc1.set_r_length(2);
4320 reloc1.set_r_type(PPC_RELOC_BR24);
4321 reloc1.set_r_extern(isExtern);
4322 }
4323 else {
4324 sreloc1->set_r_scattered(true);
4325 sreloc1->set_r_pcrel(true);
4326 sreloc1->set_r_length(2);
4327 sreloc1->set_r_type(PPC_RELOC_BR24);
4328 sreloc1->set_r_address(address);
4329 sreloc1->set_r_value(target.getAddress());
4330 }
4331 fSectionRelocs.push_back(reloc1);
4332 return 1;
4333
4334 case A::kBranch14:
4335 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4336 reloc1.set_r_address(address);
4337 if ( isExtern )
4338 reloc1.set_r_symbolnum(symbolIndex);
4339 else
4340 reloc1.set_r_symbolnum(sectionNum);
4341 reloc1.set_r_pcrel(true);
4342 reloc1.set_r_length(2);
4343 reloc1.set_r_type(PPC_RELOC_BR14);
4344 reloc1.set_r_extern(isExtern);
4345 }
4346 else {
4347 sreloc1->set_r_scattered(true);
4348 sreloc1->set_r_pcrel(true);
4349 sreloc1->set_r_length(2);
4350 sreloc1->set_r_type(PPC_RELOC_BR14);
4351 sreloc1->set_r_address(address);
4352 sreloc1->set_r_value(target.getAddress());
4353 }
4354 fSectionRelocs.push_back(reloc1);
4355 return 1;
4356
4357 case A::kPICBaseLow16:
4358 case A::kPICBaseLow14:
4359 {
4360 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4361 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4362 sreloc1->set_r_scattered(true);
4363 sreloc1->set_r_pcrel(false);
4364 sreloc1->set_r_length(2);
4365 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
4366 sreloc1->set_r_address(address);
4367 sreloc1->set_r_value(target.getAddress());
4368 sreloc2->set_r_scattered(true);
4369 sreloc2->set_r_pcrel(false);
4370 sreloc2->set_r_length(2);
4371 sreloc2->set_r_type(PPC_RELOC_PAIR);
4372 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
4373 sreloc2->set_r_value(fromAddr);
4374 fSectionRelocs.push_back(reloc2);
4375 fSectionRelocs.push_back(reloc1);
4376 return 2;
4377 }
4378
4379 case A::kPICBaseHigh16:
4380 {
4381 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4382 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4383 sreloc1->set_r_scattered(true);
4384 sreloc1->set_r_pcrel(false);
4385 sreloc1->set_r_length(2);
4386 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
4387 sreloc1->set_r_address(address);
4388 sreloc1->set_r_value(target.getAddress());
4389 sreloc2->set_r_scattered(true);
4390 sreloc2->set_r_pcrel(false);
4391 sreloc2->set_r_length(2);
4392 sreloc2->set_r_type(PPC_RELOC_PAIR);
4393 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
4394 sreloc2->set_r_value(fromAddr);
4395 fSectionRelocs.push_back(reloc2);
4396 fSectionRelocs.push_back(reloc1);
4397 return 2;
4398 }
4399
4400 case A::kAbsLow14:
4401 case A::kAbsLow16:
4402 {
4403 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4404 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4405 reloc1.set_r_address(address);
4406 if ( isExtern )
4407 reloc1.set_r_symbolnum(symbolIndex);
4408 else
4409 reloc1.set_r_symbolnum(sectionNum);
4410 reloc1.set_r_pcrel(false);
4411 reloc1.set_r_length(2);
4412 reloc1.set_r_extern(isExtern);
4413 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4414 }
4415 else {
4416 sreloc1->set_r_scattered(true);
4417 sreloc1->set_r_pcrel(false);
4418 sreloc1->set_r_length(2);
4419 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4420 sreloc1->set_r_address(address);
4421 sreloc1->set_r_value(target.getAddress());
4422 }
4423 if ( isExtern )
4424 reloc2.set_r_address(ref->getTargetOffset() >> 16);
4425 else
4426 reloc2.set_r_address(toAddr >> 16);
4427 reloc2.set_r_symbolnum(0);
4428 reloc2.set_r_pcrel(false);
4429 reloc2.set_r_length(2);
4430 reloc2.set_r_extern(false);
4431 reloc2.set_r_type(PPC_RELOC_PAIR);
4432 fSectionRelocs.push_back(reloc2);
4433 fSectionRelocs.push_back(reloc1);
4434 return 2;
4435 }
4436
4437 case A::kAbsHigh16:
4438 {
4439 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4440 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4441 reloc1.set_r_address(address);
4442 if ( isExtern )
4443 reloc1.set_r_symbolnum(symbolIndex);
4444 else
4445 reloc1.set_r_symbolnum(sectionNum);
4446 reloc1.set_r_pcrel(false);
4447 reloc1.set_r_length(2);
4448 reloc1.set_r_extern(isExtern);
4449 reloc1.set_r_type(PPC_RELOC_HI16);
4450 }
4451 else {
4452 sreloc1->set_r_scattered(true);
4453 sreloc1->set_r_pcrel(false);
4454 sreloc1->set_r_length(2);
4455 sreloc1->set_r_type(PPC_RELOC_HI16);
4456 sreloc1->set_r_address(address);
4457 sreloc1->set_r_value(target.getAddress());
4458 }
4459 if ( isExtern )
4460 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4461 else
4462 reloc2.set_r_address(toAddr & 0xFFFF);
4463 reloc2.set_r_symbolnum(0);
4464 reloc2.set_r_pcrel(false);
4465 reloc2.set_r_length(2);
4466 reloc2.set_r_extern(false);
4467 reloc2.set_r_type(PPC_RELOC_PAIR);
4468 fSectionRelocs.push_back(reloc2);
4469 fSectionRelocs.push_back(reloc1);
4470 return 2;
4471 }
4472
4473 case A::kAbsHigh16AddLow:
4474 {
4475 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4476 uint32_t overflow = 0;
4477 if ( (toAddr & 0x00008000) != 0 )
4478 overflow = 0x10000;
4479 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4480 reloc1.set_r_address(address);
4481 if ( isExtern )
4482 reloc1.set_r_symbolnum(symbolIndex);
4483 else
4484 reloc1.set_r_symbolnum(sectionNum);
4485 reloc1.set_r_pcrel(false);
4486 reloc1.set_r_length(2);
4487 reloc1.set_r_extern(isExtern);
4488 reloc1.set_r_type(PPC_RELOC_HA16);
4489 }
4490 else {
4491 sreloc1->set_r_scattered(true);
4492 sreloc1->set_r_pcrel(false);
4493 sreloc1->set_r_length(2);
4494 sreloc1->set_r_type(PPC_RELOC_HA16);
4495 sreloc1->set_r_address(address);
4496 sreloc1->set_r_value(target.getAddress());
4497 }
4498 if ( isExtern )
4499 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4500 else
4501 reloc2.set_r_address(toAddr & 0xFFFF);
4502 reloc2.set_r_symbolnum(0);
4503 reloc2.set_r_pcrel(false);
4504 reloc2.set_r_length(2);
4505 reloc2.set_r_extern(false);
4506 reloc2.set_r_type(PPC_RELOC_PAIR);
4507 fSectionRelocs.push_back(reloc2);
4508 fSectionRelocs.push_back(reloc1);
4509 return 2;
4510 }
4511
4512 case A::kDtraceTypeReference:
4513 case A::kDtraceProbe:
4514 // generates no relocs
4515 return 0;
4516 }
4517 return 0;
4518 }
4519
4520
4521
4522 //
4523 // There are cases when an entry in the indirect symbol table is the magic value
4524 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
4525 // the content of the corresponding part of the __nl_symbol_pointer section
4526 // must also change.
4527 //
4528 template <typename A>
4529 bool Writer<A>::indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const
4530 {
4531 // cannot use INDIRECT_SYMBOL_LOCAL to tentative definitions in object files
4532 // because tentative defs don't have addresses
4533 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition )
4534 return false;
4535
4536 // must use INDIRECT_SYMBOL_LOCAL if there is an addend
4537 if ( ref->getTargetOffset() != 0 )
4538 return true;
4539
4540 // don't use INDIRECT_SYMBOL_LOCAL for external symbols
4541 return ! this->shouldExport(ref->getTarget());
4542 }
4543
4544
4545 template <typename A>
4546 void Writer<A>::buildObjectFileFixups()
4547 {
4548 uint32_t relocIndex = 0;
4549 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
4550 const int segCount = segmentInfos.size();
4551 for(int i=0; i < segCount; ++i) {
4552 SegmentInfo* curSegment = segmentInfos[i];
4553 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4554 const int sectionCount = sectionInfos.size();
4555 for(int j=0; j < sectionCount; ++j) {
4556 SectionInfo* curSection = sectionInfos[j];
4557 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
4558 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
4559 if ( ! curSection->fAllZeroFill ) {
4560 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4561 || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
4562 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
4563 curSection->fRelocOffset = relocIndex;
4564 const int atomCount = sectionAtoms.size();
4565 for (int k=0; k < atomCount; ++k) {
4566 ObjectFile::Atom* atom = sectionAtoms[k];
4567 //fprintf(stderr, "buildObjectFileFixups(): atom %s has %lu references\n", atom->getDisplayName(), atom->getReferences().size());
4568 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
4569 const int refCount = refs.size();
4570 for (int l=0; l < refCount; ++l) {
4571 ObjectFile::Reference* ref = refs[l];
4572 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4573 || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
4574 uint32_t offsetInSection = atom->getSectionOffset();
4575 uint32_t indexInSection = offsetInSection / atom->getSize();
4576 uint32_t undefinedSymbolIndex;
4577 if ( curSection->fAllStubs ) {
4578 ObjectFile::Atom& stubTarget =ref->getTarget();
4579 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
4580 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
4581 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
4582 }
4583 else if ( curSection->fAllNonLazyPointers) {
4584 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
4585 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
4586 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4587 else
4588 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
4589 }
4590 else {
4591 // should never get here, fAllLazyPointers not used in generated .o files
4592 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4593 }
4594 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
4595 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
4596 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
4597 fIndirectTableAtom->fTable.push_back(entry);
4598 if ( curSection->fAllLazyPointers ) {
4599 ObjectFile::Atom& target = ref->getTarget();
4600 ObjectFile::Atom& fromTarget = ref->getFromTarget();
4601 if ( &fromTarget == NULL ) {
4602 warning("lazy pointer %s missing initial binding", atom->getDisplayName());
4603 }
4604 else {
4605 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
4606 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
4607 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
4608 macho_relocation_info<P> reloc1;
4609 reloc1.set_r_address(atom->getSectionOffset());
4610 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
4611 reloc1.set_r_pcrel(false);
4612 reloc1.set_r_length();
4613 reloc1.set_r_extern(isExtern);
4614 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4615 fSectionRelocs.push_back(reloc1);
4616 ++relocIndex;
4617 }
4618 }
4619 else if ( curSection->fAllStubs ) {
4620 relocIndex += this->addObjectRelocs(atom, ref);
4621 }
4622 }
4623 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
4624 relocIndex += this->addObjectRelocs(atom, ref);
4625 }
4626 }
4627 }
4628 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
4629 }
4630 }
4631 }
4632
4633 // reverse the relocs
4634 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
4635
4636 // now reverse section reloc offsets
4637 for(int i=0; i < segCount; ++i) {
4638 SegmentInfo* curSegment = segmentInfos[i];
4639 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4640 const int sectionCount = sectionInfos.size();
4641 for(int j=0; j < sectionCount; ++j) {
4642 SectionInfo* curSection = sectionInfos[j];
4643 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
4644 }
4645 }
4646
4647 }
4648
4649
4650 template <>
4651 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
4652 {
4653 uint64_t result;
4654 if ( fOptions.outputKind() == Options::kKextBundle ) {
4655 // for x86_64 kext bundles, the r_address field in relocs
4656 // is the offset from the start address of the first segment
4657 result = address - fSegmentInfos[0]->fBaseAddress;
4658 if ( result > 0xFFFFFFFF ) {
4659 throwf("kext bundle too large: address can't fit in 31-bit r_address field in %s from %s",
4660 atom->getDisplayName(), atom->getFile()->getPath());
4661 }
4662 }
4663 else {
4664 // for x86_64, the r_address field in relocs for final linked images
4665 // is the offset from the start address of the first writable segment
4666 result = address - fFirstWritableSegment->fBaseAddress;
4667 if ( result > 0xFFFFFFFF ) {
4668 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
4669 throwf("text relocs not supported for x86_64 in %s from %s",
4670 atom->getDisplayName(), atom->getFile()->getPath());
4671 else
4672 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
4673 atom->getDisplayName(), atom->getFile()->getPath());
4674 }
4675 }
4676 return result;
4677 }
4678
4679
4680 template <>
4681 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4682 {
4683 switch ( ref.getKind() ) {
4684 case ppc::kAbsLow16:
4685 case ppc::kAbsLow14:
4686 case ppc::kAbsHigh16:
4687 case ppc::kAbsHigh16AddLow:
4688 if ( fSlideable )
4689 return true;
4690 }
4691 return false;
4692 }
4693
4694
4695 template <>
4696 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4697 {
4698 switch ( ref.getKind() ) {
4699 case ppc::kAbsLow16:
4700 case ppc::kAbsLow14:
4701 case ppc::kAbsHigh16:
4702 case ppc::kAbsHigh16AddLow:
4703 if ( fSlideable )
4704 return true;
4705 }
4706 return false;
4707 }
4708
4709 template <>
4710 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4711 {
4712 if ( ref.getKind() == x86::kAbsolute32 ) {
4713 switch ( ref.getTarget().getDefinitionKind() ) {
4714 case ObjectFile::Atom::kTentativeDefinition:
4715 case ObjectFile::Atom::kRegularDefinition:
4716 case ObjectFile::Atom::kWeakDefinition:
4717 // illegal in dylibs/bundles, until we support TEXT relocs
4718 return fSlideable;
4719 case ObjectFile::Atom::kExternalDefinition:
4720 case ObjectFile::Atom::kExternalWeakDefinition:
4721 // illegal until we support TEXT relocs
4722 return true;
4723 case ObjectFile::Atom::kAbsoluteSymbol:
4724 // absolute symbbols only allowed in static executables
4725 return ( fOptions.outputKind() != Options::kStaticExecutable);
4726 }
4727 }
4728 return false;
4729 }
4730
4731 template <>
4732 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4733 {
4734 if ( fOptions.outputKind() == Options::kKextBundle ) {
4735 switch ( ref.getTarget().getDefinitionKind() ) {
4736 case ObjectFile::Atom::kTentativeDefinition:
4737 case ObjectFile::Atom::kRegularDefinition:
4738 case ObjectFile::Atom::kWeakDefinition:
4739 case ObjectFile::Atom::kAbsoluteSymbol:
4740 return false;
4741 case ObjectFile::Atom::kExternalDefinition:
4742 case ObjectFile::Atom::kExternalWeakDefinition:
4743 // true means we need a TEXT relocs
4744 switch ( ref.getKind() ) {
4745 case x86_64::kBranchPCRel32:
4746 case x86_64::kBranchPCRel32WeakImport:
4747 case x86_64::kPCRel32GOTLoad:
4748 case x86_64::kPCRel32GOTLoadWeakImport:
4749 case x86_64::kPCRel32GOT:
4750 case x86_64::kPCRel32GOTWeakImport:
4751 return true;
4752 }
4753 break;
4754 }
4755 }
4756 return false;
4757 }
4758
4759 template <>
4760 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4761 {
4762 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4763 switch ( ref.getTarget().getDefinitionKind() ) {
4764 case ObjectFile::Atom::kTentativeDefinition:
4765 case ObjectFile::Atom::kRegularDefinition:
4766 case ObjectFile::Atom::kWeakDefinition:
4767 // illegal in dylibs/bundles, until we support TEXT relocs
4768 return fSlideable;
4769 case ObjectFile::Atom::kExternalDefinition:
4770 case ObjectFile::Atom::kExternalWeakDefinition:
4771 // illegal until we support TEXT relocs
4772 return true;
4773 case ObjectFile::Atom::kAbsoluteSymbol:
4774 // absolute symbbols only allowed in static executables
4775 return ( fOptions.outputKind() != Options::kStaticExecutable);
4776 }
4777 }
4778 return false;
4779 }
4780
4781 template <>
4782 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4783 {
4784 if ( ref.getKind() == x86::kAbsolute32 ) {
4785 switch ( ref.getTarget().getDefinitionKind() ) {
4786 case ObjectFile::Atom::kTentativeDefinition:
4787 case ObjectFile::Atom::kRegularDefinition:
4788 case ObjectFile::Atom::kWeakDefinition:
4789 // a reference to the absolute address of something in this same linkage unit can be
4790 // encoded as a local text reloc in a dylib or bundle
4791 if ( fSlideable ) {
4792 macho_relocation_info<P> reloc;
4793 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4794 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4795 reloc.set_r_symbolnum(sectInfo->getIndex());
4796 reloc.set_r_pcrel(false);
4797 reloc.set_r_length();
4798 reloc.set_r_extern(false);
4799 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4800 fInternalRelocs.push_back(reloc);
4801 atomSection->fHasTextLocalRelocs = true;
4802 if ( fOptions.makeCompressedDyldInfo() ) {
4803 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
4804 }
4805 return true;
4806 }
4807 return false;
4808 case ObjectFile::Atom::kExternalDefinition:
4809 case ObjectFile::Atom::kExternalWeakDefinition:
4810 case ObjectFile::Atom::kAbsoluteSymbol:
4811 return false;
4812 }
4813 }
4814 return false;
4815 }
4816
4817 template <>
4818 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4819 {
4820 macho_relocation_info<P> reloc1;
4821 macho_relocation_info<P> reloc2;
4822 switch ( ref.getTarget().getDefinitionKind() ) {
4823 case ObjectFile::Atom::kTentativeDefinition:
4824 case ObjectFile::Atom::kRegularDefinition:
4825 case ObjectFile::Atom::kWeakDefinition:
4826 switch ( ref.getKind() ) {
4827 case ppc::kAbsLow16:
4828 case ppc::kAbsLow14:
4829 // a reference to the absolute address of something in this same linkage unit can be
4830 // encoded as a local text reloc in a dylib or bundle
4831 if ( fSlideable ) {
4832 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4833 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
4834 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4835 reloc1.set_r_symbolnum(sectInfo->getIndex());
4836 reloc1.set_r_pcrel(false);
4837 reloc1.set_r_length(2);
4838 reloc1.set_r_extern(false);
4839 reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4840 reloc2.set_r_address(targetAddr >> 16);
4841 reloc2.set_r_symbolnum(0);
4842 reloc2.set_r_pcrel(false);
4843 reloc2.set_r_length(2);
4844 reloc2.set_r_extern(false);
4845 reloc2.set_r_type(PPC_RELOC_PAIR);
4846 fInternalRelocs.push_back(reloc1);
4847 fInternalRelocs.push_back(reloc2);
4848 atomSection->fHasTextLocalRelocs = true;
4849 return true;
4850 }
4851 break;
4852 case ppc::kAbsHigh16:
4853 case ppc::kAbsHigh16AddLow:
4854 if ( fSlideable ) {
4855 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4856 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
4857 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4858 reloc1.set_r_symbolnum(sectInfo->getIndex());
4859 reloc1.set_r_pcrel(false);
4860 reloc1.set_r_length(2);
4861 reloc1.set_r_extern(false);
4862 reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
4863 reloc2.set_r_address(targetAddr & 0xFFFF);
4864 reloc2.set_r_symbolnum(0);
4865 reloc2.set_r_pcrel(false);
4866 reloc2.set_r_length(2);
4867 reloc2.set_r_extern(false);
4868 reloc2.set_r_type(PPC_RELOC_PAIR);
4869 fInternalRelocs.push_back(reloc1);
4870 fInternalRelocs.push_back(reloc2);
4871 atomSection->fHasTextLocalRelocs = true;
4872 return true;
4873 }
4874 }
4875 break;
4876 case ObjectFile::Atom::kExternalDefinition:
4877 case ObjectFile::Atom::kExternalWeakDefinition:
4878 case ObjectFile::Atom::kAbsoluteSymbol:
4879 return false;
4880 }
4881 return false;
4882 }
4883
4884 template <>
4885 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4886 {
4887 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4888 switch ( ref.getTarget().getDefinitionKind() ) {
4889 case ObjectFile::Atom::kTentativeDefinition:
4890 case ObjectFile::Atom::kRegularDefinition:
4891 case ObjectFile::Atom::kWeakDefinition:
4892 // a reference to the absolute address of something in this same linkage unit can be
4893 // encoded as a local text reloc in a dylib or bundle
4894 if ( fSlideable ) {
4895 macho_relocation_info<P> reloc;
4896 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4897 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4898 reloc.set_r_symbolnum(sectInfo->getIndex());
4899 reloc.set_r_pcrel(false);
4900 reloc.set_r_length();
4901 reloc.set_r_extern(false);
4902 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4903 fInternalRelocs.push_back(reloc);
4904 atomSection->fHasTextLocalRelocs = true;
4905 return true;
4906 }
4907 return false;
4908 case ObjectFile::Atom::kExternalDefinition:
4909 case ObjectFile::Atom::kExternalWeakDefinition:
4910 case ObjectFile::Atom::kAbsoluteSymbol:
4911 return false;
4912 }
4913 }
4914 return false;
4915 }
4916
4917
4918 template <>
4919 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
4920 {
4921 // text relocs not supported (usually never needed because of RIP addressing)
4922 return false;
4923 }
4924
4925 template <>
4926 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
4927 {
4928 // text relocs not supported
4929 return false;
4930 }
4931
4932 template <>
4933 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4934 {
4935 if ( ref.getKind() == x86::kAbsolute32 ) {
4936 macho_relocation_info<P> reloc;
4937 switch ( ref.getTarget().getDefinitionKind() ) {
4938 case ObjectFile::Atom::kTentativeDefinition:
4939 case ObjectFile::Atom::kRegularDefinition:
4940 case ObjectFile::Atom::kWeakDefinition:
4941 return false;
4942 case ObjectFile::Atom::kExternalDefinition:
4943 case ObjectFile::Atom::kExternalWeakDefinition:
4944 // a reference to the absolute address of something in another linkage unit can be
4945 // encoded as an external text reloc in a dylib or bundle
4946 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4947 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4948 reloc.set_r_pcrel(false);
4949 reloc.set_r_length();
4950 reloc.set_r_extern(true);
4951 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4952 fExternalRelocs.push_back(reloc);
4953 atomSection->fHasTextExternalRelocs = true;
4954 return true;
4955 case ObjectFile::Atom::kAbsoluteSymbol:
4956 return false;
4957 }
4958 }
4959 return false;
4960 }
4961
4962 template <>
4963 bool Writer<x86_64>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4964 {
4965 if ( fOptions.outputKind() == Options::kKextBundle ) {
4966 macho_relocation_info<P> reloc;
4967 switch ( ref.getTarget().getDefinitionKind() ) {
4968 case ObjectFile::Atom::kTentativeDefinition:
4969 case ObjectFile::Atom::kRegularDefinition:
4970 case ObjectFile::Atom::kWeakDefinition:
4971 case ObjectFile::Atom::kAbsoluteSymbol:
4972 return false;
4973 case ObjectFile::Atom::kExternalDefinition:
4974 case ObjectFile::Atom::kExternalWeakDefinition:
4975 switch ( ref.getKind() ) {
4976 case x86_64::kBranchPCRel32:
4977 case x86_64::kBranchPCRel32WeakImport:
4978 // a branch to something in another linkage unit is
4979 // encoded as an external text reloc in a kext bundle
4980 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4981 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4982 reloc.set_r_pcrel(true);
4983 reloc.set_r_length(2);
4984 reloc.set_r_extern(true);
4985 reloc.set_r_type(X86_64_RELOC_BRANCH);
4986 fExternalRelocs.push_back(reloc);
4987 atomSection->fHasTextExternalRelocs = true;
4988 return true;
4989 case x86_64::kPCRel32GOTLoad:
4990 case x86_64::kPCRel32GOTLoadWeakImport:
4991 // a load of the GOT entry for a symbol in another linkage unit is
4992 // encoded as an external text reloc in a kext bundle
4993 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4994 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4995 reloc.set_r_pcrel(true);
4996 reloc.set_r_length(2);
4997 reloc.set_r_extern(true);
4998 reloc.set_r_type(X86_64_RELOC_GOT_LOAD);
4999 fExternalRelocs.push_back(reloc);
5000 atomSection->fHasTextExternalRelocs = true;
5001 return true;
5002 case x86_64::kPCRel32GOT:
5003 case x86_64::kPCRel32GOTWeakImport:
5004 // a use of the GOT entry for a symbol in another linkage unit is
5005 // encoded as an external text reloc in a kext bundle
5006 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
5007 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
5008 reloc.set_r_pcrel(true);
5009 reloc.set_r_length(2);
5010 reloc.set_r_extern(true);
5011 reloc.set_r_type(X86_64_RELOC_GOT);
5012 fExternalRelocs.push_back(reloc);
5013 atomSection->fHasTextExternalRelocs = true;
5014 return true;
5015 }
5016 break;
5017 }
5018 }
5019 return false;
5020 }
5021
5022
5023 template <typename A>
5024 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5025 {
5026 return false;
5027 }
5028
5029
5030
5031
5032 template <typename A>
5033 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
5034 {
5035 switch ( target.getDefinitionKind() ) {
5036 case ObjectFile::Atom::kTentativeDefinition:
5037 case ObjectFile::Atom::kRegularDefinition:
5038 // in main executables, the only way regular symbols are indirected is if -interposable is used
5039 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
5040 if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
5041 return kRelocExternal;
5042 else if ( fSlideable )
5043 return kRelocInternal;
5044 else
5045 return kRelocNone;
5046 }
5047 // for flat-namespace or interposable two-level-namespace
5048 // all references to exported symbols get indirected
5049 else if ( this->shouldExport(target) &&
5050 ((fOptions.nameSpace() == Options::kFlatNameSpace)
5051 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
5052 || fOptions.interposable(target.getName()))
5053 && (target.getName() != NULL)
5054 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
5055 return kRelocExternal;
5056 else if ( fSlideable )
5057 return kRelocInternal;
5058 else
5059 return kRelocNone;
5060 case ObjectFile::Atom::kWeakDefinition:
5061 // all calls to global weak definitions get indirected
5062 if ( this->shouldExport(target) )
5063 return kRelocExternal;
5064 else if ( fSlideable )
5065 return kRelocInternal;
5066 else
5067 return kRelocNone;
5068 case ObjectFile::Atom::kExternalDefinition:
5069 case ObjectFile::Atom::kExternalWeakDefinition:
5070 return kRelocExternal;
5071 case ObjectFile::Atom::kAbsoluteSymbol:
5072 return kRelocNone;
5073 }
5074 return kRelocNone;
5075 }
5076
5077 template <typename A>
5078 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5079 {
5080 // for 32-bit architectures, the r_address field in relocs
5081 // for final linked images is the offset from the first segment
5082 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
5083 if ( fOptions.outputKind() == Options::kPreload ) {
5084 // kPreload uses a virtual __HEADER segment to cover the load commands
5085 result = address - fSegmentInfos[1]->fBaseAddress;
5086 }
5087 // or the offset from the first writable segment if built split-seg
5088 if ( fOptions.splitSeg() )
5089 result = address - fFirstWritableSegment->fBaseAddress;
5090 if ( result > 0x7FFFFFFF ) {
5091 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
5092 atom->getDisplayName(), atom->getFile()->getPath());
5093 }
5094 return result;
5095 }
5096
5097 template <>
5098 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5099 {
5100 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
5101 // the 10.5 dyld, iterprets the r_address as:
5102 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
5103 // 2) an offset from the base address of the first writable segment
5104 // For dyld, r_address is always the offset from the base address
5105 uint64_t result;
5106 bool badFor10_4 = false;
5107 if ( fWritableSegmentPastFirst4GB ) {
5108 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
5109 badFor10_4 = true;
5110 result = address - fFirstWritableSegment->fBaseAddress;
5111 if ( result > 0xFFFFFFFF ) {
5112 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
5113 atom->getDisplayName(), atom->getFile()->getPath());
5114 }
5115 }
5116 else {
5117 result = address - fSegmentInfos[0]->fBaseAddress;
5118 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
5119 badFor10_4 = true;
5120 }
5121 if ( badFor10_4 ) {
5122 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",
5123 atom->getDisplayName(), atom->getFile()->getPath());
5124 }
5125 return result;
5126 }
5127
5128
5129 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
5130 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5131 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
5132 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5133 template <> bool Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
5134
5135 template <typename A>
5136 void Writer<A>::buildExecutableFixups()
5137 {
5138 if ( fIndirectTableAtom != NULL )
5139 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
5140 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
5141 const int segCount = segmentInfos.size();
5142 for(int i=0; i < segCount; ++i) {
5143 SegmentInfo* curSegment = segmentInfos[i];
5144 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5145 const int sectionCount = sectionInfos.size();
5146 for(int j=0; j < sectionCount; ++j) {
5147 SectionInfo* curSection = sectionInfos[j];
5148 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
5149 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5150 if ( ! curSection->fAllZeroFill ) {
5151 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers
5152 || curSection->fAllStubs || curSection->fAllSelfModifyingStubs ) {
5153 if ( fIndirectTableAtom != NULL )
5154 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
5155 }
5156 const int atomCount = sectionAtoms.size();
5157 for (int k=0; k < atomCount; ++k) {
5158 ObjectFile::Atom* atom = sectionAtoms[k];
5159 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
5160 const int refCount = refs.size();
5161 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
5162 if ( curSection->fAllNonLazyPointers && (refCount == 0) ) {
5163 // handle imageloadercache GOT slot
5164 uint32_t offsetInSection = atom->getSectionOffset();
5165 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5166 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5167 // use INDIRECT_SYMBOL_ABS so 10.5 dyld will leave value as zero
5168 IndirectEntry entry = { indirectTableIndex, INDIRECT_SYMBOL_ABS };
5169 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5170 // indirectTableIndex, INDIRECT_SYMBOL_LOCAL, curSection->fSectionName);
5171 fIndirectTableAtom->fTable.push_back(entry);
5172 }
5173 for (int l=0; l < refCount; ++l) {
5174 ObjectFile::Reference* ref = refs[l];
5175 if ( (fOptions.outputKind() != Options::kKextBundle) &&
5176 (curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers) ) {
5177 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
5178 if ( atom->getSize() != sizeof(pint_t) ) {
5179 warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
5180 }
5181 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
5182 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5183 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
5184 }
5185 uint32_t offsetInSection = atom->getSectionOffset();
5186 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5187 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
5188 if (atom == fFastStubGOTAtom)
5189 undefinedSymbolIndex = INDIRECT_SYMBOL_ABS;
5190 else if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
5191 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
5192 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5193 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5194 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5195 // indirectTableIndex, undefinedSymbolIndex, curSection->fSectionName);
5196 fIndirectTableAtom->fTable.push_back(entry);
5197 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5198 uint8_t preboundLazyType;
5199 if ( fOptions.prebind() && (fDyldClassicHelperAtom != NULL)
5200 && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
5201 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
5202 macho_scattered_relocation_info<P> pblaReloc;
5203 pblaReloc.set_r_scattered(true);
5204 pblaReloc.set_r_pcrel(false);
5205 pblaReloc.set_r_length();
5206 pblaReloc.set_r_type(preboundLazyType);
5207 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5208 pblaReloc.set_r_value(fDyldClassicHelperAtom->getAddress());
5209 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
5210 }
5211 else if ( fSlideable ) {
5212 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
5213 macho_relocation_info<P> dyldHelperReloc;
5214 uint32_t sectionNum = 1;
5215 if ( fDyldClassicHelperAtom != NULL )
5216 sectionNum = ((SectionInfo*)(fDyldClassicHelperAtom->getSection()))->getIndex();
5217 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
5218 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5219 dyldHelperReloc.set_r_symbolnum(sectionNum);
5220 dyldHelperReloc.set_r_pcrel(false);
5221 dyldHelperReloc.set_r_length();
5222 dyldHelperReloc.set_r_extern(false);
5223 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
5224 fInternalRelocs.push_back(dyldHelperReloc);
5225 if ( fOptions.makeCompressedDyldInfo() ) {
5226 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5227 }
5228 }
5229 if ( fOptions.makeCompressedDyldInfo() ) {
5230 uint8_t type = BIND_TYPE_POINTER;
5231 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5232 if ( pointerTarget->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5233 // This is a referece to a weak def in some dylib (e.g. operator new)
5234 // need to bind into to directly bind this
5235 // later weak binding info may override
5236 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5237 fBindingInfo.push_back(BindingInfo(type, ordinal, pointerTarget->getName(), false, addresss, 0));
5238 }
5239 if ( targetRequiresWeakBinding(*pointerTarget) ) {
5240 // note: lazy pointers to weak symbols are not bound lazily
5241 fWeakBindingInfo.push_back(BindingInfo(type, pointerTarget->getName(), false, addresss, 0));
5242 }
5243 }
5244 }
5245 if ( curSection->fAllNonLazyPointers && fOptions.makeCompressedDyldInfo() ) {
5246 if ( pointerTarget != NULL ) {
5247 switch ( this->relocationNeededInFinalLinkedImage(*pointerTarget) ) {
5248 case kRelocNone:
5249 // no rebase or binding info needed
5250 break;
5251 case kRelocInternal:
5252 // a non-lazy pointer that has been optimized to LOCAL needs rebasing info
5253 // but not the magic fFastStubGOTAtom atom
5254 if (atom != fFastStubGOTAtom)
5255 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5256 break;
5257 case kRelocExternal:
5258 {
5259 uint8_t type = BIND_TYPE_POINTER;
5260 uint64_t addresss = atom->getAddress();
5261 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5262 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, 0));
5263 // if this is a non-lazy pointer to a weak definition within this linkage unit
5264 // the pointer needs to initially point within linkage unit and have
5265 // rebase command to slide it.
5266 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5267 // unless if this is a hybrid format, in which case the non-lazy pointer
5268 // is zero on disk. So use a bind instead of a rebase to set initial value
5269 if ( fOptions.makeClassicDyldInfo() )
5270 fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, 0));
5271 else
5272 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5273 }
5274 // if this is a non-lazy pointer to a weak definition in a dylib,
5275 // the pointer needs to initially bind to the dylib
5276 else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5277 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5278 fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, pointerTarget->getName(), false, addresss, 0));
5279 }
5280 }
5281 else {
5282 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5283 bool weak_import = fWeakImportMap[pointerTarget];
5284 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, 0));
5285 }
5286 }
5287 }
5288 }
5289 }
5290 }
5291 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
5292 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
5293 if ( fOptions.allowTextRelocs() ) {
5294 if ( fOptions.warnAboutTextRelocs() )
5295 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5296 }
5297 else {
5298 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
5299 atom->getDisplayName(), atom->getFile()->getPath());
5300 }
5301 }
5302 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
5303 case kRelocNone:
5304 // no reloc needed
5305 break;
5306 case kRelocInternal:
5307 {
5308 macho_relocation_info<P> internalReloc;
5309 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
5310 uint32_t sectionNum = sectInfo->getIndex();
5311 // special case _mh_dylib_header and friends which are not in any real section
5312 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
5313 sectionNum = 1;
5314 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5315 internalReloc.set_r_symbolnum(sectionNum);
5316 internalReloc.set_r_pcrel(false);
5317 internalReloc.set_r_length();
5318 internalReloc.set_r_extern(false);
5319 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5320 fInternalRelocs.push_back(internalReloc);
5321 if ( fOptions.makeCompressedDyldInfo() ) {
5322 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, atom->getAddress() + ref->getFixUpOffset()));
5323 }
5324 }
5325 break;
5326 case kRelocExternal:
5327 {
5328 macho_relocation_info<P> externalReloc;
5329 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5330 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
5331 externalReloc.set_r_pcrel(false);
5332 externalReloc.set_r_length();
5333 externalReloc.set_r_extern(true);
5334 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5335 fExternalRelocs.push_back(externalReloc);
5336 if ( fOptions.makeCompressedDyldInfo() ) {
5337 int64_t addend = ref->getTargetOffset();
5338 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5339 if ( !fOptions.makeClassicDyldInfo() ) {
5340 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5341 // pointers to internal weak defs need a rebase
5342 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, addresss));
5343 }
5344 }
5345 uint8_t type = BIND_TYPE_POINTER;
5346 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5347 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, addend));
5348 if ( fOptions.makeClassicDyldInfo() && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
5349 // hybrid linkedit puts addend in data, so we need bind phase to reset pointer to local definifion
5350 fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, addend));
5351 }
5352 // if this is a pointer to a weak definition in a dylib,
5353 // the pointer needs to initially bind to the dylib
5354 else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5355 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5356 fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, ref->getTarget().getName(), false, addresss, addend));
5357 }
5358 }
5359 else {
5360 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5361 bool weak_import = fWeakImportMap[&(ref->getTarget())];
5362 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, addend));
5363 }
5364 }
5365 }
5366 break;
5367 }
5368 }
5369 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
5370 // new x86 stubs always require text relocs
5371 if ( curSection->fAllStubs || curSection->fAllStubHelpers ) {
5372 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5373 // relocs added to fInternalRelocs
5374 }
5375 }
5376 else if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
5377 if ( fOptions.warnAboutTextRelocs() )
5378 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5379 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5380 // relocs added to fInternalRelocs
5381 }
5382 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
5383 // relocs added to fExternalRelocs
5384 }
5385 else {
5386 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
5387 }
5388 }
5389 else {
5390 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
5391 "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
5392 }
5393 }
5394 }
5395 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
5396 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
5397 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
5398 uint32_t offsetInSection = atom->getSectionOffset();
5399 uint32_t indexInSection = offsetInSection / atom->getSize();
5400 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5401 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5402 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
5403 fIndirectTableAtom->fTable.push_back(entry);
5404 }
5405 }
5406 }
5407 }
5408 }
5409 if ( fSplitCodeToDataContentAtom != NULL )
5410 fSplitCodeToDataContentAtom->encode();
5411 if ( fCompressedRebaseInfoAtom != NULL )
5412 fCompressedRebaseInfoAtom->encode();
5413 if ( fCompressedBindingInfoAtom != NULL )
5414 fCompressedBindingInfoAtom->encode();
5415 if ( fCompressedWeakBindingInfoAtom != NULL )
5416 fCompressedWeakBindingInfoAtom->encode();
5417 if ( fCompressedLazyBindingInfoAtom != NULL )
5418 fCompressedLazyBindingInfoAtom->encode();
5419 if ( fCompressedExportInfoAtom != NULL )
5420 fCompressedExportInfoAtom->encode();
5421 }
5422
5423
5424 template <>
5425 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5426 {
5427 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
5428 case ppc::kPICBaseHigh16:
5429 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5430 break;
5431 case ppc::kPointerDiff32:
5432 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5433 break;
5434 case ppc::kPointerDiff64:
5435 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5436 break;
5437 case ppc::kNoFixUp:
5438 case ppc::kGroupSubordinate:
5439 case ppc::kPointer:
5440 case ppc::kPointerWeakImport:
5441 case ppc::kPICBaseLow16:
5442 case ppc::kPICBaseLow14:
5443 // ignore
5444 break;
5445 default:
5446 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5447 fSplitCodeToDataContentAtom->setCantEncode();
5448 }
5449 }
5450
5451 template <>
5452 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5453 {
5454 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
5455 case ppc64::kPICBaseHigh16:
5456 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5457 break;
5458 case ppc64::kPointerDiff32:
5459 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5460 break;
5461 case ppc64::kPointerDiff64:
5462 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5463 break;
5464 case ppc64::kNoFixUp:
5465 case ppc64::kGroupSubordinate:
5466 case ppc64::kPointer:
5467 case ppc64::kPointerWeakImport:
5468 case ppc64::kPICBaseLow16:
5469 case ppc64::kPICBaseLow14:
5470 // ignore
5471 break;
5472 default:
5473 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5474 fSplitCodeToDataContentAtom->setCantEncode();
5475 }
5476 }
5477
5478 template <>
5479 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5480 {
5481 switch ( (x86::ReferenceKinds)ref->getKind() ) {
5482 case x86::kPointerDiff:
5483 case x86::kImageOffset32:
5484 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
5485 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5486 else
5487 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5488 break;
5489 case x86::kNoFixUp:
5490 case x86::kGroupSubordinate:
5491 case x86::kPointer:
5492 case x86::kPointerWeakImport:
5493 // ignore
5494 break;
5495 case x86::kPCRel32:
5496 case x86::kPCRel32WeakImport:
5497 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
5498 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
5499 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5500 break;
5501 }
5502 // fall into warning case
5503 default:
5504 if ( fOptions.makeCompressedDyldInfo() && (ref->getKind() == x86::kAbsolute32) ) {
5505 // will be encoded in rebase info
5506 }
5507 else {
5508 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
5509 fSplitCodeToDataContentAtom->setCantEncode();
5510 }
5511 }
5512 }
5513
5514 template <>
5515 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5516 {
5517 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
5518 case x86_64::kPCRel32:
5519 case x86_64::kPCRel32_1:
5520 case x86_64::kPCRel32_2:
5521 case x86_64::kPCRel32_4:
5522 case x86_64::kPCRel32GOTLoad:
5523 case x86_64::kPCRel32GOTLoadWeakImport:
5524 case x86_64::kPCRel32GOT:
5525 case x86_64::kPCRel32GOTWeakImport:
5526 case x86_64::kPointerDiff32:
5527 case x86_64::kImageOffset32:
5528 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5529 break;
5530 case x86_64::kPointerDiff:
5531 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5532 break;
5533 case x86_64::kNoFixUp:
5534 case x86_64::kGroupSubordinate:
5535 case x86_64::kPointer:
5536 case x86_64::kGOTNoFixUp:
5537 // ignore
5538 break;
5539 default:
5540 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
5541 fSplitCodeToDataContentAtom->setCantEncode();
5542 }
5543 }
5544
5545 template <>
5546 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5547 {
5548 switch ( (arm::ReferenceKinds)ref->getKind() ) {
5549 case arm::kPointerDiff:
5550 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5551 break;
5552 case arm::kNoFixUp:
5553 case arm::kGroupSubordinate:
5554 case arm::kPointer:
5555 case arm::kPointerWeakImport:
5556 case arm::kReadOnlyPointer:
5557 // ignore
5558 break;
5559 default:
5560 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
5561 fSplitCodeToDataContentAtom->setCantEncode();
5562 }
5563 }
5564
5565 template <typename A>
5566 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
5567 {
5568 switch ( to.getDefinitionKind() ) {
5569 case ObjectFile::Atom::kExternalDefinition:
5570 case ObjectFile::Atom::kExternalWeakDefinition:
5571 case ObjectFile::Atom::kAbsoluteSymbol:
5572 return false;
5573 case ObjectFile::Atom::kRegularDefinition:
5574 case ObjectFile::Atom::kWeakDefinition:
5575 case ObjectFile::Atom::kTentativeDefinition:
5576 // segments with same permissions slide together
5577 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
5578 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
5579 }
5580 throw "ld64 internal error";
5581 }
5582
5583
5584 template <>
5585 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
5586 {
5587 uint32_t ppcNop;
5588 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5589 for (uint32_t p=from; p < to; p += 4)
5590 ::pwrite(fd, &ppcNop, 4, p);
5591 }
5592
5593 template <>
5594 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5595 {
5596 uint32_t ppcNop;
5597 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5598 for (uint32_t p=from; p < to; p += 4)
5599 ::pwrite(fd, &ppcNop, 4, p);
5600 }
5601
5602 template <>
5603 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
5604 {
5605 uint8_t x86Nop = 0x90;
5606 for (uint32_t p=from; p < to; ++p)
5607 ::pwrite(fd, &x86Nop, 1, p);
5608 }
5609
5610 template <>
5611 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5612 {
5613 uint8_t x86Nop = 0x90;
5614 for (uint32_t p=from; p < to; ++p)
5615 ::pwrite(fd, &x86Nop, 1, p);
5616 }
5617
5618 template <>
5619 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
5620 {
5621 // FIXME: need thumb nop?
5622 uint32_t armNop;
5623 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
5624 for (uint32_t p=from; p < to; p += 4)
5625 ::pwrite(fd, &armNop, 4, p);
5626 }
5627
5628 template <>
5629 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
5630 {
5631 for (uint8_t* p=from; p < to; p += 4)
5632 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5633 }
5634
5635 template <>
5636 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
5637 {
5638 for (uint8_t* p=from; p < to; p += 4)
5639 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5640 }
5641
5642 template <>
5643 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
5644 {
5645 for (uint8_t* p=from; p < to; ++p)
5646 *p = 0x90;
5647 }
5648
5649 template <>
5650 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
5651 {
5652 for (uint8_t* p=from; p < to; ++p)
5653 *p = 0x90;
5654 }
5655
5656 template <>
5657 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
5658 {
5659 // fixme: need thumb nop?
5660 for (uint8_t* p=from; p < to; p += 4)
5661 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
5662 }
5663
5664 static const char* stringName(const char* str)
5665 {
5666 if ( strncmp(str, "cstring=", 8) == 0) {
5667 static char buffer[1024];
5668 char* t = buffer;
5669 *t++ = '\"';
5670 for(const char*s = &str[8]; *s != '\0'; ++s) {
5671 switch(*s) {
5672 case '\n':
5673 *t++ = '\\';
5674 *t++ = 'n';
5675 break;
5676 case '\t':
5677 *t++ = '\\';
5678 *t++ = 't';
5679 break;
5680 default:
5681 *t++ = *s;
5682 break;
5683 }
5684 if ( t > &buffer[1020] ) {
5685 *t++= '\"';
5686 *t++= '.';
5687 *t++= '.';
5688 *t++= '.';
5689 *t++= '\0';
5690 return buffer;
5691 }
5692 }
5693 *t++= '\"';
5694 *t++= '\0';
5695 return buffer;
5696 }
5697 else {
5698 return str;
5699 }
5700 }
5701
5702
5703 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
5704 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
5705 template <> const char* Writer<x86>::getArchString() { return "i386"; }
5706 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
5707 template <> const char* Writer<arm>::getArchString() { return "arm"; }
5708
5709 template <typename A>
5710 void Writer<A>::writeMap()
5711 {
5712 if ( fOptions.generatedMapPath() != NULL ) {
5713 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
5714 if ( mapFile != NULL ) {
5715 // write output path
5716 fprintf(mapFile, "# Path: %s\n", fFilePath);
5717 // write output architecure
5718 fprintf(mapFile, "# Arch: %s\n", getArchString());
5719 // write UUID
5720 if ( fUUIDAtom != NULL ) {
5721 const uint8_t* uuid = fUUIDAtom->getUUID();
5722 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
5723 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
5724 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
5725 }
5726 // write table of object files
5727 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
5728 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
5729 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
5730 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5731 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5732 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5733 if ( ! (*secit)->fVirtualSection ) {
5734 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5735 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5736 ObjectFile::Reader* reader = (*ait)->getFile();
5737 uint32_t readerOrdinal = (*ait)->getOrdinal();
5738 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
5739 if ( pos == readerToOrdinal.end() ) {
5740 readerToOrdinal[reader] = readerOrdinal;
5741 ordinalToReader[readerOrdinal] = reader;
5742 }
5743 }
5744 }
5745 }
5746 }
5747 fprintf(mapFile, "# Object files:\n");
5748 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
5749 uint32_t fileIndex = 0;
5750 readerToFileOrdinal[this] = fileIndex++;
5751 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
5752 if ( it->first != 0 ) {
5753 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
5754 readerToFileOrdinal[it->second] = fileIndex++;
5755 }
5756 }
5757 // write table of sections
5758 fprintf(mapFile, "# Sections:\n");
5759 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
5760 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5761 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5762 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5763 if ( ! (*secit)->fVirtualSection ) {
5764 SectionInfo* sect = *secit;
5765 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
5766 (*segit)->fName, sect->fSectionName);
5767 }
5768 }
5769 }
5770 // write table of symbols
5771 fprintf(mapFile, "# Symbols:\n");
5772 fprintf(mapFile, "# Address\tSize \tFile Name\n");
5773 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5774 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5775 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5776 if ( ! (*secit)->fVirtualSection ) {
5777 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5778 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
5779 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5780 ObjectFile::Atom* atom = *ait;
5781 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
5782 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
5783 }
5784 }
5785 }
5786 }
5787 fclose(mapFile);
5788 }
5789 else {
5790 warning("could not write map file: %s\n", fOptions.generatedMapPath());
5791 }
5792 }
5793 }
5794
5795 static const char* sCleanupFile = NULL;
5796 static void cleanup(int sig)
5797 {
5798 ::signal(sig, SIG_DFL);
5799 if ( sCleanupFile != NULL ) {
5800 ::unlink(sCleanupFile);
5801 }
5802 if ( sig == SIGINT )
5803 ::exit(1);
5804 }
5805
5806
5807 template <typename A>
5808 uint64_t Writer<A>::writeAtoms()
5809 {
5810 // for UNIX conformance, error if file exists and is not writable
5811 if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
5812 throwf("can't write output file: %s", fFilePath);
5813
5814 int permissions = 0777;
5815 if ( fOptions.outputKind() == Options::kObjectFile )
5816 permissions = 0666;
5817 // Calling unlink first assures the file is gone so that open creates it with correct permissions
5818 // It also handles the case where fFilePath file is not writable but its directory is
5819 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
5820 (void)unlink(fFilePath);
5821
5822 // try to allocate buffer for entire output file content
5823 int fd = -1;
5824 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
5825 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
5826 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
5827 uint8_t* atomBuffer = NULL;
5828 bool streaming = false;
5829 if ( wholeBuffer == NULL ) {
5830 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
5831 if ( fd == -1 )
5832 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
5833 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
5834 streaming = true;
5835 // install signal handlers to delete output file if program is killed
5836 sCleanupFile = fFilePath;
5837 ::signal(SIGINT, cleanup);
5838 ::signal(SIGBUS, cleanup);
5839 ::signal(SIGSEGV, cleanup);
5840 }
5841 uint32_t size = 0;
5842 uint32_t end = 0;
5843 try {
5844 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5845 SegmentInfo* curSegment = *segit;
5846 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5847 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5848 SectionInfo* curSection = *secit;
5849 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5850 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
5851 //fprintf(stderr, "writing %lu atoms for section %p %s at file offset 0x%08llX\n", sectionAtoms.size(), curSection, curSection->fSectionName, curSection->fFileOffset);
5852 if ( ! curSection->fAllZeroFill ) {
5853 bool needsNops = ((strcmp(curSection->fSegmentName, "__TEXT") == 0) && (strncmp(curSection->fSectionName, "__text", 6) == 0));
5854 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5855 ObjectFile::Atom* atom = *ait;
5856 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
5857 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
5858 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
5859 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
5860 if ( fileOffset != end ) {
5861 //fprintf(stderr, "writing %d pad bytes, needsNops=%d\n", fileOffset-end, needsNops);
5862 if ( needsNops ) {
5863 // fill gaps with no-ops
5864 if ( streaming )
5865 writeNoOps(fd, end, fileOffset);
5866 else
5867 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
5868 }
5869 else if ( streaming ) {
5870 // zero fill gaps
5871 if ( (fileOffset-end) == 4 ) {
5872 uint32_t zero = 0;
5873 ::pwrite(fd, &zero, 4, end);
5874 }
5875 else {
5876 uint8_t zero = 0x00;
5877 for (uint32_t p=end; p < fileOffset; ++p)
5878 ::pwrite(fd, &zero, 1, p);
5879 }
5880 }
5881 }
5882 uint64_t atomSize = atom->getSize();
5883 if ( streaming ) {
5884 if ( atomSize > fLargestAtomSize )
5885 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
5886 atom->getDisplayName(), atomSize, fLargestAtomSize);
5887 }
5888 else {
5889 if ( fileOffset > fileBufferSize )
5890 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
5891 atom->getDisplayName(), fileOffset, fileBufferSize);
5892 }
5893 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
5894 end = fileOffset+atomSize;
5895 // copy raw bytes
5896 atom->copyRawContent(buffer);
5897 // apply any fix-ups
5898 try {
5899 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5900 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
5901 ObjectFile::Reference* ref = *it;
5902 if ( fOptions.outputKind() == Options::kObjectFile ) {
5903 // doing ld -r
5904 // skip fix-ups for undefined targets
5905 if ( &(ref->getTarget()) != NULL )
5906 this->fixUpReferenceRelocatable(ref, atom, buffer);
5907 }
5908 else {
5909 // producing final linked image
5910 this->fixUpReferenceFinal(ref, atom, buffer);
5911 }
5912 }
5913 }
5914 catch (const char* msg) {
5915 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
5916 }
5917 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %p %s from %s\n",
5918 // fileOffset, end, atom->getAddress(), atom->getSize(), atom, atom->getDisplayName(), atom->getFile()->getPath());
5919 if ( streaming ) {
5920 // write out
5921 ::pwrite(fd, buffer, atomSize, fileOffset);
5922 }
5923 else {
5924 if ( (fileOffset + atomSize) > size )
5925 size = fileOffset + atomSize;
5926 }
5927 }
5928 }
5929 }
5930 }
5931 }
5932
5933 // update content based UUID
5934 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
5935 uint8_t digest[CC_MD5_DIGEST_LENGTH];
5936 if ( streaming ) {
5937 // if output file file did not fit in memory, re-read file to generate md5 hash
5938 uint32_t kMD5BufferSize = 16*1024;
5939 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
5940 if ( md5Buffer != NULL ) {
5941 CC_MD5_CTX md5State;
5942 CC_MD5_Init(&md5State);
5943 ::lseek(fd, 0, SEEK_SET);
5944 ssize_t len;
5945 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
5946 CC_MD5_Update(&md5State, md5Buffer, len);
5947 CC_MD5_Final(digest, &md5State);
5948 ::free(md5Buffer);
5949 }
5950 else {
5951 // if malloc fails, fall back to random uuid
5952 ::uuid_generate_random(digest);
5953 }
5954 fUUIDAtom->setContent(digest);
5955 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
5956 fUUIDAtom->copyRawContent(atomBuffer);
5957 ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
5958 }
5959 else {
5960 // if output file fit in memory, just genrate an md5 hash in memory
5961 #if 1
5962 // temp hack for building on Tiger
5963 CC_MD5_CTX md5State;
5964 CC_MD5_Init(&md5State);
5965 CC_MD5_Update(&md5State, wholeBuffer, size);
5966 CC_MD5_Final(digest, &md5State);
5967 #else
5968 CC_MD5(wholeBuffer, size, digest);
5969 #endif
5970 fUUIDAtom->setContent(digest);
5971 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
5972 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
5973 }
5974 }
5975 }
5976 catch (...) {
5977 if ( sCleanupFile != NULL )
5978 ::unlink(sCleanupFile);
5979 throw;
5980 }
5981
5982 // finish up
5983 if ( streaming ) {
5984 delete [] atomBuffer;
5985 close(fd);
5986 // restore default signal handlers
5987 sCleanupFile = NULL;
5988 ::signal(SIGINT, SIG_DFL);
5989 ::signal(SIGBUS, SIG_DFL);
5990 ::signal(SIGSEGV, SIG_DFL);
5991 }
5992 else {
5993 // write whole output file in one chunk
5994 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
5995 if ( fd == -1 )
5996 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
5997 ::pwrite(fd, wholeBuffer, size, 0);
5998 close(fd);
5999 delete [] wholeBuffer;
6000 }
6001
6002 return end;
6003 }
6004
6005 template <>
6006 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6007 {
6008 int64_t displacement;
6009 int64_t baseAddr;
6010 uint32_t instruction;
6011 uint32_t newInstruction;
6012 uint64_t targetAddr = 0;
6013 uint32_t firstDisp;
6014 uint32_t nextDisp;
6015 uint32_t opcode = 0;
6016 bool relocateableExternal = false;
6017 bool is_bl;
6018 bool is_blx;
6019 bool targetIsThumb;
6020
6021 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6022 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6023 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
6024 }
6025
6026 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6027 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6028 case arm::kNoFixUp:
6029 case arm::kFollowOn:
6030 case arm::kGroupSubordinate:
6031 // do nothing
6032 break;
6033 case arm::kPointerWeakImport:
6034 case arm::kPointer:
6035 // If this is the lazy pointers section, then set all lazy pointers to
6036 // point to the dyld stub binding helper.
6037 if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers
6038 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
6039 switch (ref->getTarget().getDefinitionKind()) {
6040 case ObjectFile::Atom::kExternalDefinition:
6041 case ObjectFile::Atom::kExternalWeakDefinition:
6042 // prebound lazy pointer to another dylib ==> pointer contains zero
6043 LittleEndian::set32(*fixUp, 0);
6044 break;
6045 case ObjectFile::Atom::kTentativeDefinition:
6046 case ObjectFile::Atom::kRegularDefinition:
6047 case ObjectFile::Atom::kWeakDefinition:
6048 case ObjectFile::Atom::kAbsoluteSymbol:
6049 // prebound lazy pointer to withing this dylib ==> pointer contains address
6050 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6051 targetAddr |= 1;
6052 LittleEndian::set32(*fixUp, targetAddr);
6053 break;
6054 }
6055 }
6056 else if ( relocateableExternal ) {
6057 if ( fOptions.prebind() ) {
6058 switch (ref->getTarget().getDefinitionKind()) {
6059 case ObjectFile::Atom::kExternalDefinition:
6060 case ObjectFile::Atom::kExternalWeakDefinition:
6061 // prebound external relocation ==> pointer contains addend
6062 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6063 break;
6064 case ObjectFile::Atom::kTentativeDefinition:
6065 case ObjectFile::Atom::kRegularDefinition:
6066 case ObjectFile::Atom::kWeakDefinition:
6067 // prebound external relocation to internal atom ==> pointer contains target address + addend
6068 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6069 targetAddr |= 1;
6070 LittleEndian::set32(*fixUp, targetAddr);
6071 break;
6072 case ObjectFile::Atom::kAbsoluteSymbol:
6073 break;
6074 }
6075 }
6076 else {
6077 // external relocation ==> pointer contains addend
6078 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6079 }
6080 }
6081 else {
6082 // pointer contains target address
6083 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6084 targetAddr |= 1;
6085 LittleEndian::set32(*fixUp, targetAddr);
6086 }
6087 break;
6088 case arm::kPointerDiff:
6089 LittleEndian::set32(*fixUp,
6090 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6091 break;
6092 case arm::kReadOnlyPointer:
6093 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6094 targetAddr |= 1;
6095 switch ( ref->getTarget().getDefinitionKind() ) {
6096 case ObjectFile::Atom::kRegularDefinition:
6097 case ObjectFile::Atom::kWeakDefinition:
6098 case ObjectFile::Atom::kTentativeDefinition:
6099 // pointer contains target address
6100 LittleEndian::set32(*fixUp, targetAddr);
6101 break;
6102 case ObjectFile::Atom::kExternalDefinition:
6103 case ObjectFile::Atom::kExternalWeakDefinition:
6104 // external relocation ==> pointer contains addend
6105 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6106 break;
6107 case ObjectFile::Atom::kAbsoluteSymbol:
6108 // pointer contains target address
6109 LittleEndian::set32(*fixUp, targetAddr);
6110 break;
6111 }
6112 break;
6113 case arm::kBranch24WeakImport:
6114 case arm::kBranch24:
6115 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6116 // The pc added will be +8 from the pc
6117 displacement -= 8;
6118 // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6119 // max positive displacement is 0x007FFFFF << 2
6120 // max negative displacement is 0xFF800000 << 2
6121 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6122 throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6123 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6124 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6125 }
6126 instruction = LittleEndian::get32(*fixUp);
6127 // Make sure we are calling arm with bl, thumb with blx
6128 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6129 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6130 if ( is_bl && ref->getTarget().isThumb() ) {
6131 uint32_t opcode = 0xFA000000;
6132 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6133 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6134 newInstruction = opcode | h_bit | disp;
6135 }
6136 else if ( is_blx && !ref->getTarget().isThumb() ) {
6137 uint32_t opcode = 0xEB000000;
6138 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6139 newInstruction = opcode | disp;
6140 }
6141 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6142 throwf("don't know how to convert instruction %x referencing %s to thumb",
6143 instruction, ref->getTarget().getDisplayName());
6144 }
6145 else {
6146 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6147 }
6148 LittleEndian::set32(*fixUp, newInstruction);
6149 break;
6150 case arm::kThumbBranch22WeakImport:
6151 case arm::kThumbBranch22:
6152 instruction = LittleEndian::get32(*fixUp);
6153 is_bl = ((instruction & 0xD000F800) == 0xD000F000);
6154 is_blx = ((instruction & 0xD000F800) == 0xC000F000);
6155 targetIsThumb = ref->getTarget().isThumb();
6156
6157 // The pc added will be +4 from the pc
6158 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6159 // If the target is not thumb, we will be generating a blx instruction
6160 // Since blx cannot have the low bit set, set bit[1] of the target to
6161 // bit[1] of the base address, so that the difference is a multiple of
6162 // 4 bytes.
6163 if ( !targetIsThumb ) {
6164 targetAddr &= -3ULL;
6165 targetAddr |= (baseAddr & 2LL);
6166 }
6167 displacement = targetAddr - baseAddr;
6168
6169 // max positive displacement is 0x003FFFFE
6170 // max negative displacement is 0xFFC00000
6171 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6172 // armv7 supports a larger displacement
6173 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6174 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6175 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6176 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6177 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6178 }
6179 else {
6180 // The instruction is really two instructions:
6181 // The lower 16 bits are the first instruction, which contains the high
6182 // 11 bits of the displacement.
6183 // The upper 16 bits are the second instruction, which contains the low
6184 // 11 bits of the displacement, as well as differentiating bl and blx.
6185 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6186 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6187 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6188 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6189 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6190 uint32_t j1 = (i1 == s);
6191 uint32_t j2 = (i2 == s);
6192 if ( is_bl ) {
6193 if ( targetIsThumb )
6194 opcode = 0xD000F000; // keep bl
6195 else
6196 opcode = 0xC000F000; // change to blx
6197 }
6198 else if ( is_blx ) {
6199 if ( targetIsThumb )
6200 opcode = 0xD000F000; // change to bl
6201 else
6202 opcode = 0xC000F000; // keep blx
6203 }
6204 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6205 throwf("don't know how to convert instruction %x referencing %s to arm",
6206 instruction, ref->getTarget().getDisplayName());
6207 }
6208 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6209 firstDisp = (s << 10) | imm10;
6210 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6211 //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
6212 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6213 LittleEndian::set32(*fixUp, newInstruction);
6214 }
6215 }
6216 else {
6217 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6218 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6219 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6220 }
6221 }
6222 else {
6223 // The instruction is really two instructions:
6224 // The lower 16 bits are the first instruction, which contains the high
6225 // 11 bits of the displacement.
6226 // The upper 16 bits are the second instruction, which contains the low
6227 // 11 bits of the displacement, as well as differentiating bl and blx.
6228 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6229 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6230 if ( is_bl && !targetIsThumb ) {
6231 opcode = 0xE800F000;
6232 }
6233 else if ( is_blx && targetIsThumb ) {
6234 opcode = 0xF800F000;
6235 }
6236 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6237 throwf("don't know how to convert instruction %x referencing %s to arm",
6238 instruction, ref->getTarget().getDisplayName());
6239 }
6240 else {
6241 opcode = instruction & 0xF800F800;
6242 }
6243 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6244 LittleEndian::set32(*fixUp, newInstruction);
6245 }
6246 break;
6247 case arm::kDtraceProbeSite:
6248 if ( inAtom->isThumb() ) {
6249 // change 32-bit blx call site to two thumb NOPs
6250 LittleEndian::set32(*fixUp, 0x46C046C0);
6251 }
6252 else {
6253 // change call site to a NOP
6254 LittleEndian::set32(*fixUp, 0xE1A00000);
6255 }
6256 break;
6257 case arm::kDtraceIsEnabledSite:
6258 if ( inAtom->isThumb() ) {
6259 // change 32-bit blx call site to 'nop', 'eor r0, r0'
6260 LittleEndian::set32(*fixUp, 0x46C04040);
6261 }
6262 else {
6263 // change call site to 'eor r0, r0, r0'
6264 LittleEndian::set32(*fixUp, 0xE0200000);
6265 }
6266 break;
6267 case arm::kDtraceTypeReference:
6268 case arm::kDtraceProbe:
6269 // nothing to fix up
6270 break;
6271 default:
6272 throw "boom shaka laka";
6273 }
6274 }
6275
6276 template <>
6277 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6278 {
6279 int64_t displacement;
6280 uint32_t instruction;
6281 uint32_t newInstruction;
6282 uint64_t targetAddr = 0;
6283 int64_t baseAddr;
6284 uint32_t firstDisp;
6285 uint32_t nextDisp;
6286 uint32_t opcode = 0;
6287 bool relocateableExternal = false;
6288 bool is_bl;
6289 bool is_blx;
6290 bool targetIsThumb;
6291
6292 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6293 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6294 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
6295 }
6296
6297 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6298 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6299 case arm::kNoFixUp:
6300 case arm::kFollowOn:
6301 case arm::kGroupSubordinate:
6302 // do nothing
6303 break;
6304 case arm::kPointer:
6305 case arm::kReadOnlyPointer:
6306 case arm::kPointerWeakImport:
6307 {
6308 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6309 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
6310 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6311 LittleEndian::set32(*fixUp, targetAddr);
6312 else
6313 LittleEndian::set32(*fixUp, 0);
6314 }
6315 else if ( relocateableExternal ) {
6316 if ( fOptions.prebind() ) {
6317 switch (ref->getTarget().getDefinitionKind()) {
6318 case ObjectFile::Atom::kExternalDefinition:
6319 case ObjectFile::Atom::kExternalWeakDefinition:
6320 // prebound external relocation ==> pointer contains addend
6321 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6322 break;
6323 case ObjectFile::Atom::kTentativeDefinition:
6324 case ObjectFile::Atom::kRegularDefinition:
6325 case ObjectFile::Atom::kWeakDefinition:
6326 // prebound external relocation to internal atom ==> pointer contains target address + addend
6327 LittleEndian::set32(*fixUp, targetAddr);
6328 break;
6329 case ObjectFile::Atom::kAbsoluteSymbol:
6330 break;
6331 }
6332 }
6333 }
6334 else {
6335 // internal relocation
6336 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6337 // pointer contains target address
6338 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6339 targetAddr |= 1;
6340 LittleEndian::set32(*fixUp, targetAddr);
6341 }
6342 else {
6343 // pointer contains addend
6344 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6345 }
6346 }
6347 }
6348 break;
6349 case arm::kPointerDiff:
6350 LittleEndian::set32(*fixUp,
6351 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6352 break;
6353 case arm::kDtraceProbeSite:
6354 case arm::kDtraceIsEnabledSite:
6355 case arm::kBranch24WeakImport:
6356 case arm::kBranch24:
6357 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6358 // The pc added will be +8 from the pc
6359 displacement -= 8;
6360 // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6361 if ( relocateableExternal ) {
6362 // doing "ld -r" to an external symbol
6363 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6364 displacement -= ref->getTarget().getAddress();
6365 }
6366 else {
6367 // max positive displacement is 0x007FFFFF << 2
6368 // max negative displacement is 0xFF800000 << 2
6369 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6370 throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6371 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6372 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6373 }
6374 }
6375 instruction = LittleEndian::get32(*fixUp);
6376 // Make sure we are calling arm with bl, thumb with blx
6377 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6378 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6379 if ( is_bl && ref->getTarget().isThumb() ) {
6380 uint32_t opcode = 0xFA000000;
6381 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6382 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6383 newInstruction = opcode | h_bit | disp;
6384 }
6385 else if ( is_blx && !ref->getTarget().isThumb() ) {
6386 uint32_t opcode = 0xEB000000;
6387 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6388 newInstruction = opcode | disp;
6389 }
6390 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6391 throwf("don't know how to convert instruction %x referencing %s to thumb",
6392 instruction, ref->getTarget().getDisplayName());
6393 }
6394 else {
6395 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6396 }
6397 LittleEndian::set32(*fixUp, newInstruction);
6398 break;
6399 case arm::kThumbBranch22WeakImport:
6400 case arm::kThumbBranch22:
6401 instruction = LittleEndian::get32(*fixUp);
6402 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
6403 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
6404 targetIsThumb = ref->getTarget().isThumb();
6405
6406 // The pc added will be +4 from the pc
6407 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6408 // If the target is not thumb, we will be generating a blx instruction
6409 // Since blx cannot have the low bit set, set bit[1] of the target to
6410 // bit[1] of the base address, so that the difference is a multiple of
6411 // 4 bytes.
6412 if (!targetIsThumb) {
6413 targetAddr &= -3ULL;
6414 targetAddr |= (baseAddr & 2LL);
6415 }
6416 displacement = targetAddr - baseAddr;
6417
6418 //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);
6419 if ( relocateableExternal ) {
6420 // doing "ld -r" to an external symbol
6421 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6422 displacement -= ref->getTarget().getAddress();
6423 }
6424
6425 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6426 // armv7 supports a larger displacement
6427 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6428 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6429 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6430 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6431 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6432 }
6433 else {
6434 // The instruction is really two instructions:
6435 // The lower 16 bits are the first instruction, which contains the high
6436 // 11 bits of the displacement.
6437 // The upper 16 bits are the second instruction, which contains the low
6438 // 11 bits of the displacement, as well as differentiating bl and blx.
6439 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6440 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6441 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6442 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6443 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6444 uint32_t j1 = (i1 == s);
6445 uint32_t j2 = (i2 == s);
6446 if ( is_bl ) {
6447 if ( targetIsThumb )
6448 opcode = 0xD000F000; // keep bl
6449 else
6450 opcode = 0xC000F000; // change to blx
6451 }
6452 else if ( is_blx ) {
6453 if ( targetIsThumb )
6454 opcode = 0xD000F000; // change to bl
6455 else
6456 opcode = 0xC000F000; // keep blx
6457 }
6458 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6459 throwf("don't know how to convert instruction %x referencing %s to arm",
6460 instruction, ref->getTarget().getDisplayName());
6461 }
6462 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6463 firstDisp = (s << 10) | imm10;
6464 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6465 //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
6466 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6467 LittleEndian::set32(*fixUp, newInstruction);
6468 break;
6469 }
6470 }
6471 else {
6472 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6473 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6474 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6475 }
6476 }
6477 // The instruction is really two instructions:
6478 // The lower 16 bits are the first instruction, which contains the first
6479 // 11 bits of the displacement.
6480 // The upper 16 bits are the second instruction, which contains the next
6481 // 11 bits of the displacement, as well as differentiating bl and blx.
6482 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6483 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6484 if ( is_bl && !targetIsThumb ) {
6485 opcode = 0xE800F000;
6486 }
6487 else if ( is_blx && targetIsThumb ) {
6488 opcode = 0xF800F000;
6489 }
6490 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6491 throwf("don't know how to convert instruction %x referencing %s to arm",
6492 instruction, ref->getTarget().getDisplayName());
6493 }
6494 else {
6495 opcode = instruction & 0xF800F800;
6496 }
6497 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6498 LittleEndian::set32(*fixUp, newInstruction);
6499 break;
6500 case arm::kDtraceProbe:
6501 case arm::kDtraceTypeReference:
6502 // nothing to fix up
6503 break;
6504 }
6505 }
6506
6507 template <>
6508 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6509 {
6510 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6511 uint8_t* dtraceProbeSite;
6512 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6513 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6514 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6515 const int64_t kOneTwentyEightLimit = 0x7F;
6516 int64_t displacement;
6517 uint32_t temp;
6518 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6519 switch ( kind ) {
6520 case x86::kNoFixUp:
6521 case x86::kFollowOn:
6522 case x86::kGroupSubordinate:
6523 // do nothing
6524 break;
6525 case x86::kPointerWeakImport:
6526 case x86::kPointer:
6527 {
6528 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6529 if ( fOptions.prebind() ) {
6530 switch (ref->getTarget().getDefinitionKind()) {
6531 case ObjectFile::Atom::kExternalDefinition:
6532 case ObjectFile::Atom::kExternalWeakDefinition:
6533 // prebound external relocation ==> pointer contains addend
6534 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6535 break;
6536 case ObjectFile::Atom::kTentativeDefinition:
6537 case ObjectFile::Atom::kRegularDefinition:
6538 case ObjectFile::Atom::kWeakDefinition:
6539 // prebound external relocation to internal atom ==> pointer contains target address + addend
6540 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6541 break;
6542 case ObjectFile::Atom::kAbsoluteSymbol:
6543 break;
6544 }
6545 }
6546 else if ( !fOptions.makeClassicDyldInfo()
6547 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6548 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
6549 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6550 }
6551 else {
6552 // external relocation ==> pointer contains addend
6553 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6554 }
6555 }
6556 else {
6557 // pointer contains target address
6558 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6559 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6560 }
6561 }
6562 break;
6563 case x86::kPointerDiff:
6564 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6565 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6566 break;
6567 case x86::kPointerDiff16:
6568 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6569 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6570 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6571 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6572 break;
6573 case x86::kPointerDiff24:
6574 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6575 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6576 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6577 temp = LittleEndian::get32(*fixUp);
6578 temp &= 0xFF000000;
6579 temp |= (displacement & 0x00FFFFFF);
6580 LittleEndian::set32(*fixUp, temp);
6581 break;
6582 case x86::kSectionOffset24:
6583 displacement = ref->getTarget().getSectionOffset();
6584 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6585 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6586 temp = LittleEndian::get32(*fixUp);
6587 temp &= 0xFF000000;
6588 temp |= (displacement & 0x00FFFFFF);
6589 LittleEndian::set32(*fixUp, temp);
6590 break;
6591 case x86::kDtraceProbeSite:
6592 // change call site to a NOP
6593 dtraceProbeSite = (uint8_t*)fixUp;
6594 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6595 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6596 dtraceProbeSite[1] = 0x1F;
6597 dtraceProbeSite[2] = 0x40;
6598 dtraceProbeSite[3] = 0x00;
6599 break;
6600 case x86::kDtraceIsEnabledSite:
6601 // change call site to a clear eax
6602 dtraceProbeSite = (uint8_t*)fixUp;
6603 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
6604 dtraceProbeSite[0] = 0xC0;
6605 dtraceProbeSite[1] = 0x90; // 1-byte nop
6606 dtraceProbeSite[2] = 0x90; // 1-byte nop
6607 dtraceProbeSite[3] = 0x90; // 1-byte nop
6608 break;
6609 case x86::kPCRel32WeakImport:
6610 case x86::kPCRel32:
6611 case x86::kPCRel16:
6612 case x86::kPCRel8:
6613 displacement = 0;
6614 switch ( ref->getTarget().getDefinitionKind() ) {
6615 case ObjectFile::Atom::kRegularDefinition:
6616 case ObjectFile::Atom::kWeakDefinition:
6617 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6618 break;
6619 case ObjectFile::Atom::kExternalDefinition:
6620 case ObjectFile::Atom::kExternalWeakDefinition:
6621 throw "codegen problem, can't use rel32 to external symbol";
6622 case ObjectFile::Atom::kTentativeDefinition:
6623 displacement = 0;
6624 break;
6625 case ObjectFile::Atom::kAbsoluteSymbol:
6626 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6627 break;
6628 }
6629 if ( kind == x86::kPCRel8 ) {
6630 displacement += 3;
6631 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6632 //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());
6633 throwf("rel8 out of range in %s", inAtom->getDisplayName());
6634 }
6635 *(int8_t*)fixUp = (int8_t)displacement;
6636 }
6637 else if ( kind == x86::kPCRel16 ) {
6638 displacement += 2;
6639 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6640 //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());
6641 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6642 }
6643 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6644 }
6645 else {
6646 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6647 //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());
6648 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6649 }
6650 LittleEndian::set32(*fixUp, (int32_t)displacement);
6651 }
6652 break;
6653 case x86::kAbsolute32:
6654 switch ( ref->getTarget().getDefinitionKind() ) {
6655 case ObjectFile::Atom::kRegularDefinition:
6656 case ObjectFile::Atom::kWeakDefinition:
6657 case ObjectFile::Atom::kTentativeDefinition:
6658 // pointer contains target address
6659 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6660 break;
6661 case ObjectFile::Atom::kExternalDefinition:
6662 case ObjectFile::Atom::kExternalWeakDefinition:
6663 // external relocation ==> pointer contains addend
6664 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6665 break;
6666 case ObjectFile::Atom::kAbsoluteSymbol:
6667 // pointer contains target address
6668 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
6669 break;
6670 }
6671 break;
6672 case x86::kImageOffset32:
6673 // offset of target atom from mach_header
6674 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6675 LittleEndian::set32(*fixUp, (int32_t)displacement);
6676 break;
6677 case x86::kDtraceTypeReference:
6678 case x86::kDtraceProbe:
6679 // nothing to fix up
6680 break;
6681 }
6682 }
6683
6684
6685
6686 template <>
6687 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6688 {
6689 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6690 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6691 const int64_t kOneTwentyEightLimit = 0x7F;
6692 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6693 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
6694 int64_t displacement;
6695 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6696 switch ( kind ) {
6697 case x86::kNoFixUp:
6698 case x86::kFollowOn:
6699 case x86::kGroupSubordinate:
6700 // do nothing
6701 break;
6702 case x86::kPointer:
6703 case x86::kPointerWeakImport:
6704 case x86::kAbsolute32:
6705 {
6706 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6707 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
6708 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6709 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6710 else
6711 LittleEndian::set32(*fixUp, 0);
6712 }
6713 else if ( isExtern ) {
6714 // external relocation ==> pointer contains addend
6715 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6716 }
6717 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6718 // internal relocation => pointer contains target address
6719 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6720 }
6721 else {
6722 // internal relocation to tentative ==> pointer contains addend
6723 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6724 }
6725 }
6726 break;
6727 case x86::kPointerDiff:
6728 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6729 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6730 break;
6731 case x86::kPointerDiff16:
6732 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6733 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6734 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6735 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6736 break;
6737 case x86::kPCRel8:
6738 case x86::kPCRel16:
6739 case x86::kPCRel32:
6740 case x86::kPCRel32WeakImport:
6741 case x86::kDtraceProbeSite:
6742 case x86::kDtraceIsEnabledSite:
6743 {
6744 if ( isExtern )
6745 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6746 else
6747 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6748 if ( kind == x86::kPCRel8 ) {
6749 displacement += 3;
6750 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6751 //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());
6752 throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
6753 }
6754 int8_t byte = (int8_t)displacement;
6755 *((int8_t*)fixUp) = byte;
6756 }
6757 else if ( kind == x86::kPCRel16 ) {
6758 displacement += 2;
6759 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6760 //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());
6761 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6762 }
6763 int16_t word = (int16_t)displacement;
6764 LittleEndian::set16(*((uint16_t*)fixUp), word);
6765 }
6766 else {
6767 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6768 //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement,
6769 // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6770 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6771 }
6772 LittleEndian::set32(*fixUp, (int32_t)displacement);
6773 }
6774 }
6775 break;
6776 case x86::kPointerDiff24:
6777 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
6778 case x86::kImageOffset32:
6779 throw "internal linker error, kImageOffset32 can't be encoded into object files";
6780 case x86::kSectionOffset24:
6781 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
6782 case x86::kDtraceProbe:
6783 case x86::kDtraceTypeReference:
6784 // nothing to fix up
6785 break;
6786 }
6787 }
6788
6789 template <>
6790 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6791 {
6792 const int64_t twoGigLimit = 0x7FFFFFFF;
6793 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6794 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
6795 uint8_t* dtraceProbeSite;
6796 int64_t displacement = 0;
6797 uint32_t temp;
6798 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
6799 case x86_64::kNoFixUp:
6800 case x86_64::kGOTNoFixUp:
6801 case x86_64::kFollowOn:
6802 case x86_64::kGroupSubordinate:
6803 // do nothing
6804 break;
6805 case x86_64::kPointerWeakImport:
6806 case x86_64::kPointer:
6807 {
6808 if ( &ref->getTarget() != NULL ) {
6809 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
6810 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal) {
6811 if ( !fOptions.makeClassicDyldInfo()
6812 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6813 // when using only compressed dyld info, pointer is initially set to point directly to weak definition
6814 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6815 }
6816 else {
6817 // external relocation ==> pointer contains addend
6818 LittleEndian::set64(*fixUp, ref->getTargetOffset());
6819 }
6820 }
6821 else {
6822 // internal relocation
6823 // pointer contains target address
6824 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6825 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6826 }
6827 }
6828 }
6829 break;
6830 case x86_64::kPointer32:
6831 {
6832 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
6833 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6834 // external relocation
6835 throwf("32-bit pointer to dylib or weak symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
6836 }
6837 else {
6838 // internal relocation
6839 // pointer contains target address
6840 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6841 displacement = ref->getTarget().getAddress() + ref->getTargetOffset();
6842 switch ( fOptions.outputKind() ) {
6843 case Options::kObjectFile:
6844 case Options::kPreload:
6845 case Options::kDyld:
6846 case Options::kDynamicLibrary:
6847 case Options::kDynamicBundle:
6848 case Options::kKextBundle:
6849 throwf("32-bit pointer to symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
6850 case Options::kDynamicExecutable:
6851 // <rdar://problem/5855588> allow x86_64 main executables to use 32-bit pointers if program loads in load 2GB
6852 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
6853 throw "32-bit pointer out of range";
6854 break;
6855 case Options::kStaticExecutable:
6856 // <rdar://problem/5855588> allow x86_64 mach_kernel to truncate pointers
6857 break;
6858 }
6859 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
6860 }
6861 }
6862 break;
6863 case x86_64::kPointerDiff32:
6864 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6865 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
6866 throw "32-bit pointer difference out of range";
6867 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
6868 break;
6869 case x86_64::kPointerDiff:
6870 LittleEndian::set64(*fixUp,
6871 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6872 break;
6873 case x86_64::kPointerDiff24:
6874 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6875 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6876 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6877 temp = LittleEndian::get32(*((uint32_t*)fixUp));
6878 temp &= 0xFF000000;
6879 temp |= (displacement & 0x00FFFFFF);
6880 LittleEndian::set32(*((uint32_t*)fixUp), temp);
6881 break;
6882 case x86_64::kSectionOffset24:
6883 displacement = ref->getTarget().getSectionOffset();
6884 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6885 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6886 temp = LittleEndian::get32(*((uint32_t*)fixUp));
6887 temp &= 0xFF000000;
6888 temp |= (displacement & 0x00FFFFFF);
6889 LittleEndian::set32(*((uint32_t*)fixUp), temp);
6890 break;
6891 case x86_64::kPCRel32GOTLoad:
6892 case x86_64::kPCRel32GOTLoadWeakImport:
6893 // if GOT entry was optimized away, change movq instruction to a leaq
6894 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
6895 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
6896 uint8_t* opcodes = (uint8_t*)fixUp;
6897 if ( opcodes[-2] != 0x8B )
6898 throw "GOT load reloc does not point to a movq instruction";
6899 opcodes[-2] = 0x8D;
6900 }
6901 // fall into general rel32 case
6902 case x86_64::kBranchPCRel32WeakImport:
6903 case x86_64::kBranchPCRel32:
6904 case x86_64::kBranchPCRel8:
6905 case x86_64::kPCRel32:
6906 case x86_64::kPCRel32_1:
6907 case x86_64::kPCRel32_2:
6908 case x86_64::kPCRel32_4:
6909 case x86_64::kPCRel32GOT:
6910 case x86_64::kPCRel32GOTWeakImport:
6911 switch ( ref->getTarget().getDefinitionKind() ) {
6912 case ObjectFile::Atom::kRegularDefinition:
6913 case ObjectFile::Atom::kWeakDefinition:
6914 case ObjectFile::Atom::kTentativeDefinition:
6915 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6916 break;
6917 case ObjectFile::Atom::kAbsoluteSymbol:
6918 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6919 break;
6920 case ObjectFile::Atom::kExternalDefinition:
6921 case ObjectFile::Atom::kExternalWeakDefinition:
6922 if ( fOptions.outputKind() == Options::kKextBundle )
6923 displacement = 0;
6924 else
6925 throwf("codegen problem, can't use rel32 to external symbol %s", ref->getTarget().getDisplayName());
6926 break;
6927 }
6928 switch ( ref->getKind() ) {
6929 case x86_64::kPCRel32_1:
6930 displacement -= 1;
6931 break;
6932 case x86_64::kPCRel32_2:
6933 displacement -= 2;
6934 break;
6935 case x86_64::kPCRel32_4:
6936 displacement -= 4;
6937 break;
6938 case x86_64::kBranchPCRel8:
6939 displacement += 3;
6940 break;
6941 }
6942 if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
6943 if ( (displacement > 127) || (displacement < (-128)) ) {
6944 fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n",
6945 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
6946 throw "rel8 out of range";
6947 }
6948 *((int8_t*)fixUp) = (int8_t)displacement;
6949 }
6950 else {
6951 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
6952 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
6953 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
6954 throw "rel32 out of range";
6955 }
6956 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
6957 }
6958 break;
6959 case x86_64::kImageOffset32:
6960 // offset of target atom from mach_header
6961 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6962 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
6963 break;
6964 case x86_64::kDtraceProbeSite:
6965 // change call site to a NOP
6966 dtraceProbeSite = (uint8_t*)fixUp;
6967 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6968 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6969 dtraceProbeSite[1] = 0x1F;
6970 dtraceProbeSite[2] = 0x40;
6971 dtraceProbeSite[3] = 0x00;
6972 break;
6973 case x86_64::kDtraceIsEnabledSite:
6974 // change call site to a clear eax
6975 dtraceProbeSite = (uint8_t*)fixUp;
6976 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
6977 dtraceProbeSite[0] = 0x33;
6978 dtraceProbeSite[1] = 0xC0;
6979 dtraceProbeSite[2] = 0x90; // 1-byte nop
6980 dtraceProbeSite[3] = 0x90; // 1-byte nop
6981 break;
6982 case x86_64::kDtraceTypeReference:
6983 case x86_64::kDtraceProbe:
6984 // nothing to fix up
6985 break;
6986 }
6987 }
6988
6989 template <>
6990 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6991 {
6992 const int64_t twoGigLimit = 0x7FFFFFFF;
6993 bool external = this->makesExternalRelocatableReference(ref->getTarget());
6994 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
6995 int64_t displacement = 0;
6996 int32_t temp32;
6997 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
6998 case x86_64::kNoFixUp:
6999 case x86_64::kGOTNoFixUp:
7000 case x86_64::kFollowOn:
7001 case x86_64::kGroupSubordinate:
7002 // do nothing
7003 break;
7004 case x86_64::kPointer:
7005 case x86_64::kPointerWeakImport:
7006 {
7007 if ( external ) {
7008 // external relocation ==> pointer contains addend
7009 LittleEndian::set64(*fixUp, ref->getTargetOffset());
7010 }
7011 else {
7012 // internal relocation ==> pointer contains target address
7013 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
7014 }
7015 }
7016 break;
7017 case x86_64::kPointer32:
7018 {
7019 if ( external ) {
7020 // external relocation ==> pointer contains addend
7021 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset());
7022 }
7023 else {
7024 // internal relocation ==> pointer contains target address
7025 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTarget().getAddress() + ref->getTargetOffset());
7026 }
7027 }
7028 break;
7029 case x86_64::kPointerDiff32:
7030 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
7031 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7032 displacement += ref->getTarget().getAddress();
7033 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7034 displacement -= ref->getFromTarget().getAddress();
7035 LittleEndian::set32(*((uint32_t*)fixUp), displacement);
7036 break;
7037 case x86_64::kPointerDiff:
7038 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
7039 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7040 displacement += ref->getTarget().getAddress();
7041 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
7042 displacement -= ref->getFromTarget().getAddress();
7043 LittleEndian::set64(*fixUp, displacement);
7044 break;
7045 case x86_64::kBranchPCRel32:
7046 case x86_64::kBranchPCRel32WeakImport:
7047 case x86_64::kDtraceProbeSite:
7048 case x86_64::kDtraceIsEnabledSite:
7049 case x86_64::kPCRel32:
7050 case x86_64::kPCRel32_1:
7051 case x86_64::kPCRel32_2:
7052 case x86_64::kPCRel32_4:
7053 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7054 temp32 = ref->getTargetOffset();
7055 if ( external ) {
7056 // extern relocation contains addend
7057 displacement = temp32;
7058 }
7059 else {
7060 // internal relocations contain delta to target address
7061 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7062 }
7063 switch ( ref->getKind() ) {
7064 case x86_64::kPCRel32_1:
7065 displacement -= 1;
7066 break;
7067 case x86_64::kPCRel32_2:
7068 displacement -= 2;
7069 break;
7070 case x86_64::kPCRel32_4:
7071 displacement -= 4;
7072 break;
7073 }
7074 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
7075 //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());
7076 throw "rel32 out of range";
7077 }
7078 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
7079 break;
7080 case x86_64::kBranchPCRel8:
7081 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7082 temp32 = ref->getTargetOffset();
7083 if ( external ) {
7084 // extern relocation contains addend
7085 displacement = temp32;
7086 }
7087 else {
7088 // internal relocations contain delta to target address
7089 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
7090 }
7091 if ( (displacement > 127) || (displacement < (-128)) ) {
7092 //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());
7093 throw "rel8 out of range";
7094 }
7095 *((int8_t*)fixUp) = (int8_t)displacement;
7096 break;
7097 case x86_64::kPCRel32GOT:
7098 case x86_64::kPCRel32GOTLoad:
7099 case x86_64::kPCRel32GOTWeakImport:
7100 case x86_64::kPCRel32GOTLoadWeakImport:
7101 // contains addend (usually zero)
7102 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
7103 break;
7104 case x86_64::kPointerDiff24:
7105 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
7106 case x86_64::kImageOffset32:
7107 throw "internal linker error, kImageOffset32 can't be encoded into object files";
7108 case x86_64::kSectionOffset24:
7109 throw "internal linker error, kSectionOffset24 can't be encoded into object files";
7110 case x86_64::kDtraceTypeReference:
7111 case x86_64::kDtraceProbe:
7112 // nothing to fix up
7113 break;
7114 }
7115 }
7116
7117 template <>
7118 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7119 {
7120 fixUpReference_powerpc(ref, inAtom, buffer, true);
7121 }
7122
7123 template <>
7124 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7125 {
7126 fixUpReference_powerpc(ref, inAtom, buffer, true);
7127 }
7128
7129 template <>
7130 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7131 {
7132 fixUpReference_powerpc(ref, inAtom, buffer, false);
7133 }
7134
7135 template <>
7136 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7137 {
7138 fixUpReference_powerpc(ref, inAtom, buffer, false);
7139 }
7140
7141 //
7142 // ppc and ppc64 are mostly the same, so they share a template specialzation
7143 //
7144 template <typename A>
7145 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
7146 {
7147 uint32_t instruction;
7148 uint32_t newInstruction;
7149 int64_t displacement;
7150 uint64_t targetAddr = 0;
7151 uint64_t picBaseAddr;
7152 uint16_t instructionLowHalf;
7153 uint16_t instructionHighHalf;
7154 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
7155 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
7156 bool relocateableExternal = false;
7157 const int64_t picbase_twoGigLimit = 0x80000000;
7158
7159 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
7160 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
7161 if ( finalLinkedImage )
7162 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
7163 else
7164 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
7165 }
7166
7167 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
7168 case A::kNoFixUp:
7169 case A::kFollowOn:
7170 case A::kGroupSubordinate:
7171 // do nothing
7172 break;
7173 case A::kPointerWeakImport:
7174 case A::kPointer:
7175 {
7176 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
7177 if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers
7178 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
7179 switch (ref->getTarget().getDefinitionKind()) {
7180 case ObjectFile::Atom::kExternalDefinition:
7181 case ObjectFile::Atom::kExternalWeakDefinition:
7182 // prebound lazy pointer to another dylib ==> pointer contains zero
7183 P::setP(*fixUpPointer, 0);
7184 break;
7185 case ObjectFile::Atom::kTentativeDefinition:
7186 case ObjectFile::Atom::kRegularDefinition:
7187 case ObjectFile::Atom::kWeakDefinition:
7188 case ObjectFile::Atom::kAbsoluteSymbol:
7189 // prebound lazy pointer to withing this dylib ==> pointer contains address
7190 P::setP(*fixUpPointer, targetAddr);
7191 break;
7192 }
7193 }
7194 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
7195 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
7196 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
7197 P::setP(*fixUpPointer, targetAddr);
7198 else
7199 P::setP(*fixUpPointer, 0);
7200 }
7201 else if ( relocateableExternal ) {
7202 if ( fOptions.prebind() ) {
7203 switch (ref->getTarget().getDefinitionKind()) {
7204 case ObjectFile::Atom::kExternalDefinition:
7205 case ObjectFile::Atom::kExternalWeakDefinition:
7206 // prebound external relocation ==> pointer contains addend
7207 P::setP(*fixUpPointer, ref->getTargetOffset());
7208 break;
7209 case ObjectFile::Atom::kTentativeDefinition:
7210 case ObjectFile::Atom::kRegularDefinition:
7211 case ObjectFile::Atom::kWeakDefinition:
7212 // prebound external relocation to internal atom ==> pointer contains target address + addend
7213 P::setP(*fixUpPointer, targetAddr);
7214 break;
7215 case ObjectFile::Atom::kAbsoluteSymbol:
7216 break;
7217 }
7218 }
7219 else {
7220 // external relocation ==> pointer contains addend
7221 P::setP(*fixUpPointer, ref->getTargetOffset());
7222 }
7223 }
7224 else {
7225 // internal relocation
7226 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
7227 // pointer contains target address
7228 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
7229 P::setP(*fixUpPointer, targetAddr);
7230 }
7231 else {
7232 // pointer contains addend
7233 P::setP(*fixUpPointer, ref->getTargetOffset());
7234 }
7235 }
7236 }
7237 break;
7238 case A::kPointerDiff64:
7239 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7240 break;
7241 case A::kPointerDiff32:
7242 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7243 break;
7244 case A::kPointerDiff16:
7245 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7246 break;
7247 case A::kDtraceProbeSite:
7248 if ( finalLinkedImage ) {
7249 // change call site to a NOP
7250 BigEndian::set32(*fixUp, 0x60000000);
7251 }
7252 else {
7253 // set bl instuction to branch to address zero in .o file
7254 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7255 instruction = BigEndian::get32(*fixUp);
7256 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7257 BigEndian::set32(*fixUp, newInstruction);
7258 }
7259 break;
7260 case A::kDtraceIsEnabledSite:
7261 if ( finalLinkedImage ) {
7262 // change call site to a li r3,0
7263 BigEndian::set32(*fixUp, 0x38600000);
7264 }
7265 else {
7266 // set bl instuction to branch to address zero in .o file
7267 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7268 instruction = BigEndian::get32(*fixUp);
7269 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7270 BigEndian::set32(*fixUp, newInstruction);
7271 }
7272 break;
7273 case A::kBranch24WeakImport:
7274 case A::kBranch24:
7275 {
7276 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
7277 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7278 if ( relocateableExternal ) {
7279 // doing "ld -r" to an external symbol
7280 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7281 displacement -= ref->getTarget().getAddress();
7282 }
7283 else {
7284 const int64_t bl_eightMegLimit = 0x00FFFFFF;
7285 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
7286 //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());
7287 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",
7288 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
7289 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
7290 }
7291 }
7292 instruction = BigEndian::get32(*fixUp);
7293 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7294 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7295 BigEndian::set32(*fixUp, newInstruction);
7296 }
7297 break;
7298 case A::kBranch14:
7299 {
7300 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7301 if ( relocateableExternal ) {
7302 // doing "ld -r" to an external symbol
7303 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7304 displacement -= ref->getTarget().getAddress();
7305 }
7306 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
7307 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
7308 //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());
7309 throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
7310 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
7311 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
7312 }
7313
7314 //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
7315 instruction = BigEndian::get32(*fixUp);
7316 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
7317 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7318 BigEndian::set32(*fixUp, newInstruction);
7319 }
7320 break;
7321 case A::kPICBaseLow16:
7322 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7323 displacement = targetAddr - picBaseAddr;
7324 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7325 throw "32-bit pic-base out of range";
7326 instructionLowHalf = (displacement & 0xFFFF);
7327 instruction = BigEndian::get32(*fixUp);
7328 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7329 BigEndian::set32(*fixUp, newInstruction);
7330 break;
7331 case A::kPICBaseLow14:
7332 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7333 displacement = targetAddr - picBaseAddr;
7334 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7335 throw "32-bit pic-base out of range";
7336 if ( (displacement & 0x3) != 0 )
7337 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
7338 instructionLowHalf = (displacement & 0xFFFC);
7339 instruction = BigEndian::get32(*fixUp);
7340 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7341 BigEndian::set32(*fixUp, newInstruction);
7342 break;
7343 case A::kPICBaseHigh16:
7344 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7345 displacement = targetAddr - picBaseAddr;
7346 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7347 throw "32-bit pic-base out of range";
7348 instructionLowHalf = displacement >> 16;
7349 if ( (displacement & 0x00008000) != 0 )
7350 ++instructionLowHalf;
7351 instruction = BigEndian::get32(*fixUp);
7352 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7353 BigEndian::set32(*fixUp, newInstruction);
7354 break;
7355 case A::kAbsLow16:
7356 if ( relocateableExternal && !finalLinkedImage )
7357 targetAddr -= ref->getTarget().getAddress();
7358 instructionLowHalf = (targetAddr & 0xFFFF);
7359 instruction = BigEndian::get32(*fixUp);
7360 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7361 BigEndian::set32(*fixUp, newInstruction);
7362 break;
7363 case A::kAbsLow14:
7364 if ( relocateableExternal && !finalLinkedImage )
7365 targetAddr -= ref->getTarget().getAddress();
7366 if ( (targetAddr & 0x3) != 0 )
7367 throw "bad address for absolute lo14 instruction fix-up";
7368 instructionLowHalf = (targetAddr & 0xFFFF);
7369 instruction = BigEndian::get32(*fixUp);
7370 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7371 BigEndian::set32(*fixUp, newInstruction);
7372 break;
7373 case A::kAbsHigh16:
7374 if ( relocateableExternal ) {
7375 if ( finalLinkedImage ) {
7376 switch (ref->getTarget().getDefinitionKind()) {
7377 case ObjectFile::Atom::kExternalDefinition:
7378 case ObjectFile::Atom::kExternalWeakDefinition:
7379 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7380 break;
7381 case ObjectFile::Atom::kTentativeDefinition:
7382 case ObjectFile::Atom::kRegularDefinition:
7383 case ObjectFile::Atom::kWeakDefinition:
7384 // use target address
7385 break;
7386 case ObjectFile::Atom::kAbsoluteSymbol:
7387 targetAddr = ref->getTarget().getSectionOffset();
7388 break;
7389 }
7390 }
7391 else {
7392 targetAddr -= ref->getTarget().getAddress();
7393 }
7394 }
7395 instructionHighHalf = (targetAddr >> 16);
7396 instruction = BigEndian::get32(*fixUp);
7397 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
7398 BigEndian::set32(*fixUp, newInstruction);
7399 break;
7400 case A::kAbsHigh16AddLow:
7401 if ( relocateableExternal ) {
7402 if ( finalLinkedImage ) {
7403 switch (ref->getTarget().getDefinitionKind()) {
7404 case ObjectFile::Atom::kExternalDefinition:
7405 case ObjectFile::Atom::kExternalWeakDefinition:
7406 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7407 break;
7408 case ObjectFile::Atom::kTentativeDefinition:
7409 case ObjectFile::Atom::kRegularDefinition:
7410 case ObjectFile::Atom::kWeakDefinition:
7411 // use target address
7412 break;
7413 case ObjectFile::Atom::kAbsoluteSymbol:
7414 targetAddr = ref->getTarget().getSectionOffset();
7415 break;
7416 }
7417 }
7418 else {
7419 targetAddr -= ref->getTarget().getAddress();
7420 }
7421 }
7422 if ( targetAddr & 0x00008000 )
7423 targetAddr += 0x00010000;
7424 instruction = BigEndian::get32(*fixUp);
7425 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
7426 BigEndian::set32(*fixUp, newInstruction);
7427 break;
7428 case A::kDtraceTypeReference:
7429 case A::kDtraceProbe:
7430 // nothing to fix up
7431 break;
7432 }
7433 }
7434
7435 template <>
7436 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7437 {
7438 uint8_t kind = ref->getKind();
7439 switch ( (ppc::ReferenceKinds)kind ) {
7440 case ppc::kNoFixUp:
7441 case ppc::kFollowOn:
7442 case ppc::kGroupSubordinate:
7443 case ppc::kPointer:
7444 case ppc::kPointerWeakImport:
7445 case ppc::kPointerDiff16:
7446 case ppc::kPointerDiff32:
7447 case ppc::kPointerDiff64:
7448 case ppc::kDtraceProbe:
7449 case ppc::kDtraceProbeSite:
7450 case ppc::kDtraceIsEnabledSite:
7451 case ppc::kDtraceTypeReference:
7452 // these are never used to call external functions
7453 return false;
7454 case ppc::kBranch24:
7455 case ppc::kBranch24WeakImport:
7456 case ppc::kBranch14:
7457 // these are used to call external functions
7458 return true;
7459 case ppc::kPICBaseLow16:
7460 case ppc::kPICBaseLow14:
7461 case ppc::kPICBaseHigh16:
7462 case ppc::kAbsLow16:
7463 case ppc::kAbsLow14:
7464 case ppc::kAbsHigh16:
7465 case ppc::kAbsHigh16AddLow:
7466 // these are only used to call external functions
7467 // in -mlong-branch stubs
7468 switch ( ref->getTarget().getDefinitionKind() ) {
7469 case ObjectFile::Atom::kExternalDefinition:
7470 case ObjectFile::Atom::kExternalWeakDefinition:
7471 // if the .o file this atom came from has long-branch stubs,
7472 // then assume these instructions in a stub.
7473 // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
7474 return ( inAtom->getFile()->hasLongBranchStubs() );
7475 case ObjectFile::Atom::kTentativeDefinition:
7476 case ObjectFile::Atom::kRegularDefinition:
7477 case ObjectFile::Atom::kWeakDefinition:
7478 case ObjectFile::Atom::kAbsoluteSymbol:
7479 return false;
7480 }
7481 break;
7482 }
7483 return false;
7484 }
7485
7486 template <>
7487 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7488 {
7489 uint8_t kind = ref->getKind();
7490 switch ( (arm::ReferenceKinds)kind ) {
7491 case arm::kBranch24:
7492 case arm::kBranch24WeakImport:
7493 case arm::kThumbBranch22:
7494 case arm::kThumbBranch22WeakImport:
7495 return true;
7496 case arm::kNoFixUp:
7497 case arm::kFollowOn:
7498 case arm::kGroupSubordinate:
7499 case arm::kPointer:
7500 case arm::kReadOnlyPointer:
7501 case arm::kPointerWeakImport:
7502 case arm::kPointerDiff:
7503 case arm::kDtraceProbe:
7504 case arm::kDtraceProbeSite:
7505 case arm::kDtraceIsEnabledSite:
7506 case arm::kDtraceTypeReference:
7507 return false;
7508 }
7509 return false;
7510 }
7511
7512 template <>
7513 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7514 {
7515 uint8_t kind = ref->getKind();
7516 switch ( (ppc64::ReferenceKinds)kind ) {
7517 case ppc::kNoFixUp:
7518 case ppc::kFollowOn:
7519 case ppc::kGroupSubordinate:
7520 case ppc::kPointer:
7521 case ppc::kPointerWeakImport:
7522 case ppc::kPointerDiff16:
7523 case ppc::kPointerDiff32:
7524 case ppc::kPointerDiff64:
7525 case ppc::kPICBaseLow16:
7526 case ppc::kPICBaseLow14:
7527 case ppc::kPICBaseHigh16:
7528 case ppc::kAbsLow16:
7529 case ppc::kAbsLow14:
7530 case ppc::kAbsHigh16:
7531 case ppc::kAbsHigh16AddLow:
7532 case ppc::kDtraceProbe:
7533 case ppc::kDtraceProbeSite:
7534 case ppc::kDtraceIsEnabledSite:
7535 case ppc::kDtraceTypeReference:
7536 // these are never used to call external functions
7537 return false;
7538 case ppc::kBranch24:
7539 case ppc::kBranch24WeakImport:
7540 case ppc::kBranch14:
7541 // these are used to call external functions
7542 return true;
7543 }
7544 return false;
7545 }
7546
7547 template <>
7548 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7549 {
7550 uint8_t kind = ref->getKind();
7551 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
7552 }
7553
7554 template <>
7555 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7556 {
7557 uint8_t kind = ref->getKind();
7558 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
7559 }
7560
7561
7562 template <>
7563 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
7564 {
7565 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
7566 }
7567
7568 template <>
7569 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
7570 {
7571 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
7572 }
7573
7574 template <>
7575 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
7576 {
7577 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
7578 }
7579
7580 template <>
7581 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
7582 {
7583 switch ( kind ) {
7584 case x86_64::kPointerWeakImport:
7585 case x86_64::kBranchPCRel32WeakImport:
7586 case x86_64::kPCRel32GOTWeakImport:
7587 case x86_64::kPCRel32GOTLoadWeakImport:
7588 return true;
7589 }
7590 return false;
7591 }
7592
7593 template <>
7594 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
7595 {
7596 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
7597 kind == arm::kPointerWeakImport);
7598 }
7599
7600 template <>
7601 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
7602 {
7603 return false;
7604 }
7605
7606 template <>
7607 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
7608 {
7609 return false;
7610 }
7611
7612 template <>
7613 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
7614 {
7615 return false;
7616 }
7617
7618 template <>
7619 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
7620 {
7621 switch ( kind ) {
7622 case x86_64::kPCRel32GOT:
7623 case x86_64::kPCRel32GOTWeakImport:
7624 case x86_64::kPCRel32GOTLoad:
7625 case x86_64::kPCRel32GOTLoadWeakImport:
7626 case x86_64::kGOTNoFixUp:
7627 return true;
7628 }
7629 return false;
7630 }
7631
7632 template <>
7633 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
7634 {
7635 return false;
7636 }
7637
7638 template <>
7639 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
7640 {
7641 return false;
7642 }
7643
7644 template <>
7645 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
7646 {
7647 return false;
7648 }
7649
7650 template <>
7651 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
7652 {
7653 return false;
7654 }
7655
7656 template <>
7657 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
7658 {
7659 switch ( kind ) {
7660 case x86_64::kPCRel32GOTLoad:
7661 case x86_64::kPCRel32GOTLoadWeakImport:
7662 return true;
7663 }
7664 return false;
7665 }
7666
7667 template <>
7668 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
7669 {
7670 return false;
7671 }
7672
7673 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
7674 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
7675 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
7676 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
7677
7678
7679 template <typename A>
7680 void Writer<A>::optimizeDylibReferences()
7681 {
7682 //fprintf(stderr, "original ordinals table:\n");
7683 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7684 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7685 //}
7686 // find unused dylibs that can be removed
7687 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
7688 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
7689 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7690 ObjectFile::Reader* reader = it->first;
7691 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
7692 if ( aliasPos != fLibraryAliases.end() ) {
7693 // already noticed that this reader has same install name as another reader
7694 readerAliases[reader] = aliasPos->second;
7695 }
7696 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || reader->deadStrippable() || fOptions.deadStripDylibs()) ) {
7697 // this reader can be optimized away
7698 it->second = 0xFFFFFFFF;
7699 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
7700 if ( pos != fLibraryToLoadCommand.end() )
7701 pos->second->optimizeAway();
7702 }
7703 else {
7704 // mark this reader as using it ordinal
7705 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
7706 if ( pos == ordinalToReader.end() )
7707 ordinalToReader[it->second] = reader;
7708 else
7709 readerAliases[reader] = pos->second;
7710 }
7711 }
7712 // renumber ordinals (depends on iterator walking in ordinal order)
7713 // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
7714 uint32_t newOrdinal = 0;
7715 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7716 if ( it->first <= fLibraryToOrdinal.size() ) {
7717 if ( ! it->second->isLazyLoadedDylib() )
7718 fLibraryToOrdinal[it->second] = ++newOrdinal;
7719 }
7720 }
7721 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7722 if ( it->first <= fLibraryToOrdinal.size() ) {
7723 if ( it->second->isLazyLoadedDylib() ) {
7724 fLibraryToOrdinal[it->second] = ++newOrdinal;
7725 }
7726 }
7727 }
7728
7729 // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
7730 if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
7731 throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
7732
7733 // add aliases (e.g. -lm points to libSystem.dylib)
7734 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
7735 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
7736 }
7737
7738 //fprintf(stderr, "new ordinals table:\n");
7739 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7740 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7741 //}
7742 }
7743
7744
7745 template <>
7746 void Writer<arm>::scanForAbsoluteReferences()
7747 {
7748 // arm codegen never has absolute references. FIXME: Is this correct?
7749 }
7750
7751 template <>
7752 void Writer<x86_64>::scanForAbsoluteReferences()
7753 {
7754 // x86_64 codegen never has absolute references
7755 }
7756
7757 template <>
7758 void Writer<x86>::scanForAbsoluteReferences()
7759 {
7760 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
7761 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
7762 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7763 ObjectFile::Atom* atom = *it;
7764 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7765 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7766 ObjectFile::Reference* ref = *rit;
7767 switch (ref->getKind()) {
7768 case x86::kAbsolute32:
7769 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
7770 return;
7771 }
7772 }
7773 }
7774 }
7775 }
7776
7777 template <>
7778 void Writer<ppc>::scanForAbsoluteReferences()
7779 {
7780 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
7781 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
7782 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7783 ObjectFile::Atom* atom = *it;
7784 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7785 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7786 ObjectFile::Reference* ref = *rit;
7787 switch (ref->getKind()) {
7788 case ppc::kAbsLow16:
7789 case ppc::kAbsLow14:
7790 case ppc::kAbsHigh16:
7791 case ppc::kAbsHigh16AddLow:
7792 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
7793 return;
7794 }
7795 }
7796 }
7797 }
7798 }
7799
7800
7801 // for ppc64 look for any -mdynamic-no-pic codegen
7802 template <>
7803 void Writer<ppc64>::scanForAbsoluteReferences()
7804 {
7805 // only do this for main executable
7806 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
7807 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7808 ObjectFile::Atom* atom = *it;
7809 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7810 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7811 ObjectFile::Reference* ref = *rit;
7812 switch (ref->getKind()) {
7813 case ppc64::kAbsLow16:
7814 case ppc64::kAbsLow14:
7815 case ppc64::kAbsHigh16:
7816 case ppc64::kAbsHigh16AddLow:
7817 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
7818 // shrink page-zero and add pad segment to compensate
7819 fPadSegmentInfo = new SegmentInfo(4096);
7820 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
7821 fPageZeroAtom->setSize(0x1000);
7822 return;
7823 }
7824 }
7825 }
7826 }
7827 }
7828
7829
7830 template <typename A>
7831 void Writer<A>::insertDummyStubs()
7832 {
7833 // only needed for x86
7834 }
7835
7836 template <>
7837 void Writer<x86>::insertDummyStubs()
7838 {
7839 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
7840 std::vector<class StubAtom<x86>*> betterStubs;
7841 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
7842 switch (betterStubs.size() % 64 ) {
7843 case 12:// stub would occupy 0x3C->0x41
7844 case 25:// stub would occupy 0x7D->0x82
7845 case 38:// stub would occupy 0xBE->0xC3
7846 case 51:// stub would occupy 0xFF->0x04
7847 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
7848 break;
7849 }
7850 betterStubs.push_back(*it);
7851 }
7852 // replace
7853 fAllSynthesizedStubs.clear();
7854 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
7855 }
7856
7857
7858 template <typename A>
7859 void Writer<A>::synthesizeKextGOT()
7860 {
7861 // walk every atom and reference
7862 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7863 ObjectFile::Atom* atom = *it;
7864 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7865 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7866 ObjectFile::Reference* ref = *rit;
7867 switch ( ref->getTargetBinding()) {
7868 case ObjectFile::Reference::kUnboundByName:
7869 case ObjectFile::Reference::kDontBind:
7870 break;
7871 case ObjectFile::Reference::kBoundByName:
7872 case ObjectFile::Reference::kBoundDirectly:
7873 ObjectFile::Atom& target = ref->getTarget();
7874 // create GOT slots (non-lazy pointers) as needed
7875 if ( this->GOTReferenceKind(ref->getKind()) ) {
7876 bool useGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
7877 // if this GOT usage cannot be optimized away then make a GOT enry
7878 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
7879 useGOT = true;
7880 if ( useGOT ) {
7881 ObjectFile::Atom* nlp = NULL;
7882 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
7883 if ( pos == fGOTMap.end() ) {
7884 nlp = new NonLazyPointerAtom<A>(*this, target);
7885 fGOTMap[&target] = nlp;
7886 }
7887 else {
7888 nlp = pos->second;
7889 }
7890 // alter reference to use non lazy pointer instead
7891 ref->setTarget(*nlp, ref->getTargetOffset());
7892 }
7893 }
7894 // build map of which symbols need weak importing
7895 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
7896 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
7897 if ( this->weakImportReferenceKind(ref->getKind()) ) {
7898 fWeakImportMap[&target] = true;
7899 }
7900 }
7901 break;
7902 }
7903 }
7904 }
7905
7906 // add non-lazy pointers to fAllAtoms
7907 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
7908 ObjectFile::Section* curSection = NULL;
7909 ObjectFile::Atom* prevAtom = NULL;
7910 bool inserted = false;
7911 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7912 ObjectFile::Atom* atom = *it;
7913 ObjectFile::Section* nextSection = atom->getSection();
7914 if ( nextSection != curSection ) {
7915 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__data") == 0) ) {
7916 // found end of __data section, insert lazy pointers here
7917 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
7918 inserted = true;
7919 break;
7920 }
7921 curSection = nextSection;
7922 }
7923 prevAtom = atom;
7924 }
7925 if ( !inserted ) {
7926 throw "can't insert non-lazy pointers, __data section not found";
7927 }
7928 }
7929
7930 }
7931
7932
7933 template <typename A>
7934 void Writer<A>::synthesizeStubs()
7935 {
7936 switch ( fOptions.outputKind() ) {
7937 case Options::kObjectFile:
7938 case Options::kPreload:
7939 // these output kinds never have stubs
7940 return;
7941 case Options::kKextBundle:
7942 // new kext need a synthesized GOT only
7943 synthesizeKextGOT();
7944 return;
7945 case Options::kStaticExecutable:
7946 case Options::kDyld:
7947 case Options::kDynamicLibrary:
7948 case Options::kDynamicBundle:
7949 case Options::kDynamicExecutable:
7950 // try to synthesize stubs for these
7951 break;
7952 }
7953
7954 // walk every atom and reference
7955 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7956 ObjectFile::Atom* atom = *it;
7957 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7958 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7959 ObjectFile::Reference* ref = *rit;
7960 switch ( ref->getTargetBinding()) {
7961 case ObjectFile::Reference::kUnboundByName:
7962 case ObjectFile::Reference::kDontBind:
7963 break;
7964 case ObjectFile::Reference::kBoundByName:
7965 case ObjectFile::Reference::kBoundDirectly:
7966 ObjectFile::Atom& target = ref->getTarget();
7967 // build map of which symbols need weak importing
7968 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
7969 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
7970 bool weakImport = this->weakImportReferenceKind(ref->getKind());
7971 // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
7972 // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
7973 // in dylibs that are weakly linked.
7974 if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
7975 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
7976 pos = fLibraryToLoadCommand.find(target.getFile());
7977 if ( pos != fLibraryToLoadCommand.end() ) {
7978 if ( pos->second->linkedWeak() )
7979 weakImport = true;
7980 }
7981 }
7982 // <rdar://problem/6186838> -weak_library no longer forces uses to be weak_import
7983 if ( fForcedWeakImportReaders.count(target.getFile()) != 0 ) {
7984 fWeakImportMap[&target] = true;
7985 weakImport = true;
7986 }
7987
7988 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
7989 if ( pos == fWeakImportMap.end() ) {
7990 // target not in fWeakImportMap, so add
7991 fWeakImportMap[&target] = weakImport;
7992 }
7993 else {
7994 // target in fWeakImportMap, check for weakness mismatch
7995 if ( pos->second != weakImport ) {
7996 // found mismatch
7997 switch ( fOptions.weakReferenceMismatchTreatment() ) {
7998 case Options::kWeakReferenceMismatchError:
7999 throwf("mismatching weak references for symbol: %s", target.getName());
8000 case Options::kWeakReferenceMismatchWeak:
8001 pos->second = true;
8002 break;
8003 case Options::kWeakReferenceMismatchNonWeak:
8004 pos->second = false;
8005 break;
8006 }
8007 }
8008 }
8009 // update if we use a weak_import or a strong import from this dylib
8010 if ( fWeakImportMap[&target] )
8011 fDylibReadersWithWeakImports.insert(target.getFile());
8012 else
8013 fDylibReadersWithNonWeakImports.insert(target.getFile());
8014 }
8015 // create stubs as needed
8016 if ( this->stubableReference(atom, ref)
8017 && (ref->getTargetOffset() == 0)
8018 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
8019 ObjectFile::Atom* stub = NULL;
8020 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
8021 if ( pos == fStubsMap.end() ) {
8022 bool forLazyDylib = false;
8023 switch ( target.getDefinitionKind() ) {
8024 case ObjectFile::Atom::kRegularDefinition:
8025 case ObjectFile::Atom::kWeakDefinition:
8026 case ObjectFile::Atom::kAbsoluteSymbol:
8027 case ObjectFile::Atom::kTentativeDefinition:
8028 break;
8029 case ObjectFile::Atom::kExternalDefinition:
8030 case ObjectFile::Atom::kExternalWeakDefinition:
8031 if ( target.getFile()->isLazyLoadedDylib() )
8032 forLazyDylib = true;
8033 break;
8034 }
8035 // just-in-time, create GOT slot to dyld_stub_binder
8036 if ( fOptions.makeCompressedDyldInfo() && (fFastStubGOTAtom == NULL) ) {
8037 if ( fDyldCompressedHelperAtom == NULL )
8038 throw "missing symbol dyld_stub_binder";
8039 fFastStubGOTAtom = new NonLazyPointerAtom<A>(*this, *fDyldCompressedHelperAtom);
8040 }
8041 stub = new StubAtom<A>(*this, target, forLazyDylib);
8042 fStubsMap[&target] = stub;
8043 }
8044 else {
8045 stub = pos->second;
8046 }
8047 // alter reference to use stub instead
8048 ref->setTarget(*stub, 0);
8049 }
8050 else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
8051 throwf("illegal reference to %s in lazy loaded dylib from %s in %s",
8052 target.getDisplayName(), atom->getDisplayName(),
8053 atom->getFile()->getPath());
8054 }
8055 // create GOT slots (non-lazy pointers) as needed
8056 else if ( this->GOTReferenceKind(ref->getKind()) ) {
8057 //
8058 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
8059 bool useGOT;
8060 if ( fBiggerThanTwoGigs ) {
8061 // in big images use GOT for all zero fill atoms
8062 // this is just a heuristic and may need to be re-examined
8063 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
8064 }
8065 else {
8066 // < 2GB image so remove all GOT entries that we can
8067 useGOT = mustUseGOT;
8068 }
8069 // if this GOT usage cannot be optimized away then make a GOT enry
8070 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
8071 useGOT = true;
8072 if ( useGOT ) {
8073 ObjectFile::Atom* nlp = NULL;
8074 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
8075 if ( pos == fGOTMap.end() ) {
8076 nlp = new NonLazyPointerAtom<A>(*this, target);
8077 fGOTMap[&target] = nlp;
8078 }
8079 else {
8080 nlp = pos->second;
8081 }
8082 // alter reference to use non lazy pointer instead
8083 ref->setTarget(*nlp, ref->getTargetOffset());
8084 }
8085 }
8086 }
8087 }
8088 }
8089
8090 // sort stubs
8091 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
8092 std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter());
8093
8094 // add dummy self-modifying stubs (x86 only)
8095 if ( ! fOptions.makeCompressedDyldInfo() )
8096 this->insertDummyStubs();
8097
8098 // sort lazy pointers
8099 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
8100 std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
8101
8102
8103 // add stubs to fAllAtoms
8104 if ( fAllSynthesizedStubs.size() != 0 ) {
8105 std::vector<ObjectFile::Atom*> textStubs;
8106 std::vector<ObjectFile::Atom*> importStubs;
8107 for (typename std::vector<class StubAtom<A>*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) {
8108 ObjectFile::Atom* stubAtom = *sit;
8109 if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 )
8110 textStubs.push_back(stubAtom);
8111 else
8112 importStubs.push_back(stubAtom);
8113 }
8114 // any helper stubs go right after regular stubs
8115 if ( fAllSynthesizedStubHelpers.size() != 0 )
8116 textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
8117 // insert text stubs right after __text section
8118 ObjectFile::Section* curSection = NULL;
8119 ObjectFile::Atom* prevAtom = NULL;
8120 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8121 ObjectFile::Atom* atom = *it;
8122 ObjectFile::Section* nextSection = atom->getSection();
8123 if ( nextSection != curSection ) {
8124 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
8125 // found end of __text section, insert stubs here
8126 fAllAtoms->insert(it, textStubs.begin(), textStubs.end());
8127 break;
8128 }
8129 curSection = nextSection;
8130 }
8131 prevAtom = atom;
8132 }
8133 if ( importStubs.size() != 0 ) {
8134 // insert __IMPORTS stubs right before __LINKEDIT
8135 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8136 ObjectFile::Atom* atom = *it;
8137 ObjectFile::Section* nextSection = atom->getSection();
8138 if ( nextSection != curSection ) {
8139 // for i386 where stubs are not in __TEXT segment
8140 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
8141 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
8142 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
8143 fAllAtoms->insert(it, importStubs.begin(), importStubs.end());
8144 break;
8145 }
8146 curSection = nextSection;
8147 }
8148 prevAtom = atom;
8149 }
8150 }
8151 }
8152
8153
8154 // add non-lazy pointers to fAllAtoms
8155 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
8156 ObjectFile::Section* curSection = NULL;
8157 ObjectFile::Atom* prevAtom = NULL;
8158 bool inserted = false;
8159 // first try to insert at end of __nl_symbol_ptr
8160 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8161 ObjectFile::Atom* atom = *it;
8162 ObjectFile::Section* nextSection = atom->getSection();
8163 if ( nextSection != curSection ) {
8164 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) {
8165 // found end of __nl_symbol_ptr section, insert non-lazy pointers at end of it
8166 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8167 inserted = true;
8168 break;
8169 }
8170 curSection = nextSection;
8171 }
8172 prevAtom = atom;
8173 }
8174 if ( !inserted ) {
8175 // next try to insert after __dyld section
8176 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8177 ObjectFile::Atom* atom = *it;
8178 ObjectFile::Section* nextSection = atom->getSection();
8179 if ( nextSection != curSection ) {
8180 if ( strcmp(atom->getSegment().getName(), "__DATA") == 0 ) {
8181 const char* prevSectionName = (prevAtom != NULL) ? prevAtom->getSectionName() : "";
8182 if ( (strcmp(prevSectionName, "__dyld") != 0)
8183 && (strcmp(prevSectionName, "__program_vars") != 0)
8184 && (strcmp(prevSectionName, "__mod_init_func") != 0) ) {
8185 // found end of __dyld section, insert non-lazy pointers here
8186 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8187 inserted = true;
8188 break;
8189 }
8190 }
8191 }
8192 prevAtom = atom;
8193 }
8194 if ( !inserted ) {
8195 // might not be any __DATA sections, insert after end of __TEXT
8196 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8197 ObjectFile::Atom* atom = *it;
8198 ObjectFile::Section* nextSection = atom->getSection();
8199 if ( nextSection != curSection ) {
8200 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__TEXT") == 0) && (strcmp(atom->getSegment().getName(), "__TEXT") != 0)) {
8201 // found end of __TEXT segment, insert non-lazy pointers at end of it
8202 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8203 inserted = true;
8204 break;
8205 }
8206 curSection = nextSection;
8207 }
8208 prevAtom = atom;
8209 }
8210 }
8211 if ( !inserted )
8212 throw "can't insert non-lazy pointers, __dyld section not found";
8213 }
8214 }
8215
8216 // add lazy dylib pointers to fAllAtoms
8217 if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) {
8218 ObjectFile::Section* curSection = NULL;
8219 ObjectFile::Atom* prevAtom = NULL;
8220 bool inserted = false;
8221 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8222 ObjectFile::Atom* atom = *it;
8223 ObjectFile::Section* nextSection = atom->getSection();
8224 if ( nextSection != curSection ) {
8225 if ( (prevAtom != NULL) &&
8226 ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0)
8227 || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0)
8228 || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) {
8229 // found end of __dyld section, insert lazy pointers here
8230 fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
8231 inserted = true;
8232 break;
8233 }
8234 curSection = nextSection;
8235 }
8236 prevAtom = atom;
8237 }
8238 if ( !inserted ) {
8239 throw "can't insert lazy pointers, __dyld section not found";
8240 }
8241 }
8242
8243 // add lazy pointers to fAllAtoms
8244 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
8245 ObjectFile::Section* curSection = NULL;
8246 ObjectFile::Atom* prevAtom = NULL;
8247 bool inserted = false;
8248 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8249 ObjectFile::Atom* atom = *it;
8250 ObjectFile::Section* nextSection = atom->getSection();
8251 if ( nextSection != curSection ) {
8252 if ( (prevAtom != NULL) &&
8253 ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0)
8254 || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0)
8255 || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) {
8256 // found end of __dyld section, insert lazy pointers here
8257 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
8258 inserted = true;
8259 break;
8260 }
8261 curSection = nextSection;
8262 }
8263 prevAtom = atom;
8264 }
8265 if ( !inserted ) {
8266 throw "can't insert lazy pointers, __dyld section not found";
8267 }
8268 }
8269
8270
8271 }
8272
8273 template <typename A>
8274 void Writer<A>::createSplitSegContent()
8275 {
8276 // build LC_SEGMENT_SPLIT_INFO once all atoms exist
8277 if ( fSplitCodeToDataContentAtom != NULL ) {
8278 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8279 ObjectFile::Atom* atom = *it;
8280 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8281 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8282 ObjectFile::Reference* ref = *rit;
8283 switch ( ref->getTargetBinding()) {
8284 case ObjectFile::Reference::kUnboundByName:
8285 case ObjectFile::Reference::kDontBind:
8286 break;
8287 case ObjectFile::Reference::kBoundByName:
8288 case ObjectFile::Reference::kBoundDirectly:
8289 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
8290 this->addCrossSegmentRef(atom, ref);
8291 }
8292 break;
8293 }
8294 }
8295 }
8296 // bad codegen may cause LC_SEGMENT_SPLIT_INFO to be removed
8297 adjustLoadCommandsAndPadding();
8298 }
8299
8300 }
8301
8302
8303 template <typename A>
8304 void Writer<A>::synthesizeUnwindInfoTable()
8305 {
8306 if ( fUnwindInfoAtom != NULL ) {
8307 // walk every atom and gets its unwind info
8308 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8309 ObjectFile::Atom* atom = *it;
8310 if ( atom->beginUnwind() == atom->endUnwind() ) {
8311 // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
8312 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
8313 fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL, NULL);
8314 }
8315 else {
8316 // atom has unwind
8317 for ( ObjectFile::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
8318 fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getFDE(), atom->getLSDA(), atom->getPersonalityPointer());
8319 }
8320 }
8321 }
8322 }
8323 }
8324
8325
8326
8327 template <typename A>
8328 void Writer<A>::partitionIntoSections()
8329 {
8330 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
8331
8332 // for every atom, set its sectionInfo object and section offset
8333 // build up fSegmentInfos along the way
8334 ObjectFile::Section* curSection = (ObjectFile::Section*)(-1);
8335 SectionInfo* currentSectionInfo = NULL;
8336 SegmentInfo* currentSegmentInfo = NULL;
8337 SectionInfo* cstringSectionInfo = NULL;
8338 unsigned int sectionIndex = 1;
8339 fSegmentInfos.reserve(8);
8340 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
8341 ObjectFile::Atom* atom = (*fAllAtoms)[i];
8342 if ( ((atom->getSection() != curSection) || (curSection==NULL))
8343 && ((currentSectionInfo == NULL)
8344 || (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)
8345 || (strcmp(atom->getSegment().getName(),currentSectionInfo->fSegmentName) != 0)) ) {
8346 if ( oneSegmentCommand ) {
8347 if ( currentSegmentInfo == NULL ) {
8348 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8349 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8350 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8351 this->fSegmentInfos.push_back(currentSegmentInfo);
8352 }
8353 currentSectionInfo = new SectionInfo();
8354 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8355 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8356 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8357 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8358 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
8359 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8360 currentSectionInfo->setIndex(sectionIndex++);
8361 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8362 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
8363 cstringSectionInfo = currentSectionInfo;
8364 }
8365 else {
8366 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
8367 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8368 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
8369 uint32_t initprot = 0;
8370 if ( atom->getSegment().isContentReadable() )
8371 initprot |= VM_PROT_READ;
8372 if ( atom->getSegment().isContentWritable() )
8373 initprot |= VM_PROT_WRITE;
8374 if ( atom->getSegment().isContentExecutable() )
8375 initprot |= VM_PROT_EXECUTE;
8376 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
8377 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
8378 currentSegmentInfo->fInitProtection = initprot;
8379 if ( initprot == 0 )
8380 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
8381 else if ( fOptions.architecture() == CPU_TYPE_ARM )
8382 currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init
8383 else
8384 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8385 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
8386 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
8387 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
8388 currentSegmentInfo->fInitProtection = it->init;
8389 currentSegmentInfo->fMaxProtection = it->max;
8390 }
8391 }
8392 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
8393 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
8394 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
8395 currentSegmentInfo->fIndependentAddress = true;
8396 if ( (fOptions.outputKind() == Options::kPreload) && (strcmp(currentSegmentInfo->fName, "__LINKEDIT")==0) )
8397 currentSegmentInfo->fHasLoadCommand = false;
8398 if ( strcmp(currentSegmentInfo->fName, "__HEADER")==0 )
8399 currentSegmentInfo->fHasLoadCommand = false;
8400 this->fSegmentInfos.push_back(currentSegmentInfo);
8401 }
8402 currentSectionInfo = new SectionInfo();
8403 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
8404 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8405 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8406 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8407 // check for -sectalign override
8408 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
8409 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
8410 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
8411 currentSectionInfo->fAlignment = it->alignment;
8412 }
8413 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8414 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
8415 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8416 currentSectionInfo->setIndex(sectionIndex++);
8417 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8418 }
8419 //fprintf(stderr, "new section %s for atom %s\n", atom->getSectionName(), atom->getDisplayName());
8420 if ( strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0 ) {
8421 fLoadCommandsSection = currentSectionInfo;
8422 fLoadCommandsSegment = currentSegmentInfo;
8423 }
8424 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
8425 currentSectionInfo->fAllLazyPointers = true;
8426 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
8427 currentSectionInfo->fAllLazyPointers = true;
8428 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) )
8429 currentSectionInfo->fAllLazyDylibPointers = true;
8430 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
8431 currentSectionInfo->fAllNonLazyPointers = true;
8432 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
8433 currentSectionInfo->fAllNonLazyPointers = true;
8434 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
8435 currentSectionInfo->fAllNonLazyPointers = true;
8436 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
8437 currentSectionInfo->fAllStubs = true;
8438 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
8439 currentSectionInfo->fAllStubs = true;
8440 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
8441 currentSectionInfo->fAllStubs = true;
8442 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
8443 currentSectionInfo->fAllStubs = true;
8444 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) )
8445 currentSectionInfo->fAllStubs = true;
8446 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) )
8447 currentSectionInfo->fAllStubs = true;
8448 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
8449 currentSectionInfo->fAllSelfModifyingStubs = true;
8450 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
8451 }
8452 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__stub_helper") == 0) )
8453 currentSectionInfo->fAllStubHelpers = true;
8454 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) )
8455 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
8456 curSection = atom->getSection();
8457 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers
8458 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) {
8459 fSymbolTableCommands->needDynamicTable();
8460 }
8461 }
8462 // any non-zero fill atoms make whole section marked not-zero-fill
8463 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
8464 currentSectionInfo->fAllZeroFill = false;
8465 // change section object to be Writer's SectionInfo object
8466 atom->setSection(currentSectionInfo);
8467 // section alignment is that of a contained atom with the greatest alignment
8468 uint8_t atomAlign = atom->getAlignment().powerOf2;
8469 if ( currentSectionInfo->fAlignment < atomAlign )
8470 currentSectionInfo->fAlignment = atomAlign;
8471 // calculate section offset for this atom
8472 uint64_t offset = currentSectionInfo->fSize;
8473 uint64_t alignment = 1 << atomAlign;
8474 uint64_t currentModulus = (offset % alignment);
8475 uint64_t requiredModulus = atom->getAlignment().modulus;
8476 if ( currentModulus != requiredModulus ) {
8477 if ( requiredModulus > currentModulus )
8478 offset += requiredModulus-currentModulus;
8479 else
8480 offset += requiredModulus+alignment-currentModulus;
8481 }
8482 atom->setSectionOffset(offset);
8483 uint64_t curAtomSize = atom->getSize();
8484 currentSectionInfo->fSize = offset + curAtomSize;
8485 // add atom to section vector
8486 currentSectionInfo->fAtoms.push_back(atom);
8487 //fprintf(stderr, " adding atom %p %s size=0x%0llX to section %p %s from %s\n", atom, atom->getDisplayName(), atom->getSize(),
8488 // currentSectionInfo, currentSectionInfo->fSectionName, atom->getFile()->getPath());
8489 // update largest size
8490 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
8491 fLargestAtomSize = curAtomSize;
8492 }
8493 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
8494 // when merging cstring sections in .o files, all strings need to use the max alignment
8495 uint64_t offset = 0;
8496 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
8497 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
8498 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
8499 ObjectFile::Atom* atom = *it;
8500 atom->setSectionOffset(offset);
8501 offset += atom->getSize();
8502 }
8503 cstringSectionInfo->fSize = offset;
8504 }
8505 }
8506
8507
8508 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
8509 class TargetAndOffsetComparor
8510 {
8511 public:
8512 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
8513 {
8514 if ( left.atom != right.atom )
8515 return ( left.atom < right.atom );
8516 return ( left.offset < right.offset );
8517 }
8518 };
8519
8520 template <>
8521 bool Writer<ppc>::addBranchIslands()
8522 {
8523 return this->addPPCBranchIslands();
8524 }
8525
8526 template <>
8527 bool Writer<ppc64>::addBranchIslands()
8528 {
8529 return this->addPPCBranchIslands();
8530 }
8531
8532 template <>
8533 bool Writer<x86>::addBranchIslands()
8534 {
8535 // x86 branches can reach entire 4G address space, so no need for branch islands
8536 return false;
8537 }
8538
8539 template <>
8540 bool Writer<x86_64>::addBranchIslands()
8541 {
8542 // x86 branches can reach entire 4G size of largest image
8543 return false;
8544 }
8545
8546 template <>
8547 bool Writer<arm>::addBranchIslands()
8548 {
8549 // arm branch islands not (yet) supported
8550 // you can instead compile with -mlong-call
8551 return false;
8552 }
8553
8554 template <>
8555 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
8556 {
8557 switch (kind) {
8558 case ppc::kBranch24:
8559 case ppc::kBranch24WeakImport:
8560 return true;
8561 }
8562 return false;
8563 }
8564
8565 template <>
8566 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
8567 {
8568 switch (kind) {
8569 case ppc64::kBranch24:
8570 case ppc64::kBranch24WeakImport:
8571 return true;
8572 }
8573 return false;
8574 }
8575
8576 //
8577 // PowerPC can do PC relative branches as far as +/-16MB.
8578 // If a branch target is >16MB then we insert one or more
8579 // "branch islands" between the branch and its target that
8580 // allows island hoping to the target.
8581 //
8582 // Branch Island Algorithm
8583 //
8584 // If the __TEXT segment < 16MB, then no branch islands needed
8585 // Otherwise, every 14MB into the __TEXT segment a region is
8586 // added which can contain branch islands. Every out of range
8587 // bl instruction is checked. If it crosses a region, an island
8588 // is added to that region with the same target and the bl is
8589 // adjusted to target the island instead.
8590 //
8591 // In theory, if too many islands are added to one region, it
8592 // could grow the __TEXT enough that other previously in-range
8593 // bl branches could be pushed out of range. We reduce the
8594 // probability this could happen by placing the ranges every
8595 // 15MB which means the region would have to be 1MB (256K islands)
8596 // before any branches could be pushed out of range.
8597 //
8598 template <typename A>
8599 bool Writer<A>::addPPCBranchIslands()
8600 {
8601 bool log = false;
8602 bool result = false;
8603 // Can only possibly need branch islands if __TEXT segment > 16M
8604 if ( fLoadCommandsSegment->fSize > 16000000 ) {
8605 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
8606 const uint32_t kBetweenRegions = 14*1024*1024; // place regions of islands every 14MB in __text section
8607 SectionInfo* textSection = NULL;
8608 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
8609 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
8610 textSection = *it;
8611 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
8612 break;
8613 }
8614 }
8615 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
8616 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
8617 AtomToIsland regionsMap[kIslandRegionsCount];
8618 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
8619 unsigned int islandCount = 0;
8620 if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
8621
8622 // create islands for branch references that are out of range
8623 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8624 ObjectFile::Atom* atom = *it;
8625 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8626 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8627 ObjectFile::Reference* ref = *rit;
8628 if ( this->isBranch24Reference(ref->getKind()) ) {
8629 ObjectFile::Atom& target = ref->getTarget();
8630 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
8631 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
8632 int64_t displacement = dstAddr - srcAddr;
8633 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
8634 const int64_t kFifteenMegLimit = kBetweenRegions;
8635 if ( displacement > kFifteenMegLimit ) {
8636 // create forward branch chain
8637 ObjectFile::Atom* nextTarget = &target;
8638 uint64_t nextTargetOffset = ref->getTargetOffset();
8639 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
8640 AtomToIsland* region = &regionsMap[i];
8641 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
8642 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
8643 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8644 if ( pos == region->end() ) {
8645 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
8646 island->setSection(textSection);
8647 (*region)[finalTargetAndOffset] = island;
8648 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8649 regionsIslands[i].push_back(island);
8650 ++islandCount;
8651 nextTarget = island;
8652 nextTargetOffset = 0;
8653 }
8654 else {
8655 nextTarget = pos->second;
8656 nextTargetOffset = 0;
8657 }
8658 }
8659 }
8660 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
8661 ref->setTarget(*nextTarget, nextTargetOffset);
8662 }
8663 else if ( displacement < (-kFifteenMegLimit) ) {
8664 // create back branching chain
8665 ObjectFile::Atom* prevTarget = &target;
8666 uint64_t prevTargetOffset = ref->getTargetOffset();
8667 for (int i=0; i < kIslandRegionsCount ; ++i) {
8668 AtomToIsland* region = &regionsMap[i];
8669 int64_t islandRegionAddr = kBetweenRegions * (i+1);
8670 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
8671 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8672 if ( pos == region->end() ) {
8673 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
8674 island->setSection(textSection);
8675 (*region)[finalTargetAndOffset] = island;
8676 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8677 regionsIslands[i].push_back(island);
8678 ++islandCount;
8679 prevTarget = island;
8680 prevTargetOffset = 0;
8681 }
8682 else {
8683 prevTarget = pos->second;
8684 prevTargetOffset = 0;
8685 }
8686 }
8687 }
8688 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
8689 ref->setTarget(*prevTarget, prevTargetOffset);
8690 }
8691 }
8692 }
8693 }
8694
8695 // insert islands into __text section and adjust section offsets
8696 if ( islandCount > 0 ) {
8697 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
8698 std::vector<ObjectFile::Atom*> newAtomList;
8699 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
8700 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
8701 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
8702 int regionIndex = 0;
8703 uint64_t atomSlide = 0;
8704 uint64_t sectionOffset = 0;
8705 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
8706 ObjectFile::Atom* atom = *it;
8707 if ( (atom->getAddress()+atom->getSize()) > islandRegionAddr ) {
8708 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
8709 sectionOffset = islandStartOffset;
8710 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
8711 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8712 ObjectFile::Atom* islandAtom = *rit;
8713 newAtomList.push_back(islandAtom);
8714 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8715 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8716 islandAtom->setSectionOffset(sectionOffset);
8717 sectionOffset += islandAtom->getSize();
8718 }
8719 ++regionIndex;
8720 islandRegionAddr += kBetweenRegions;
8721 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
8722 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
8723 }
8724 newAtomList.push_back(atom);
8725 if ( atomSlide != 0 )
8726 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
8727 }
8728 sectionOffset = textSection->fSize+atomSlide;
8729 // put any remaining islands at end of __text section
8730 if ( regionIndex < kIslandRegionsCount ) {
8731 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
8732 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8733 ObjectFile::Atom* islandAtom = *rit;
8734 newAtomList.push_back(islandAtom);
8735 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8736 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8737 islandAtom->setSectionOffset(sectionOffset);
8738 sectionOffset += islandAtom->getSize();
8739 }
8740 }
8741
8742 textSection->fAtoms = newAtomList;
8743 textSection->fSize = sectionOffset;
8744 result = true;
8745 }
8746
8747 }
8748 return result;
8749 }
8750
8751
8752 template <typename A>
8753 void Writer<A>::adjustLoadCommandsAndPadding()
8754 {
8755 fSegmentCommands->computeSize();
8756
8757 // recompute load command section offsets
8758 uint64_t offset = 0;
8759 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
8760 const unsigned int atomCount = loadCommandAtoms.size();
8761 for (unsigned int i=0; i < atomCount; ++i) {
8762 ObjectFile::Atom* atom = loadCommandAtoms[i];
8763 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
8764 offset = ( (offset+alignment-1) & (-alignment) );
8765 atom->setSectionOffset(offset);
8766 uint32_t atomSize = atom->getSize();
8767 if ( atomSize > fLargestAtomSize )
8768 fLargestAtomSize = atomSize;
8769 offset += atomSize;
8770 fLoadCommandsSection->fSize = offset;
8771 }
8772
8773 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
8774 const int sectionCount = sectionInfos.size();
8775 uint32_t totalSizeOfTEXTLessHeaderAndLoadCommands = 0;
8776 for(int j=0; j < sectionCount; ++j) {
8777 SectionInfo* curSection = sectionInfos[j];
8778 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8779 break;
8780 totalSizeOfTEXTLessHeaderAndLoadCommands += curSection->fSize;
8781 }
8782 uint64_t paddingSize = 0;
8783 if ( fOptions.outputKind() == Options::kDyld ) {
8784 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
8785 paddingSize = 4096 - (totalSizeOfTEXTLessHeaderAndLoadCommands % 4096);
8786 }
8787 else if ( fOptions.outputKind() == Options::kObjectFile ) {
8788 // mach-o .o files need no padding between load commands and first section
8789 // but leave enough room that the object file could be signed
8790 paddingSize = 32;
8791 }
8792 else if ( fOptions.outputKind() == Options::kPreload ) {
8793 // mach-o MH_PRELOAD files need no padding between load commands and first section
8794 paddingSize = 0;
8795 }
8796 else if ( fOptions.makeEncryptable() ) {
8797 // want load commands to end on a page boundary, so __text starts on page boundary
8798 paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
8799 fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfTEXTLessHeaderAndLoadCommands+paddingSize);
8800 }
8801 else {
8802 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
8803 uint64_t addr = 0;
8804 for(int j=sectionCount-1; j >=0; --j) {
8805 SectionInfo* curSection = sectionInfos[j];
8806 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
8807 addr -= (fLoadCommandsSection->fSize+fMachHeaderAtom->getSize());
8808 paddingSize = addr % fOptions.segmentAlignment();
8809 break;
8810 }
8811 addr -= curSection->fSize;
8812 addr = addr & (0 - (1 << curSection->fAlignment));
8813 }
8814
8815 // if command line requires more padding than this
8816 uint32_t minPad = fOptions.minimumHeaderPad();
8817 if ( fOptions.maxMminimumHeaderPad() ) {
8818 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
8819 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
8820 if ( fOptions.outputKind() == Options::kDynamicLibrary )
8821 altMin += MAXPATHLEN;
8822 if ( altMin > minPad )
8823 minPad = altMin;
8824 }
8825 if ( paddingSize < minPad ) {
8826 int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment();
8827 paddingSize += extraPages * fOptions.segmentAlignment();
8828 }
8829 }
8830
8831 // adjust atom size and update section size
8832 fHeaderPadding->setSize(paddingSize);
8833 for(int j=0; j < sectionCount; ++j) {
8834 SectionInfo* curSection = sectionInfos[j];
8835 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8836 curSection->fSize = paddingSize;
8837 }
8838 }
8839
8840 static uint64_t segmentAlign(uint64_t addr, uint64_t alignment)
8841 {
8842 return ((addr+alignment-1) & (-alignment));
8843 }
8844
8845 // assign file offsets and logical address to all segments
8846 template <typename A>
8847 void Writer<A>::assignFileOffsets()
8848 {
8849 const bool virtualSectionOccupyAddressSpace = ((fOptions.outputKind() != Options::kObjectFile)
8850 && (fOptions.outputKind() != Options::kPreload));
8851 bool haveFixedSegments = false;
8852 uint64_t fileOffset = 0;
8853 uint64_t nextContiguousAddress = fOptions.baseAddress();
8854 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
8855 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
8856
8857 // process segments with fixed addresses (-segaddr)
8858 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
8859 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8860 SegmentInfo* curSegment = *segit;
8861 if ( strcmp(curSegment->fName, it->name) == 0 ) {
8862 curSegment->fBaseAddress = it->address;
8863 curSegment->fFixedAddress = true;
8864 break;
8865 }
8866 }
8867 }
8868
8869 // process segments with fixed addresses (-seg_page_size)
8870 for (std::vector<Options::SegmentSize>::iterator it = fOptions.customSegmentSizes().begin(); it != fOptions.customSegmentSizes().end(); ++it) {
8871 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8872 SegmentInfo* curSegment = *segit;
8873 if ( strcmp(curSegment->fName, it->name) == 0 ) {
8874 curSegment->fPageSize = it->size;
8875 break;
8876 }
8877 }
8878 }
8879
8880 // Run through the segments and each segment's sections to assign addresses
8881 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8882 SegmentInfo* curSegment = *segit;
8883
8884 if ( fOptions.splitSeg() ) {
8885 if ( curSegment->fInitProtection & VM_PROT_WRITE )
8886 nextContiguousAddress = nextWritableAddress;
8887 else
8888 nextContiguousAddress = nextReadOnlyAddress;
8889 }
8890
8891 if ( fOptions.outputKind() == Options::kPreload ) {
8892 if ( strcmp(curSegment->fName, "__HEADER") == 0 )
8893 nextContiguousAddress = 0;
8894 else if ( strcmp(curSegment->fName, "__TEXT") == 0 )
8895 nextContiguousAddress = fOptions.baseAddress();
8896 }
8897
8898 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
8899 curSegment->fFileOffset = fileOffset;
8900
8901 // Set the segment base address
8902 if ( curSegment->fFixedAddress )
8903 haveFixedSegments = true;
8904 else
8905 curSegment->fBaseAddress = segmentAlign(nextContiguousAddress, curSegment->fPageSize);
8906
8907 // We've set the segment address, now run through each section.
8908 uint64_t address = curSegment->fBaseAddress;
8909 SectionInfo* firstZeroFillSection = NULL;
8910 SectionInfo* prevSection = NULL;
8911
8912 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
8913
8914 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
8915 SectionInfo* curSection = *it;
8916
8917 // adjust section address based on alignment
8918 uint64_t alignment = 1 << curSection->fAlignment;
8919 if ( curSection->fAtoms.size() == 1 ) {
8920 // if there is only one atom in section, use modulus for even better layout
8921 ObjectFile::Alignment atomAlign = curSection->fAtoms[0]->getAlignment();
8922 uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
8923 uint64_t currentModulus = (address % atomAlignP2);
8924 if ( currentModulus != atomAlign.modulus ) {
8925 if ( atomAlign.modulus > currentModulus )
8926 address += atomAlign.modulus-currentModulus;
8927 else
8928 address += atomAlign.modulus+atomAlignP2-currentModulus;
8929 }
8930 }
8931 else {
8932 address = ( (address+alignment-1) & (-alignment) );
8933 }
8934
8935 // adjust file offset to match address
8936 if ( prevSection != NULL ) {
8937 if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection )
8938 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
8939 else
8940 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
8941 }
8942
8943 // update section info
8944 curSection->fFileOffset = fileOffset;
8945 curSection->setBaseAddress(address);
8946 //fprintf(stderr, "%s %s addr=0x%llX, fileoffset=0x%llX, size=0x%llX\n", curSegment->fName, curSection->fSectionName, address, fileOffset, curSection->fSize);
8947
8948 // keep track of trailing zero fill sections
8949 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
8950 firstZeroFillSection = curSection;
8951 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && (fOptions.outputKind() != Options::kObjectFile) )
8952 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
8953
8954 // update running pointers
8955 if ( virtualSectionOccupyAddressSpace || !curSection->fVirtualSection )
8956 address += curSection->fSize;
8957 fileOffset += curSection->fSize;
8958
8959 // sanity check size of 32-bit binaries
8960 if ( address > maxAddress() )
8961 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
8962
8963 // update segment info
8964 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
8965 curSegment->fSize = curSegment->fFileSize;
8966 prevSection = curSection;
8967 }
8968
8969 if ( fOptions.outputKind() == Options::kObjectFile ) {
8970 // don't page align .o files
8971 }
8972 else {
8973 // optimize trailing zero-fill sections to not occupy disk space
8974 if ( firstZeroFillSection != NULL ) {
8975 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
8976 fileOffset = firstZeroFillSection->fFileOffset;
8977 }
8978 // page align segment size
8979 curSegment->fFileSize = segmentAlign(curSegment->fFileSize, curSegment->fPageSize);
8980 curSegment->fSize = segmentAlign(curSegment->fSize, curSegment->fPageSize);
8981 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
8982 nextContiguousAddress = segmentAlign(curSegment->fBaseAddress+curSegment->fSize, curSegment->fPageSize);
8983 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
8984 if ( curSegment->fInitProtection & VM_PROT_WRITE )
8985 nextWritableAddress = nextContiguousAddress;
8986 else
8987 nextReadOnlyAddress = nextContiguousAddress;
8988 }
8989 }
8990 //fprintf(stderr, "end of seg %s, fileoffset=0x%llX, nextContiguousAddress=0x%llX\n", curSegment->fName, fileOffset, nextContiguousAddress);
8991 }
8992
8993 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
8994 if ( haveFixedSegments ) {
8995 int segCount = fSegmentInfos.size();
8996 for(int i=0; i < segCount; ++i) {
8997 SegmentInfo* segment1 = fSegmentInfos[i];
8998
8999 for(int j=0; j < segCount; ++j) {
9000 if ( i != j ) {
9001 SegmentInfo* segment2 = fSegmentInfos[j];
9002
9003 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
9004 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
9005 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9006 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9007 }
9008 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
9009 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
9010 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9011 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9012 }
9013 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
9014 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
9015 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
9016 }
9017 }
9018 }
9019 }
9020 }
9021
9022 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
9023 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9024 SegmentInfo* curSegment = *segit;
9025 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
9026 if ( fFirstWritableSegment == NULL )
9027 fFirstWritableSegment = curSegment;
9028 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
9029 fWritableSegmentPastFirst4GB = true;
9030 }
9031 }
9032
9033 // record size of encrypted part of __TEXT segment
9034 if ( fOptions.makeEncryptable() ) {
9035 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
9036 SegmentInfo* curSegment = *segit;
9037 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
9038 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
9039 break;
9040 }
9041 }
9042 }
9043
9044 }
9045
9046 template <typename A>
9047 void Writer<A>::adjustLinkEditSections()
9048 {
9049 // link edit content is always in last segment
9050 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
9051 unsigned int firstLinkEditSectionIndex = 0;
9052 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
9053 ++firstLinkEditSectionIndex;
9054
9055 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
9056 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
9057 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
9058 if ( fPadSegmentInfo != NULL ) {
9059 // insert __4GBFILL segment into segments vector before LINKEDIT
9060 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
9061 if ( *it == lastSeg ) {
9062 fSegmentInfos.insert(it, fPadSegmentInfo);
9063 break;
9064 }
9065 }
9066 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
9067 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
9068 fPadSegmentInfo->fBaseAddress = address;
9069 // adjust LINKEDIT to start at zeroPageSize
9070 address = fOptions.zeroPageSize();
9071 lastSeg->fBaseAddress = fOptions.zeroPageSize();
9072 }
9073 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
9074 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
9075 // adjust section address based on alignment
9076 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
9077 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
9078 address += pad;
9079 fileOffset += pad; // adjust file offset to match address
9080 lastSeg->fSections[i]->setBaseAddress(address);
9081 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
9082 lastSeg->fSections[i]->setBaseAddress(0);
9083 lastSeg->fSections[i]->fFileOffset = fileOffset;
9084 uint64_t sectionOffset = 0;
9085 for (unsigned int j=0; j < atoms.size(); ++j) {
9086 ObjectFile::Atom* atom = atoms[j];
9087 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
9088 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
9089 atom->setSectionOffset(sectionOffset);
9090 uint64_t size = atom->getSize();
9091 sectionOffset += size;
9092 if ( size > fLargestAtomSize )
9093 fLargestAtomSize = size;
9094 }
9095 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
9096 lastSeg->fSections[i]->fSize = sectionOffset;
9097 fileOffset += sectionOffset;
9098 address += sectionOffset;
9099 }
9100 if ( fOptions.outputKind() == Options::kObjectFile ) {
9101 //lastSeg->fBaseAddress = 0;
9102 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
9103 //lastSeg->fFileOffset = 0;
9104 //lastSeg->fFileSize =
9105 }
9106 else {
9107 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
9108 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
9109 }
9110 }
9111
9112
9113 template <typename A>
9114 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
9115 {
9116 switch ( fWriter.fOptions.outputKind() ) {
9117 case Options::kDynamicExecutable:
9118 case Options::kStaticExecutable:
9119 return ObjectFile::Atom::scopeGlobal;
9120 case Options::kDynamicLibrary:
9121 case Options::kDynamicBundle:
9122 case Options::kDyld:
9123 case Options::kObjectFile:
9124 case Options::kPreload:
9125 case Options::kKextBundle:
9126 return ObjectFile::Atom::scopeLinkageUnit;
9127 }
9128 throw "unknown header type";
9129 }
9130
9131 template <typename A>
9132 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
9133 {
9134 switch ( fWriter.fOptions.outputKind() ) {
9135 case Options::kDynamicExecutable:
9136 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
9137 case Options::kStaticExecutable:
9138 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
9139 case Options::kDynamicLibrary:
9140 case Options::kDynamicBundle:
9141 case Options::kDyld:
9142 return ObjectFile::Atom::kSymbolTableIn;
9143 case Options::kObjectFile:
9144 case Options::kPreload:
9145 case Options::kKextBundle:
9146 return ObjectFile::Atom::kSymbolTableNotIn;
9147 }
9148 throw "unknown header type";
9149 }
9150
9151 template <typename A>
9152 const char* MachHeaderAtom<A>::getName() const
9153 {
9154 switch ( fWriter.fOptions.outputKind() ) {
9155 case Options::kDynamicExecutable:
9156 case Options::kStaticExecutable:
9157 return "__mh_execute_header";
9158 case Options::kDynamicLibrary:
9159 return "__mh_dylib_header";
9160 case Options::kDynamicBundle:
9161 return "__mh_bundle_header";
9162 case Options::kObjectFile:
9163 case Options::kPreload:
9164 case Options::kKextBundle:
9165 return NULL;
9166 case Options::kDyld:
9167 return "__mh_dylinker_header";
9168 }
9169 throw "unknown header type";
9170 }
9171
9172 template <typename A>
9173 const char* MachHeaderAtom<A>::getDisplayName() const
9174 {
9175 switch ( fWriter.fOptions.outputKind() ) {
9176 case Options::kDynamicExecutable:
9177 case Options::kStaticExecutable:
9178 case Options::kDynamicLibrary:
9179 case Options::kDynamicBundle:
9180 case Options::kDyld:
9181 return this->getName();
9182 case Options::kObjectFile:
9183 case Options::kPreload:
9184 case Options::kKextBundle:
9185 return "mach header";
9186 }
9187 throw "unknown header type";
9188 }
9189
9190 template <typename A>
9191 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
9192 {
9193 // get file type
9194 uint32_t fileType = 0;
9195 switch ( fWriter.fOptions.outputKind() ) {
9196 case Options::kDynamicExecutable:
9197 case Options::kStaticExecutable:
9198 fileType = MH_EXECUTE;
9199 break;
9200 case Options::kDynamicLibrary:
9201 fileType = MH_DYLIB;
9202 break;
9203 case Options::kDynamicBundle:
9204 fileType = MH_BUNDLE;
9205 break;
9206 case Options::kObjectFile:
9207 fileType = MH_OBJECT;
9208 break;
9209 case Options::kDyld:
9210 fileType = MH_DYLINKER;
9211 break;
9212 case Options::kPreload:
9213 fileType = MH_PRELOAD;
9214 break;
9215 case Options::kKextBundle:
9216 fileType = MH_KEXT_BUNDLE;
9217 break;
9218 }
9219
9220 // get flags
9221 uint32_t flags = 0;
9222 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
9223 if ( fWriter.fCanScatter )
9224 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
9225 }
9226 else {
9227 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
9228 flags |= MH_NOUNDEFS;
9229 }
9230 else if ( fWriter.fOptions.outputKind() == Options::kPreload ) {
9231 flags |= MH_NOUNDEFS;
9232 if ( fWriter.fOptions.positionIndependentExecutable() )
9233 flags |= MH_PIE;
9234 }
9235 else {
9236 flags = MH_DYLDLINK;
9237 if ( fWriter.fOptions.bindAtLoad() )
9238 flags |= MH_BINDATLOAD;
9239 switch ( fWriter.fOptions.nameSpace() ) {
9240 case Options::kTwoLevelNameSpace:
9241 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
9242 break;
9243 case Options::kFlatNameSpace:
9244 break;
9245 case Options::kForceFlatNameSpace:
9246 flags |= MH_FORCE_FLAT;
9247 break;
9248 }
9249 bool hasWeakDefines = fWriter.fHasWeakExports;
9250 if ( fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->size() != 0 ) {
9251 for(std::set<const ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
9252 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
9253 if ( fWriter.shouldExport(**it) ) {
9254 hasWeakDefines = true;
9255 break;
9256 }
9257 }
9258 }
9259 if ( hasWeakDefines )
9260 flags |= MH_WEAK_DEFINES;
9261 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
9262 flags |= MH_BINDS_TO_WEAK;
9263 if ( fWriter.fOptions.prebind() )
9264 flags |= MH_PREBOUND;
9265 if ( fWriter.fOptions.splitSeg() )
9266 flags |= MH_SPLIT_SEGS;
9267 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
9268 flags |= MH_NO_REEXPORTED_DYLIBS;
9269 if ( fWriter.fOptions.positionIndependentExecutable() )
9270 flags |= MH_PIE;
9271 if ( fWriter.fOptions.markAutoDeadStripDylib() )
9272 flags |= MH_DEAD_STRIPPABLE_DYLIB;
9273 }
9274 if ( fWriter.fOptions.hasExecutableStack() )
9275 flags |= MH_ALLOW_STACK_EXECUTION;
9276 if ( fWriter.fOptions.readerOptions().fRootSafe )
9277 flags |= MH_ROOT_SAFE;
9278 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
9279 flags |= MH_SETUID_SAFE;
9280 }
9281
9282 // get commands info
9283 uint32_t commandsSize = 0;
9284 uint32_t commandsCount = 0;
9285
9286 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
9287 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
9288 ObjectFile::Atom* atom = *it;
9289 commandsSize += atom->getSize();
9290 // segment and symbol table atoms can contain more than one load command
9291 if ( atom == fWriter.fSegmentCommands )
9292 commandsCount += fWriter.fSegmentCommands->commandCount();
9293 else if ( atom == fWriter.fSymbolTableCommands )
9294 commandsCount += fWriter.fSymbolTableCommands->commandCount();
9295 else if ( atom->getSize() != 0 )
9296 ++commandsCount;
9297 }
9298
9299 // fill out mach_header
9300 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
9301 setHeaderInfo(*mh);
9302 mh->set_filetype(fileType);
9303 mh->set_ncmds(commandsCount);
9304 mh->set_sizeofcmds(commandsSize);
9305 mh->set_flags(flags);
9306 }
9307
9308 template <>
9309 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
9310 {
9311 header.set_magic(MH_MAGIC);
9312 header.set_cputype(CPU_TYPE_POWERPC);
9313 header.set_cpusubtype(fWriter.fCpuConstraint);
9314 }
9315
9316 template <>
9317 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
9318 {
9319 header.set_magic(MH_MAGIC_64);
9320 header.set_cputype(CPU_TYPE_POWERPC64);
9321 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9322 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
9323 else
9324 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
9325 header.set_reserved(0);
9326 }
9327
9328 template <>
9329 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
9330 {
9331 header.set_magic(MH_MAGIC);
9332 header.set_cputype(CPU_TYPE_I386);
9333 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
9334 }
9335
9336 template <>
9337 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
9338 {
9339 header.set_magic(MH_MAGIC_64);
9340 header.set_cputype(CPU_TYPE_X86_64);
9341 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9342 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
9343 else
9344 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
9345 header.set_reserved(0);
9346 }
9347
9348 template <>
9349 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
9350 {
9351 header.set_magic(MH_MAGIC);
9352 header.set_cputype(CPU_TYPE_ARM);
9353 header.set_cpusubtype(fWriter.fCpuConstraint);
9354 }
9355
9356 template <typename A>
9357 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
9358 : WriterAtom<A>(writer, Segment::fgStackSegment)
9359 {
9360 if ( stackGrowsDown() )
9361 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
9362 else
9363 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
9364 }
9365
9366
9367 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
9368 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
9369 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
9370 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
9371 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
9372
9373 template <typename A>
9374 void SegmentLoadCommandsAtom<A>::computeSize()
9375 {
9376 uint64_t size = 0;
9377 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9378 int segCount = 0;
9379 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9380 SegmentInfo* seg = *it;
9381 if ( seg->fHasLoadCommand ) {
9382 ++segCount;
9383 size += sizeof(macho_segment_command<P>);
9384 std::vector<SectionInfo*>& sectionInfos = seg->fSections;
9385 const int sectionCount = sectionInfos.size();
9386 for(int j=0; j < sectionCount; ++j) {
9387 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
9388 size += sizeof(macho_section<P>);
9389 }
9390 }
9391 }
9392 fSize = size;
9393 fCommandCount = segCount;
9394 if ( fWriter.fPadSegmentInfo != NULL ) {
9395 ++fCommandCount;
9396 fSize += sizeof(macho_segment_command<P>);
9397 }
9398 }
9399
9400 template <>
9401 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
9402 {
9403 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9404 }
9405
9406 template <>
9407 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
9408 {
9409 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9410 }
9411
9412 template <>
9413 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
9414 {
9415 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9416 }
9417
9418 template <>
9419 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
9420 {
9421 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9422 }
9423
9424 template <>
9425 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
9426 {
9427 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9428 }
9429
9430 template <typename A>
9431 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9432 {
9433 uint64_t size = this->getSize();
9434 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
9435 bzero(buffer, size);
9436 uint8_t* p = buffer;
9437 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9438 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9439 SegmentInfo* segInfo = *it;
9440 if ( ! segInfo->fHasLoadCommand )
9441 continue;
9442 const int sectionCount = segInfo->fSections.size();
9443 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
9444 cmd->set_cmd(macho_segment_command<P>::CMD);
9445 cmd->set_segname(segInfo->fName);
9446 cmd->set_vmaddr(segInfo->fBaseAddress);
9447 cmd->set_vmsize(oneSegment ? 0 : segInfo->fSize);
9448 cmd->set_fileoff(segInfo->fFileOffset);
9449 cmd->set_filesize(oneSegment ? 0 : segInfo->fFileSize);
9450 cmd->set_maxprot(segInfo->fMaxProtection);
9451 cmd->set_initprot(segInfo->fInitProtection);
9452 // add sections array
9453 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
9454 unsigned int sectionsEmitted = 0;
9455 for (int j=0; j < sectionCount; ++j) {
9456 SectionInfo* sectInfo = segInfo->fSections[j];
9457 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
9458 macho_section<P>* sect = &sections[sectionsEmitted++];
9459 if ( oneSegment ) {
9460 // .o file segment does not cover load commands, so recalc at first real section
9461 if ( sectionsEmitted == 1 ) {
9462 cmd->set_vmaddr(sectInfo->getBaseAddress());
9463 cmd->set_fileoff(sectInfo->fFileOffset);
9464 }
9465 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
9466 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
9467 }
9468 sect->set_sectname(sectInfo->fSectionName);
9469 sect->set_segname(sectInfo->fSegmentName);
9470 sect->set_addr(sectInfo->getBaseAddress());
9471 sect->set_size(sectInfo->fSize);
9472 sect->set_offset(sectInfo->fFileOffset);
9473 sect->set_align(sectInfo->fAlignment);
9474 if ( sectInfo->fRelocCount != 0 ) {
9475 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
9476 sect->set_nreloc(sectInfo->fRelocCount);
9477 }
9478 if ( sectInfo->fAllZeroFill ) {
9479 sect->set_flags(S_ZEROFILL);
9480 sect->set_offset(0);
9481 }
9482 else if ( sectInfo->fAllLazyPointers ) {
9483 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
9484 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9485 }
9486 else if ( sectInfo->fAllLazyDylibPointers ) {
9487 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
9488 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9489 }
9490 else if ( sectInfo->fAllNonLazyPointers ) {
9491 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
9492 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9493 }
9494 else if ( sectInfo->fAllStubs ) {
9495 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9496 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9497 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9498 if ( sectInfo->fHasTextLocalRelocs )
9499 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9500 }
9501 else if ( sectInfo->fAllSelfModifyingStubs ) {
9502 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
9503 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9504 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9505 }
9506 else if ( sectInfo->fAllStubHelpers ) {
9507 sect->set_flags(S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9508 if ( sectInfo->fHasTextLocalRelocs )
9509 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9510 }
9511 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCStringType ) {
9512 sect->set_flags(S_CSTRING_LITERALS);
9513 }
9514 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCFIType ) {
9515 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
9516 }
9517 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9518 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
9519 }
9520 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9521 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
9522 }
9523 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9524 sect->set_flags(S_COALESCED);
9525 }
9526 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9527 sect->set_flags(S_COALESCED);
9528 }
9529 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9530 sect->set_flags(S_INTERPOSING);
9531 }
9532 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9533 sect->set_flags(S_4BYTE_LITERALS);
9534 }
9535 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9536 sect->set_flags(S_8BYTE_LITERALS);
9537 }
9538 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9539 sect->set_flags(S_16BYTE_LITERALS);
9540 }
9541 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9542 sect->set_flags(S_LITERAL_POINTERS);
9543 }
9544 else if ( (strcmp(sectInfo->fSectionName, "__objc_selrefs") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9545 sect->set_flags(S_LITERAL_POINTERS);
9546 }
9547 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9548 sect->set_flags(S_LITERAL_POINTERS);
9549 }
9550 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9551 sect->set_flags(S_DTRACE_DOF);
9552 }
9553 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9554 sect->set_flags(S_DTRACE_DOF);
9555 }
9556 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9557 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9558 if ( sectInfo->fHasTextLocalRelocs )
9559 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9560 if ( sectInfo->fHasTextExternalRelocs )
9561 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
9562 }
9563 //fprintf(stderr, "section %s flags=0x%08X\n", sectInfo->fSectionName, sect->flags());
9564 }
9565 }
9566 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
9567 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
9568 cmd->set_nsects(sectionsEmitted);
9569 }
9570 }
9571
9572
9573 template <typename A>
9574 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
9575 : LoadCommandAtom<A>(writer), fNeedsDynamicSymbolTable(false)
9576 {
9577 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
9578 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
9579 switch ( fWriter.fOptions.outputKind() ) {
9580 case Options::kDynamicExecutable:
9581 case Options::kDynamicLibrary:
9582 case Options::kDynamicBundle:
9583 case Options::kDyld:
9584 case Options::kKextBundle:
9585 fNeedsDynamicSymbolTable = true;
9586 break;
9587 case Options::kObjectFile:
9588 case Options::kStaticExecutable:
9589 fNeedsDynamicSymbolTable = false;
9590 case Options::kPreload:
9591 fNeedsDynamicSymbolTable = fWriter.fOptions.positionIndependentExecutable();
9592 break;
9593 }
9594 writer.fSymbolTableCommands = this;
9595 }
9596
9597
9598
9599 template <typename A>
9600 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
9601 {
9602 fNeedsDynamicSymbolTable = true;
9603 }
9604
9605
9606 template <typename A>
9607 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
9608 {
9609 if ( fNeedsDynamicSymbolTable )
9610 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
9611 else
9612 return this->alignedSize(sizeof(macho_symtab_command<P>));
9613 }
9614
9615 template <typename A>
9616 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9617 {
9618 // build LC_SYMTAB command
9619 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
9620 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
9621 symbolTableCmd->set_cmd(LC_SYMTAB);
9622 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
9623 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
9624 symbolTableCmd->set_symoff(fWriter.fSymbolTableCount == 0 ? 0 : fWriter.fSymbolTableAtom->getFileOffset());
9625 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getSize() == 0 ? 0 : fWriter.fStringsAtom->getFileOffset());
9626 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
9627
9628 // build LC_DYSYMTAB command
9629 if ( fNeedsDynamicSymbolTable ) {
9630 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
9631 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
9632 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
9633 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
9634 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
9635 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
9636 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
9637 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
9638 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
9639 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
9640 if ( fWriter.fModuleInfoAtom != NULL ) {
9641 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
9642 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
9643 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
9644 dynamicSymbolTableCmd->set_nmodtab(1);
9645 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
9646 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
9647 }
9648 dynamicSymbolTableCmd->set_indirectsymoff((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->getFileOffset());
9649 dynamicSymbolTableCmd->set_nindirectsyms((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->fTable.size());
9650 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
9651 if ( fWriter.fExternalRelocationsAtom != 0 ) {
9652 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
9653 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
9654 }
9655 if ( fWriter.fLocalRelocationsAtom != 0 ) {
9656 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
9657 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
9658 }
9659 }
9660 }
9661 }
9662
9663
9664 template <typename A>
9665 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
9666 {
9667 return fNeedsDynamicSymbolTable ? 2 : 1;
9668 }
9669
9670 template <typename A>
9671 uint64_t DyldLoadCommandsAtom<A>::getSize() const
9672 {
9673 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
9674 }
9675
9676 template <typename A>
9677 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9678 {
9679 uint64_t size = this->getSize();
9680 bzero(buffer, size);
9681 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
9682 if ( fWriter.fOptions.outputKind() == Options::kDyld )
9683 cmd->set_cmd(LC_ID_DYLINKER);
9684 else
9685 cmd->set_cmd(LC_LOAD_DYLINKER);
9686 cmd->set_cmdsize(this->getSize());
9687 cmd->set_name_offset();
9688 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
9689 }
9690
9691 template <typename A>
9692 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
9693 {
9694 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
9695 }
9696
9697 template <typename A>
9698 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9699 {
9700 uint64_t size = this->getSize();
9701
9702 bzero(buffer, size);
9703 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
9704 cmd->set_cmd(LC_SUB_CLIENT);
9705 cmd->set_cmdsize(size);
9706 cmd->set_client_offset();
9707 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
9708
9709 }
9710
9711 template <typename A>
9712 uint64_t DylibLoadCommandsAtom<A>::getSize() const
9713 {
9714 if ( fOptimizedAway ) {
9715 return 0;
9716 }
9717 else {
9718 const char* path = fInfo.reader->getInstallPath();
9719 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
9720 }
9721 }
9722
9723 template <typename A>
9724 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9725 {
9726 if ( fOptimizedAway )
9727 return;
9728 uint64_t size = this->getSize();
9729 bzero(buffer, size);
9730 const char* path = fInfo.reader->getInstallPath();
9731 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9732 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
9733 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
9734 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
9735 if ( fInfo.options.fLazyLoad )
9736 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
9737 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
9738 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
9739 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9740 cmd->set_cmd(LC_REEXPORT_DYLIB);
9741 else
9742 cmd->set_cmd(LC_LOAD_DYLIB);
9743 cmd->set_cmdsize(this->getSize());
9744 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
9745 cmd->set_current_version(fInfo.reader->getCurrentVersion());
9746 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
9747 cmd->set_name_offset();
9748 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
9749 }
9750
9751
9752
9753 template <typename A>
9754 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
9755 {
9756 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
9757 }
9758
9759 template <typename A>
9760 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9761 {
9762 uint64_t size = this->getSize();
9763 bzero(buffer, size);
9764 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9765 cmd->set_cmd(LC_ID_DYLIB);
9766 cmd->set_cmdsize(this->getSize());
9767 cmd->set_name_offset();
9768 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
9769 cmd->set_current_version(fWriter.fOptions.currentVersion());
9770 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
9771 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
9772 }
9773
9774
9775 template <typename A>
9776 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9777 {
9778 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9779 if (fWriter.fEntryPoint->isThumb())
9780 initAddr |= 1ULL;
9781 bzero(buffer, sizeof(macho_routines_command<P>));
9782 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
9783 cmd->set_cmd(macho_routines_command<P>::CMD);
9784 cmd->set_cmdsize(this->getSize());
9785 cmd->set_init_address(initAddr);
9786 }
9787
9788
9789 template <typename A>
9790 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
9791 {
9792 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
9793 }
9794
9795 template <typename A>
9796 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9797 {
9798 uint64_t size = this->getSize();
9799 bzero(buffer, size);
9800 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
9801 cmd->set_cmd(LC_SUB_UMBRELLA);
9802 cmd->set_cmdsize(this->getSize());
9803 cmd->set_sub_umbrella_offset();
9804 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
9805 }
9806
9807 template <typename A>
9808 void UUIDLoadCommandAtom<A>::generate()
9809 {
9810 switch ( fWriter.fOptions.getUUIDMode() ) {
9811 case Options::kUUIDNone:
9812 fEmit = false;
9813 break;
9814 case Options::kUUIDRandom:
9815 ::uuid_generate_random(fUUID);
9816 fEmit = true;
9817 break;
9818 case Options::kUUIDContent:
9819 bzero(fUUID, 16);
9820 fEmit = true;
9821 break;
9822 }
9823 }
9824
9825 template <typename A>
9826 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
9827 {
9828 memcpy(fUUID, uuid, 16);
9829 }
9830
9831 template <typename A>
9832 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
9833 {
9834 if (fEmit) {
9835 uint64_t size = this->getSize();
9836 bzero(buffer, size);
9837 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
9838 cmd->set_cmd(LC_UUID);
9839 cmd->set_cmdsize(this->getSize());
9840 cmd->set_uuid((uint8_t*)fUUID);
9841 }
9842 }
9843
9844
9845 template <typename A>
9846 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
9847 {
9848 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
9849 }
9850
9851 template <typename A>
9852 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9853 {
9854 uint64_t size = this->getSize();
9855 bzero(buffer, size);
9856 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
9857 cmd->set_cmd(LC_SUB_LIBRARY);
9858 cmd->set_cmdsize(this->getSize());
9859 cmd->set_sub_library_offset();
9860 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
9861 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
9862 }
9863
9864 template <typename A>
9865 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
9866 {
9867 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
9868 }
9869
9870 template <typename A>
9871 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9872 {
9873 uint64_t size = this->getSize();
9874 bzero(buffer, size);
9875 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
9876 cmd->set_cmd(LC_SUB_FRAMEWORK);
9877 cmd->set_cmdsize(this->getSize());
9878 cmd->set_umbrella_offset();
9879 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
9880 }
9881
9882 template <>
9883 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
9884 {
9885 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
9886 }
9887
9888 template <>
9889 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
9890 {
9891 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
9892 }
9893
9894 template <>
9895 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
9896 {
9897 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
9898 }
9899
9900 template <>
9901 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
9902 {
9903 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
9904 }
9905
9906 // We should be picking it up from a header
9907 template <>
9908 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
9909 {
9910 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
9911 }
9912
9913 template <>
9914 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
9915 {
9916 uint64_t size = this->getSize();
9917 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9918 bzero(buffer, size);
9919 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
9920 cmd->set_cmd(LC_UNIXTHREAD);
9921 cmd->set_cmdsize(size);
9922 cmd->set_flavor(1); // PPC_THREAD_STATE
9923 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
9924 cmd->set_thread_register(0, start);
9925 if ( fWriter.fOptions.hasCustomStack() )
9926 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
9927 }
9928
9929
9930 template <>
9931 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
9932 {
9933 uint64_t size = this->getSize();
9934 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9935 bzero(buffer, size);
9936 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
9937 cmd->set_cmd(LC_UNIXTHREAD);
9938 cmd->set_cmdsize(size);
9939 cmd->set_flavor(5); // PPC_THREAD_STATE64
9940 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
9941 cmd->set_thread_register(0, start);
9942 if ( fWriter.fOptions.hasCustomStack() )
9943 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
9944 }
9945
9946 template <>
9947 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
9948 {
9949 uint64_t size = this->getSize();
9950 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9951 bzero(buffer, size);
9952 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
9953 cmd->set_cmd(LC_UNIXTHREAD);
9954 cmd->set_cmdsize(size);
9955 cmd->set_flavor(1); // i386_THREAD_STATE
9956 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
9957 cmd->set_thread_register(10, start);
9958 if ( fWriter.fOptions.hasCustomStack() )
9959 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
9960 }
9961
9962 template <>
9963 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
9964 {
9965 uint64_t size = this->getSize();
9966 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9967 bzero(buffer, size);
9968 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
9969 cmd->set_cmd(LC_UNIXTHREAD);
9970 cmd->set_cmdsize(size);
9971 cmd->set_flavor(x86_THREAD_STATE64);
9972 cmd->set_count(x86_THREAD_STATE64_COUNT);
9973 cmd->set_thread_register(16, start); // rip
9974 if ( fWriter.fOptions.hasCustomStack() )
9975 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
9976 }
9977
9978 template <>
9979 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
9980 {
9981 uint64_t size = this->getSize();
9982 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9983 if ( fWriter.fEntryPoint->isThumb() )
9984 start |= 1ULL;
9985 bzero(buffer, size);
9986 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
9987 cmd->set_cmd(LC_UNIXTHREAD);
9988 cmd->set_cmdsize(size);
9989 cmd->set_flavor(1);
9990 cmd->set_count(17);
9991 cmd->set_thread_register(15, start); // pc
9992 if ( fWriter.fOptions.hasCustomStack() )
9993 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
9994 }
9995
9996 template <typename A>
9997 uint64_t RPathLoadCommandsAtom<A>::getSize() const
9998 {
9999 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
10000 }
10001
10002 template <typename A>
10003 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10004 {
10005 uint64_t size = this->getSize();
10006 bzero(buffer, size);
10007 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
10008 cmd->set_cmd(LC_RPATH);
10009 cmd->set_cmdsize(this->getSize());
10010 cmd->set_path_offset();
10011 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
10012 }
10013
10014
10015
10016 template <typename A>
10017 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10018 {
10019 uint64_t size = this->getSize();
10020 bzero(buffer, size);
10021 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
10022 cmd->set_cmd(LC_ENCRYPTION_INFO);
10023 cmd->set_cmdsize(this->getSize());
10024 cmd->set_cryptoff(fStartOffset);
10025 cmd->set_cryptsize(fEndOffset-fStartOffset);
10026 cmd->set_cryptid(0);
10027 }
10028
10029
10030
10031 template <typename A>
10032 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
10033 {
10034 bzero(buffer, fSize);
10035 }
10036
10037 template <typename A>
10038 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
10039 {
10040 fSize = newSize;
10041 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
10042 if ( fWriter.fLargestAtomSize < newSize )
10043 fWriter.fLargestAtomSize = newSize;
10044 }
10045
10046 template <typename A>
10047 void UnwindInfoAtom<A>::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
10048 ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsdaRef,
10049 ObjectFile::Atom* personalityPointer)
10050 {
10051 Info info;
10052 info.func = func;
10053 if ( fdeRef != NULL )
10054 info.fde = &fdeRef->getTarget();
10055 else
10056 info.fde = NULL;
10057 if ( lsdaRef != NULL ) {
10058 info.lsda = &lsdaRef->getTarget();
10059 info.lsdaOffset = lsdaRef->getTargetOffset();
10060 }
10061 else {
10062 info.lsda = NULL;
10063 info.lsdaOffset = 0;
10064 }
10065 info.personalityPointer = personalityPointer;
10066 info.encoding = encoding;
10067 fInfos.push_back(info);
10068 //fprintf(stderr, "addUnwindInfo() encoding=0x%08X, lsda=%p, lsdaOffset=%d, person=%p, func=%s\n",
10069 // encoding, info.lsda, info.lsdaOffset, personalityPointer, func->getDisplayName());
10070 }
10071
10072 template <>
10073 bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10074 {
10075 return ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
10076 }
10077
10078 template <>
10079 bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10080 {
10081 return ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
10082 }
10083
10084 template <typename A>
10085 bool UnwindInfoAtom<A>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
10086 {
10087 return false;
10088 }
10089
10090
10091 template <typename A>
10092 void UnwindInfoAtom<A>::compressDuplicates(std::vector<Info>& uniqueInfos)
10093 {
10094 // build new list removing entries where next function has same encoding
10095 uniqueInfos.reserve(fInfos.size());
10096 Info last;
10097 last.func = NULL;
10098 last.lsda = NULL;
10099 last.lsdaOffset = 0;
10100 last.personalityPointer = NULL;
10101 last.encoding = 0xFFFFFFFF;
10102 for(typename std::vector<Info>::iterator it=fInfos.begin(); it != fInfos.end(); ++it) {
10103 Info& newInfo = *it;
10104 bool newNeedsDwarf = encodingMeansUseDwarf(newInfo.encoding);
10105 // remove infos which have same encoding and personalityPointer as last one
10106 if ( newNeedsDwarf || (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer)
10107 || (newInfo.lsda != NULL) || (last.lsda != NULL) ) {
10108 uniqueInfos.push_back(newInfo);
10109 }
10110 last = newInfo;
10111 }
10112 //fprintf(stderr, "compressDuplicates() fInfos.size()=%lu, uniqueInfos.size()=%lu\n", fInfos.size(), uniqueInfos.size());
10113 }
10114
10115 template <typename A>
10116 void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings)
10117 {
10118 // scan infos to get frequency counts for each encoding
10119 std::map<uint32_t, unsigned int> encodingsUsed;
10120 unsigned int mostCommonEncodingUsageCount = 0;
10121 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10122 // never put dwarf into common table
10123 if ( encodingMeansUseDwarf(it->encoding) )
10124 continue;
10125 std::map<uint32_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
10126 if ( pos == encodingsUsed.end() ) {
10127 encodingsUsed[it->encoding] = 1;
10128 }
10129 else {
10130 encodingsUsed[it->encoding] += 1;
10131 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
10132 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
10133 }
10134 }
10135 // put the most common encodings into the common table, but at most 127 of them
10136 for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
10137 for (std::map<uint32_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
10138 if ( euit->second == usages ) {
10139 unsigned int size = commonEncodings.size();
10140 if ( size < 127 ) {
10141 commonEncodings[euit->first] = size;
10142 }
10143 }
10144 }
10145 }
10146 }
10147
10148 template <typename A>
10149 void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap)
10150 {
10151 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10152 lsdaIndexOffsetMap[it->func] = fLSDAIndex.size() * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10153 if ( it->lsda != NULL ) {
10154 LSDAEntry entry;
10155 entry.func = it->func;
10156 entry.lsda = it->lsda;
10157 entry.lsdaOffset = it->lsdaOffset;
10158 fLSDAIndex.push_back(entry);
10159 }
10160 }
10161 }
10162
10163 template <typename A>
10164 void UnwindInfoAtom<A>::makePersonalityIndex(std::vector<Info>& uniqueInfos)
10165 {
10166 for(typename std::vector<Info>::iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10167 if ( it->personalityPointer != NULL ) {
10168 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fPersonalityIndexMap.find(it->personalityPointer);
10169 if ( pos == fPersonalityIndexMap.end() ) {
10170 const uint32_t nextIndex = fPersonalityIndexMap.size() + 1;
10171 fPersonalityIndexMap[it->personalityPointer] = nextIndex;
10172 }
10173 uint32_t personalityIndex = fPersonalityIndexMap[it->personalityPointer];
10174 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
10175 }
10176 }
10177 }
10178
10179 template <typename A>
10180 unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize,
10181 unsigned int endIndex, uint8_t*& pageEnd)
10182 {
10183 const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10184 const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
10185 uint8_t* pageStart = pageEnd
10186 - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
10187 - sizeof(unwind_info_regular_second_level_page_header);
10188 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
10189 page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
10190 page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
10191 page->set_entryCount(entriesToAdd);
10192 macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
10193 for (unsigned int i=0; i < entriesToAdd; ++i) {
10194 const Info& info = uniqueInfos[endIndex-entriesToAdd+i];
10195 entryTable[i].set_functionOffset(0);
10196 entryTable[i].set_encoding(info.encoding);
10197 RegFixUp fixup;
10198 fixup.contentPointer = (uint8_t*)(&entryTable[i]);
10199 fixup.func = info.func;
10200 fixup.fde = ( encodingMeansUseDwarf(info.encoding) ? info.fde : NULL );
10201 fRegFixUps.push_back(fixup);
10202 }
10203 //fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
10204 pageEnd = pageStart;
10205 return endIndex - entriesToAdd;
10206 }
10207
10208
10209 template <typename A>
10210 unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
10211 const std::map<uint32_t,unsigned int> commonEncodings,
10212 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
10213 {
10214 const bool log = false;
10215 if (log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
10216 // first pass calculates how many compressed entries we could fit in this sized page
10217 // keep adding entries to page until:
10218 // 1) encoding table plus entry table plus header exceed page size
10219 // 2) the file offset delta from the first to last function > 24 bits
10220 // 3) custom encoding index reachs 255
10221 // 4) run out of uniqueInfos to encode
10222 std::map<uint32_t, unsigned int> pageSpecificEncodings;
10223 uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
10224 std::vector<uint8_t> encodingIndexes;
10225 int index = endIndex-1;
10226 int entryCount = 0;
10227 uint64_t lastEntryAddress = uniqueInfos[index].func->getAddress();
10228 bool canDo = true;
10229 while ( canDo && (index >= 0) ) {
10230 const Info& info = uniqueInfos[index--];
10231 // compute encoding index
10232 unsigned int encodingIndex;
10233 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10234 if ( pos != commonEncodings.end() ) {
10235 encodingIndex = pos->second;
10236 }
10237 else {
10238 // no commmon entry, so add one on this page
10239 uint32_t encoding = info.encoding;
10240 if ( encodingMeansUseDwarf(encoding) ) {
10241 // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
10242 encoding += (index+1);
10243 }
10244 std::map<uint32_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
10245 if ( ppos != pageSpecificEncodings.end() ) {
10246 encodingIndex = pos->second;
10247 }
10248 else {
10249 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
10250 if ( encodingIndex <= 255 ) {
10251 pageSpecificEncodings[encoding] = encodingIndex;
10252 }
10253 else {
10254 canDo = false; // case 3)
10255 if (log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
10256 entryCount, pageSpecificEncodings.size());
10257 }
10258 }
10259 }
10260 if ( canDo )
10261 encodingIndexes.push_back(encodingIndex);
10262 // compute function offset
10263 uint32_t funcOffsetWithInPage = lastEntryAddress - info.func->getAddress();
10264 if ( funcOffsetWithInPage > 0x00FFFF00 ) {
10265 // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
10266 canDo = false; // case 2)
10267 if (log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
10268 }
10269 else {
10270 ++entryCount;
10271 }
10272 // check room for entry
10273 if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
10274 canDo = false; // case 1)
10275 --entryCount;
10276 if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
10277 }
10278 //if (log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
10279 }
10280
10281 // check for cases where it would be better to use a regular (non-compressed) page
10282 const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
10283 + pageSpecificEncodings.size()*sizeof(uint32_t)
10284 + entryCount*sizeof(uint32_t);
10285 if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
10286 const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10287 if ( entryCount < regularEntriesPerPage ) {
10288 return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
10289 }
10290 }
10291
10292 // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
10293 uint32_t pad = 0;
10294 if ( compressPageUsed == (pageSize-4) )
10295 pad = 4;
10296
10297 // second pass fills in page
10298 uint8_t* pageStart = pageEnd - compressPageUsed - pad;
10299 macho_unwind_info_compressed_second_level_page_header<P>* page = (macho_unwind_info_compressed_second_level_page_header<P>*)pageStart;
10300 page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
10301 page->set_entryPageOffset(sizeof(macho_unwind_info_compressed_second_level_page_header<P>));
10302 page->set_entryCount(entryCount);
10303 page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
10304 page->set_encodingsCount(pageSpecificEncodings.size());
10305 uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
10306 // fill in entry table
10307 uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
10308 ObjectFile::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
10309 for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
10310 const Info& info = uniqueInfos[i];
10311 uint8_t encodingIndex;
10312 if ( encodingMeansUseDwarf(info.encoding) ) {
10313 // dwarf entries are always in page specific encodings
10314 encodingIndex = pageSpecificEncodings[info.encoding+i];
10315 }
10316 else {
10317 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10318 if ( pos != commonEncodings.end() )
10319 encodingIndex = pos->second;
10320 else
10321 encodingIndex = pageSpecificEncodings[info.encoding];
10322 }
10323 uint32_t entryIndex = i - endIndex + entryCount;
10324 A::P::E::set32(entiresArray[entryIndex], encodingIndex << 24);
10325 CompressedFixUp funcStartFixUp;
10326 funcStartFixUp.contentPointer = (uint8_t*)(&entiresArray[entryIndex]);
10327 funcStartFixUp.func = info.func;
10328 funcStartFixUp.fromFunc = firstFunc;
10329 fCompressedFixUps.push_back(funcStartFixUp);
10330 if ( encodingMeansUseDwarf(info.encoding) ) {
10331 CompressedEncodingFixUp dwarfStartFixup;
10332 dwarfStartFixup.contentPointer = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]);
10333 dwarfStartFixup.fde = info.fde;
10334 fCompressedEncodingFixUps.push_back(dwarfStartFixup);
10335 }
10336 }
10337 // fill in encodings table
10338 for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
10339 A::P::E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
10340 }
10341
10342 if (log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
10343
10344 // update pageEnd;
10345 pageEnd = pageStart;
10346 return endIndex-entryCount; // endIndex for next page
10347 }
10348
10349 template <> void UnwindInfoAtom<ppc>::generate() { }
10350 template <> void UnwindInfoAtom<ppc64>::generate() { }
10351 template <> void UnwindInfoAtom<arm>::generate() { }
10352
10353
10354 template <typename A>
10355 void UnwindInfoAtom<A>::generate()
10356 {
10357 // only generate table if there are functions with unwind info
10358 if ( fInfos.size() > 0 ) {
10359 // find offset of end of __unwind_info section
10360 SectionInfo* unwindSectionInfo = (SectionInfo*)this->getSection();
10361
10362 // build new list that has proper offsetInImage and remove entries where next function has same encoding
10363 std::vector<Info> uniqueInfos;
10364 this->compressDuplicates(uniqueInfos);
10365
10366 // build personality index, update encodings with personality index
10367 this->makePersonalityIndex(uniqueInfos);
10368 if ( fPersonalityIndexMap.size() > 3 )
10369 throw "too many personality routines for compact unwind to encode";
10370
10371 // put the most common encodings into the common table, but at most 127 of them
10372 std::map<uint32_t, unsigned int> commonEncodings;
10373 this->findCommonEncoding(uniqueInfos, commonEncodings);
10374
10375 // build lsda index
10376 std::map<ObjectFile::Atom*, uint32_t> lsdaIndexOffsetMap;
10377 this->makeLsdaIndex(uniqueInfos, lsdaIndexOffsetMap);
10378
10379 // calculate worst case size for all unwind info pages when allocating buffer
10380 const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10381 const unsigned int pageCount = ((uniqueInfos.size() - 1)/entriesPerRegularPage) + 1;
10382 fPagesContentForDelete = (uint8_t*)calloc(pageCount,4096);
10383 fPagesSize = 0;
10384 if ( fPagesContentForDelete == NULL )
10385 throw "could not allocate space for compact unwind info";
10386 ObjectFile::Atom* secondLevelFirstFuncs[pageCount*3];
10387 uint8_t* secondLevelPagesStarts[pageCount*3];
10388
10389 // make last second level page smaller so that all other second level pages can be page aligned
10390 uint32_t maxLastPageSize = unwindSectionInfo->fFileOffset % 4096;
10391 uint32_t tailPad = 0;
10392 if ( maxLastPageSize < 128 ) {
10393 tailPad = maxLastPageSize;
10394 maxLastPageSize = 4096;
10395 }
10396
10397 // fill in pages in reverse order
10398 unsigned int endIndex = uniqueInfos.size();
10399 unsigned int secondLevelPageCount = 0;
10400 uint8_t* pageEnd = &fPagesContentForDelete[pageCount*4096];
10401 uint32_t pageSize = maxLastPageSize;
10402 while ( endIndex > 0 ) {
10403 endIndex = makeCompressedSecondLevelPage(uniqueInfos, commonEncodings, pageSize, endIndex, pageEnd);
10404 secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
10405 secondLevelFirstFuncs[secondLevelPageCount] = uniqueInfos[endIndex].func;
10406 ++secondLevelPageCount;
10407 pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
10408 }
10409 fPagesContent = pageEnd;
10410 fPagesSize = &fPagesContentForDelete[pageCount*4096] - pageEnd;
10411
10412 // calculate section layout
10413 const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
10414 const uint32_t commonEncodingsArrayCount = commonEncodings.size();
10415 const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
10416 const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
10417 const uint32_t personalityArrayCount = fPersonalityIndexMap.size();
10418 const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
10419 const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
10420 const uint32_t indexCount = secondLevelPageCount+1;
10421 const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
10422 const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
10423 const uint32_t lsdaIndexArrayCount = fLSDAIndex.size();
10424 const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10425 const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
10426
10427
10428 // allocate and fill in section header
10429 fHeaderSize = headerEndSectionOffset;
10430 fHeaderContent = new uint8_t[fHeaderSize];
10431 bzero(fHeaderContent, fHeaderSize);
10432 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)fHeaderContent;
10433 sectionHeader->set_version(UNWIND_SECTION_VERSION);
10434 sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
10435 sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
10436 sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
10437 sectionHeader->set_personalityArrayCount(personalityArrayCount);
10438 sectionHeader->set_indexSectionOffset(indexSectionOffset);
10439 sectionHeader->set_indexCount(indexCount);
10440
10441 // copy common encodings
10442 uint32_t* commonEncodingsTable = (uint32_t*)&fHeaderContent[commonEncodingsArraySectionOffset];
10443 for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
10444 A::P::E::set32(commonEncodingsTable[it->second], it->first);
10445
10446 // make references for personality entries
10447 uint32_t* personalityArray = (uint32_t*)&fHeaderContent[sectionHeader->personalityArraySectionOffset()];
10448 for (std::map<ObjectFile::Atom*, unsigned int>::iterator it=fPersonalityIndexMap.begin(); it != fPersonalityIndexMap.end(); ++it) {
10449 uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - fHeaderContent;
10450 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->first));
10451 }
10452
10453 // build first level index and references
10454 macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&fHeaderContent[indexSectionOffset];
10455 for (unsigned int i=0; i < secondLevelPageCount; ++i) {
10456 unsigned int reverseIndex = secondLevelPageCount - 1 - i;
10457 indexTable[i].set_functionOffset(0);
10458 indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-fPagesContent+headerEndSectionOffset);
10459 indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
10460 uint32_t refOffset = (uint8_t*)&indexTable[i] - fHeaderContent;
10461 fReferences.push_back(new WriterReference<A>(refOffset, A::kImageOffset32, secondLevelFirstFuncs[reverseIndex]));
10462 }
10463 indexTable[secondLevelPageCount].set_functionOffset(0);
10464 indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
10465 indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
10466 fReferences.push_back(new WriterReference<A>((uint8_t*)&indexTable[secondLevelPageCount] - fHeaderContent, A::kImageOffset32,
10467 fInfos.back().func, fInfos.back().func->getSize()+1));
10468
10469 // build lsda references
10470 uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
10471 for (typename std::vector<LSDAEntry>::iterator it = fLSDAIndex.begin(); it != fLSDAIndex.end(); ++it) {
10472 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset, A::kImageOffset32, it->func));
10473 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset+4, A::kImageOffset32, it->lsda, it->lsdaOffset));
10474 lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
10475 }
10476
10477 // make references for regular second level entries
10478 for (typename std::vector<RegFixUp>::iterator it = fRegFixUps.begin(); it != fRegFixUps.end(); ++it) {
10479 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10480 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->func));
10481 if ( it->fde != NULL )
10482 fReferences.push_back(new WriterReference<A>(offset+4, A::kSectionOffset24, it->fde));
10483 }
10484 // make references for compressed second level entries
10485 for (typename std::vector<CompressedFixUp>::iterator it = fCompressedFixUps.begin(); it != fCompressedFixUps.end(); ++it) {
10486 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10487 fReferences.push_back(new WriterReference<A>(offset, A::kPointerDiff24, it->func, 0, it->fromFunc, 0));
10488 }
10489 for (typename std::vector<CompressedEncodingFixUp>::iterator it = fCompressedEncodingFixUps.begin(); it != fCompressedEncodingFixUps.end(); ++it) {
10490 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10491 fReferences.push_back(new WriterReference<A>(offset, A::kSectionOffset24, it->fde));
10492 }
10493
10494 // update section record with new size
10495 unwindSectionInfo->fSize = this->getSize();
10496
10497 // alter alignment so this section lays out so second level tables are page aligned
10498 if ( secondLevelPageCount > 2 )
10499 fAlignment = ObjectFile::Alignment(12, (unwindSectionInfo->fFileOffset - this->getSize()) % 4096);
10500 }
10501
10502 }
10503
10504
10505
10506
10507 template <typename A>
10508 void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10509 {
10510 memcpy(buffer, fHeaderContent, fHeaderSize);
10511 memcpy(&buffer[fHeaderSize], fPagesContent, fPagesSize);
10512 }
10513
10514
10515
10516 template <typename A>
10517 uint64_t LinkEditAtom<A>::getFileOffset() const
10518 {
10519 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
10520 }
10521
10522
10523 template <typename A>
10524 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
10525 {
10526 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
10527 }
10528
10529 template <typename A>
10530 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10531 {
10532 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
10533 }
10534
10535
10536 template <typename A>
10537 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
10538 {
10539 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
10540 }
10541
10542 template <typename A>
10543 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10544 {
10545 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
10546 }
10547
10548
10549
10550 template <typename A>
10551 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
10552 {
10553 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
10554 }
10555
10556 template <typename A>
10557 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10558 {
10559 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
10560 }
10561
10562 template <typename A>
10563 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
10564 {
10565 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
10566 }
10567
10568 template <typename A>
10569 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10570 {
10571 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
10572 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
10573 }
10574
10575
10576
10577 template <typename A>
10578 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
10579 {
10580 return fTable.size() * sizeof(uint32_t);
10581 }
10582
10583 template <typename A>
10584 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10585 {
10586 uint64_t size = this->getSize();
10587 bzero(buffer, size);
10588 const uint32_t indirectTableSize = fTable.size();
10589 uint32_t* indirectTable = (uint32_t*)buffer;
10590 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
10591 if ( it->indirectIndex < indirectTableSize )
10592 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
10593 else
10594 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
10595 }
10596 }
10597
10598
10599
10600 template <typename A>
10601 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
10602 {
10603 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
10604 + sizeof(macho_dylib_module<P>)
10605 + this->getReferencesCount()*sizeof(uint32_t);
10606 }
10607
10608 template <typename A>
10609 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
10610 {
10611 return this->getFileOffset();
10612 }
10613
10614 template <typename A>
10615 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
10616 {
10617 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
10618 }
10619
10620 template <typename A>
10621 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
10622 {
10623 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
10624 }
10625
10626 template <typename A>
10627 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
10628 {
10629 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
10630 }
10631
10632 template <typename A>
10633 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10634 {
10635 uint64_t size = this->getSize();
10636 bzero(buffer, size);
10637 // create toc. The symbols are already sorted, they are all in the smae module
10638 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
10639 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
10640 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
10641 p->set_module_index(0);
10642 }
10643 // create module table (one entry)
10644 pint_t objcModuleSectionStart = 0;
10645 pint_t objcModuleSectionSize = 0;
10646 uint16_t numInits = 0;
10647 uint16_t numTerms = 0;
10648 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
10649 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
10650 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
10651 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
10652 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10653 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
10654 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10655 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
10656 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10657 }
10658 }
10659 else if ( strcmp((*segit)->fName, "__OBJC") == 0 ) {
10660 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10661 SectionInfo* sectInfo = (*sectit);
10662 if ( strcmp(sectInfo->fSectionName, "__module_info") == 0 ) {
10663 objcModuleSectionStart = sectInfo->getBaseAddress();
10664 objcModuleSectionSize = sectInfo->fSize;
10665 }
10666 }
10667 }
10668 }
10669 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
10670 module->set_module_name(fModuleNameOffset);
10671 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
10672 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
10673 module->set_irefsym(0);
10674 module->set_nrefsym(this->getReferencesCount());
10675 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
10676 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
10677 module->set_iextrel(0);
10678 module->set_nextrel(fWriter.fExternalRelocs.size());
10679 module->set_iinit_iterm(0,0);
10680 module->set_ninit_nterm(numInits,numTerms);
10681 module->set_objc_module_info_addr(objcModuleSectionStart);
10682 module->set_objc_module_info_size(objcModuleSectionSize);
10683 // create reference table
10684 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
10685 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
10686 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
10687 ref->set_flags(REFERENCE_FLAG_DEFINED);
10688 }
10689 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
10690 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
10691 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
10692 if ( pos != fWriter.fStubsMap.end() )
10693 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
10694 else
10695 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
10696 }
10697 }
10698
10699
10700
10701 template <typename A>
10702 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
10703 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
10704 {
10705 fCurrentBuffer = new char[kBufferSize];
10706 // burn first byte of string pool (so zero is never a valid string offset)
10707 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
10708 // make offset 1 always point to an empty string
10709 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
10710 }
10711
10712 template <typename A>
10713 uint64_t StringsLinkEditAtom<A>::getSize() const
10714 {
10715 // align size
10716 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
10717 }
10718
10719 template <typename A>
10720 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10721 {
10722 uint64_t offset = 0;
10723 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
10724 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
10725 offset += kBufferSize;
10726 }
10727 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
10728 // zero fill end to align
10729 offset += fCurrentBufferUsed;
10730 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
10731 buffer[offset++] = 0;
10732 }
10733
10734 template <typename A>
10735 int32_t StringsLinkEditAtom<A>::add(const char* name)
10736 {
10737 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
10738 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
10739 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
10740 fCurrentBufferUsed += lenNeeded;
10741 }
10742 else {
10743 int copied = kBufferSize-fCurrentBufferUsed-1;
10744 // change trailing '\0' that strlcpy added to real char
10745 fCurrentBuffer[kBufferSize-1] = name[copied];
10746 // alloc next buffer
10747 fFullBuffers.push_back(fCurrentBuffer);
10748 fCurrentBuffer = new char[kBufferSize];
10749 fCurrentBufferUsed = 0;
10750 // append rest of string
10751 this->add(&name[copied+1]);
10752 }
10753 return offset;
10754 }
10755
10756
10757 template <typename A>
10758 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
10759 {
10760 StringToOffset::iterator pos = fUniqueStrings.find(name);
10761 if ( pos != fUniqueStrings.end() ) {
10762 return pos->second;
10763 }
10764 else {
10765 int32_t offset = this->add(name);
10766 fUniqueStrings[name] = offset;
10767 return offset;
10768 }
10769 }
10770
10771
10772 template <typename A>
10773 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
10774 {
10775 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
10776 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
10777 // check for out of bounds
10778 if ( index > maxIndex )
10779 return "";
10780 // check for index in fCurrentBuffer
10781 if ( index > currentBufferStartIndex )
10782 return &fCurrentBuffer[index-currentBufferStartIndex];
10783 // otherwise index is in a full buffer
10784 uint32_t fullBufferIndex = index/kBufferSize;
10785 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
10786 }
10787
10788
10789
10790 template <typename A>
10791 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
10792 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
10793 {
10794 char* buf = new char[strlen(name)+32];
10795 if ( targetOffset == 0 ) {
10796 if ( islandRegion == 0 )
10797 sprintf(buf, "%s$island", name);
10798 else
10799 sprintf(buf, "%s$island_%d", name, islandRegion);
10800 }
10801 else {
10802 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
10803 }
10804 fName = buf;
10805 }
10806
10807
10808 template <>
10809 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
10810 {
10811 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
10812 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10813 OSWriteBigInt32(buffer, 0, branchInstruction);
10814 }
10815
10816 template <>
10817 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
10818 {
10819 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
10820 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10821 OSWriteBigInt32(buffer, 0, branchInstruction);
10822 }
10823
10824 template <>
10825 uint64_t BranchIslandAtom<ppc>::getSize() const
10826 {
10827 return 4;
10828 }
10829
10830 template <>
10831 uint64_t BranchIslandAtom<ppc64>::getSize() const
10832 {
10833 return 4;
10834 }
10835
10836
10837
10838 template <typename A>
10839 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
10840 {
10841 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
10842 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
10843 else
10844 return 0; // a zero size causes the load command to be suppressed
10845 }
10846
10847 template <typename A>
10848 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10849 {
10850 uint64_t size = this->getSize();
10851 if ( size > 0 ) {
10852 bzero(buffer, size);
10853 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
10854 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
10855 cmd->set_cmdsize(size);
10856 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
10857 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
10858 }
10859 }
10860
10861
10862 template <typename A>
10863 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
10864 {
10865 return fEncodedData.size();
10866 }
10867
10868 template <typename A>
10869 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
10870 {
10871 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
10872 }
10873
10874
10875 template <typename A>
10876 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
10877 {
10878 pint_t addr = fWriter.fOptions.baseAddress();
10879 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
10880 pint_t nextAddr = it->atom->getAddress() + it->offset;
10881 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
10882 uint64_t delta = nextAddr - addr;
10883 if ( delta == 0 )
10884 throw "double split seg info for same address";
10885 // uleb128 encode
10886 uint8_t byte;
10887 do {
10888 byte = delta & 0x7F;
10889 delta &= ~0x7F;
10890 if ( delta != 0 )
10891 byte |= 0x80;
10892 fEncodedData.push_back(byte);
10893 delta = delta >> 7;
10894 }
10895 while( byte >= 0x80 );
10896 addr = nextAddr;
10897 }
10898 }
10899
10900 template <typename A>
10901 void SegmentSplitInfoContentAtom<A>::encode()
10902 {
10903 if ( ! fCantEncode ) {
10904 fEncodedData.reserve(8192);
10905
10906 if ( fKind1Locations.size() != 0 ) {
10907 fEncodedData.push_back(1);
10908 //fprintf(stderr, "type 1:\n");
10909 this->uleb128EncodeAddresses(fKind1Locations);
10910 fEncodedData.push_back(0);
10911 }
10912
10913 if ( fKind2Locations.size() != 0 ) {
10914 fEncodedData.push_back(2);
10915 //fprintf(stderr, "type 2:\n");
10916 this->uleb128EncodeAddresses(fKind2Locations);
10917 fEncodedData.push_back(0);
10918 }
10919
10920 if ( fKind3Locations.size() != 0 ) {
10921 fEncodedData.push_back(3);
10922 //fprintf(stderr, "type 3:\n");
10923 this->uleb128EncodeAddresses(fKind3Locations);
10924 fEncodedData.push_back(0);
10925 }
10926
10927 if ( fKind4Locations.size() != 0 ) {
10928 fEncodedData.push_back(4);
10929 //fprintf(stderr, "type 4:\n");
10930 this->uleb128EncodeAddresses(fKind4Locations);
10931 fEncodedData.push_back(0);
10932 }
10933
10934 // always add zero byte to mark end
10935 fEncodedData.push_back(0);
10936
10937 // add zeros to end to align size
10938 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
10939 fEncodedData.push_back(0);
10940 }
10941 }
10942
10943
10944 template <typename A>
10945 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
10946 : WriterAtom<A>(writer, getInfoSegment())
10947 {
10948 fContent[0] = 0;
10949 uint32_t value = 0;
10950 // struct objc_image_info {
10951 // uint32_t version; // initially 0
10952 // uint32_t flags;
10953 // };
10954 // #define OBJC_IMAGE_SUPPORTS_GC 2
10955 // #define OBJC_IMAGE_GC_ONLY 4
10956 //
10957 if ( objcReplacementClasses )
10958 value = 1;
10959 switch ( objcConstraint ) {
10960 case ObjectFile::Reader::kObjcNone:
10961 case ObjectFile::Reader::kObjcRetainRelease:
10962 break;
10963 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
10964 value |= 2;
10965 break;
10966 case ObjectFile::Reader::kObjcGC:
10967 value |= 6;
10968 break;
10969 }
10970 A::P::E::set32(fContent[1], value);
10971 }
10972
10973 template <typename A>
10974 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10975 {
10976 memcpy(buffer, &fContent[0], 8);
10977 }
10978
10979
10980 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
10981 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
10982 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
10983 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
10984 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
10985 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
10986
10987 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
10988 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
10989 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
10990 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
10991 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
10992
10993
10994
10995
10996 template <typename A>
10997 void DyldInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10998 {
10999 // build LC_DYLD_INFO command
11000 macho_dyld_info_command<P>* cmd = (macho_dyld_info_command<P>*)buffer;
11001 bzero(cmd, sizeof(macho_dyld_info_command<P>));
11002
11003 cmd->set_cmd( fWriter.fOptions.makeClassicDyldInfo() ? LC_DYLD_INFO : LC_DYLD_INFO_ONLY);
11004 cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
11005 if ( (fWriter.fCompressedRebaseInfoAtom != NULL) && (fWriter.fCompressedRebaseInfoAtom->getSize() != 0) ) {
11006 cmd->set_rebase_off(fWriter.fCompressedRebaseInfoAtom->getFileOffset());
11007 cmd->set_rebase_size(fWriter.fCompressedRebaseInfoAtom->getSize());
11008 }
11009 if ( (fWriter.fCompressedBindingInfoAtom != NULL) && (fWriter.fCompressedBindingInfoAtom->getSize() != 0) ) {
11010 cmd->set_bind_off(fWriter.fCompressedBindingInfoAtom->getFileOffset());
11011 cmd->set_bind_size(fWriter.fCompressedBindingInfoAtom->getSize());
11012 }
11013 if ( (fWriter.fCompressedWeakBindingInfoAtom != NULL) && (fWriter.fCompressedWeakBindingInfoAtom->getSize() != 0) ) {
11014 cmd->set_weak_bind_off(fWriter.fCompressedWeakBindingInfoAtom->getFileOffset());
11015 cmd->set_weak_bind_size(fWriter.fCompressedWeakBindingInfoAtom->getSize());
11016 }
11017 if ( (fWriter.fCompressedLazyBindingInfoAtom != NULL) && (fWriter.fCompressedLazyBindingInfoAtom->getSize() != 0) ) {
11018 cmd->set_lazy_bind_off(fWriter.fCompressedLazyBindingInfoAtom->getFileOffset());
11019 cmd->set_lazy_bind_size(fWriter.fCompressedLazyBindingInfoAtom->getSize());
11020 }
11021 if ( (fWriter.fCompressedExportInfoAtom != NULL) && (fWriter.fCompressedExportInfoAtom->getSize() != 0) ) {
11022 cmd->set_export_off(fWriter.fCompressedExportInfoAtom->getFileOffset());
11023 cmd->set_export_size(fWriter.fCompressedExportInfoAtom->getSize());
11024 }
11025 }
11026
11027
11028 struct rebase_tmp
11029 {
11030 rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
11031 uint8_t opcode;
11032 uint64_t operand1;
11033 uint64_t operand2;
11034 };
11035
11036
11037 template <typename A>
11038 void CompressedRebaseInfoLinkEditAtom<A>::encode()
11039 {
11040 // sort rebase info by type, then address
11041 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11042 std::vector<RebaseInfo>& info = fWriter.fRebaseInfo;
11043 std::sort(info.begin(), info.end());
11044
11045 // convert to temp encoding that can be more easily optimized
11046 std::vector<rebase_tmp> mid;
11047 const SegmentInfo* currentSegment = NULL;
11048 unsigned int segIndex = 0;
11049 uint8_t type = 0;
11050 uint64_t address = (uint64_t)(-1);
11051 for (std::vector<RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11052 if ( type != it->fType ) {
11053 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->fType));
11054 type = it->fType;
11055 }
11056 if ( address != it->fAddress ) {
11057 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11058 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= it->fAddress) ) {
11059 segIndex = 0;
11060 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11061 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11062 currentSegment = *segit;
11063 break;
11064 }
11065 ++segIndex;
11066 }
11067 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11068 }
11069 else {
11070 mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11071 }
11072 address = it->fAddress;
11073 }
11074 mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
11075 address += sizeof(pint_t);
11076 }
11077 mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
11078
11079 // optimize phase 1, compress packed runs of pointers
11080 rebase_tmp* dst = &mid[0];
11081 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11082 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
11083 *dst = *src++;
11084 while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
11085 dst->operand1 += src->operand1;
11086 ++src;
11087 }
11088 --src;
11089 ++dst;
11090 }
11091 else {
11092 *dst++ = *src;
11093 }
11094 }
11095 dst->opcode = REBASE_OPCODE_DONE;
11096
11097 // optimize phase 2, combine rebase/add pairs
11098 dst = &mid[0];
11099 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11100 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
11101 && (src->operand1 == 1)
11102 && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
11103 dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
11104 dst->operand1 = src[1].operand1;
11105 ++src;
11106 ++dst;
11107 }
11108 else {
11109 *dst++ = *src;
11110 }
11111 }
11112 dst->opcode = REBASE_OPCODE_DONE;
11113
11114 // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
11115 // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
11116 dst = &mid[0];
11117 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11118 uint64_t delta = src->operand1;
11119 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11120 && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11121 && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11122 && (src[1].operand1 == delta)
11123 && (src[2].operand1 == delta) ) {
11124 // found at least three in a row, this is worth compressing
11125 dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
11126 dst->operand1 = 1;
11127 dst->operand2 = delta;
11128 ++src;
11129 while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11130 && (src->operand1 == delta) ) {
11131 dst->operand1++;
11132 ++src;
11133 }
11134 --src;
11135 ++dst;
11136 }
11137 else {
11138 *dst++ = *src;
11139 }
11140 }
11141 dst->opcode = REBASE_OPCODE_DONE;
11142
11143 // optimize phase 4, use immediate encodings
11144 for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11145 if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB)
11146 && (p->operand1 < (15*sizeof(pint_t)))
11147 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11148 p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
11149 p->operand1 = p->operand1/sizeof(pint_t);
11150 }
11151 else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
11152 p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
11153 }
11154 }
11155
11156 // convert to compressed encoding
11157 const static bool log = false;
11158 fEncodedData.reserve(info.size()*2);
11159 bool done = false;
11160 for (std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11161 switch ( it->opcode ) {
11162 case REBASE_OPCODE_DONE:
11163 if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
11164 done = true;
11165 break;
11166 case REBASE_OPCODE_SET_TYPE_IMM:
11167 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11168 fEncodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
11169 break;
11170 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11171 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11172 fEncodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11173 fEncodedData.append_uleb128(it->operand2);
11174 break;
11175 case REBASE_OPCODE_ADD_ADDR_ULEB:
11176 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11177 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
11178 fEncodedData.append_uleb128(it->operand1);
11179 break;
11180 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
11181 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11182 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
11183 break;
11184 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
11185 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
11186 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
11187 break;
11188 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
11189 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
11190 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
11191 fEncodedData.append_uleb128(it->operand1);
11192 break;
11193 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
11194 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11195 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
11196 fEncodedData.append_uleb128(it->operand1);
11197 break;
11198 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
11199 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11200 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
11201 fEncodedData.append_uleb128(it->operand1);
11202 fEncodedData.append_uleb128(it->operand2);
11203 break;
11204 }
11205 }
11206
11207
11208 // align to pointer size
11209 fEncodedData.pad_to_size(sizeof(pint_t));
11210
11211 if (log) fprintf(stderr, "total rebase info size = %ld\n", fEncodedData.size());
11212 }
11213
11214
11215 struct binding_tmp
11216 {
11217 binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
11218 : opcode(op), operand1(p1), operand2(p2), name(s) {}
11219 uint8_t opcode;
11220 uint64_t operand1;
11221 uint64_t operand2;
11222 const char* name;
11223 };
11224
11225
11226
11227 template <typename A>
11228 void CompressedBindingInfoLinkEditAtom<A>::encode()
11229 {
11230 // sort by library, symbol, type, then address
11231 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11232 std::vector<BindingInfo>& info = fWriter.fBindingInfo;
11233 std::sort(info.begin(), info.end());
11234
11235 // convert to temp encoding that can be more easily optimized
11236 std::vector<binding_tmp> mid;
11237 const SegmentInfo* currentSegment = NULL;
11238 unsigned int segIndex = 0;
11239 int ordinal = 0x80000000;
11240 const char* symbolName = NULL;
11241 uint8_t type = 0;
11242 uint64_t address = (uint64_t)(-1);
11243 int64_t addend = 0;
11244 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11245 if ( ordinal != it->fLibraryOrdinal ) {
11246 if ( it->fLibraryOrdinal <= 0 ) {
11247 // special lookups are encoded as negative numbers in BindingInfo
11248 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->fLibraryOrdinal));
11249 }
11250 else {
11251 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->fLibraryOrdinal));
11252 }
11253 ordinal = it->fLibraryOrdinal;
11254 }
11255 if ( symbolName != it->fSymbolName ) {
11256 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11257 symbolName = it->fSymbolName;
11258 }
11259 if ( type != it->fType ) {
11260 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11261 type = it->fType;
11262 }
11263 if ( address != it->fAddress ) {
11264 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11265 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress)
11266 || (it->fAddress < address) ) {
11267 segIndex = 0;
11268 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11269 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11270 currentSegment = *segit;
11271 break;
11272 }
11273 ++segIndex;
11274 }
11275 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11276 }
11277 else {
11278 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11279 }
11280 address = it->fAddress;
11281 }
11282 if ( addend != it->fAddend ) {
11283 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11284 addend = it->fAddend;
11285 }
11286 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11287 address += sizeof(pint_t);
11288 }
11289 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11290
11291
11292 // optimize phase 1, combine bind/add pairs
11293 binding_tmp* dst = &mid[0];
11294 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11295 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11296 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11297 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11298 dst->operand1 = src[1].operand1;
11299 ++src;
11300 ++dst;
11301 }
11302 else {
11303 *dst++ = *src;
11304 }
11305 }
11306 dst->opcode = BIND_OPCODE_DONE;
11307
11308 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11309 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11310 dst = &mid[0];
11311 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11312 uint64_t delta = src->operand1;
11313 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11314 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11315 && (src[1].operand1 == delta) ) {
11316 // found at least two in a row, this is worth compressing
11317 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11318 dst->operand1 = 1;
11319 dst->operand2 = delta;
11320 ++src;
11321 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11322 && (src->operand1 == delta) ) {
11323 dst->operand1++;
11324 ++src;
11325 }
11326 --src;
11327 ++dst;
11328 }
11329 else {
11330 *dst++ = *src;
11331 }
11332 }
11333 dst->opcode = BIND_OPCODE_DONE;
11334
11335 // optimize phase 3, use immediate encodings
11336 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11337 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11338 && (p->operand1 < (15*sizeof(pint_t)))
11339 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11340 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11341 p->operand1 = p->operand1/sizeof(pint_t);
11342 }
11343 else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
11344 p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
11345 }
11346 }
11347 dst->opcode = BIND_OPCODE_DONE;
11348
11349 // convert to compressed encoding
11350 const static bool log = false;
11351 fEncodedData.reserve(info.size()*2);
11352 bool done = false;
11353 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11354 switch ( it->opcode ) {
11355 case BIND_OPCODE_DONE:
11356 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11357 done = true;
11358 break;
11359 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11360 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11361 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11362 break;
11363 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11364 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11365 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11366 fEncodedData.append_uleb128(it->operand1);
11367 break;
11368 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11369 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11370 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11371 break;
11372 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11373 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11374 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11375 fEncodedData.append_string(it->name);
11376 break;
11377 case BIND_OPCODE_SET_TYPE_IMM:
11378 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11379 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11380 break;
11381 case BIND_OPCODE_SET_ADDEND_SLEB:
11382 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11383 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11384 fEncodedData.append_sleb128(it->operand1);
11385 break;
11386 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11387 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11388 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11389 fEncodedData.append_uleb128(it->operand2);
11390 break;
11391 case BIND_OPCODE_ADD_ADDR_ULEB:
11392 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11393 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11394 fEncodedData.append_uleb128(it->operand1);
11395 break;
11396 case BIND_OPCODE_DO_BIND:
11397 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11398 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11399 break;
11400 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11401 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11402 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11403 fEncodedData.append_uleb128(it->operand1);
11404 break;
11405 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11406 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11407 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11408 break;
11409 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11410 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11411 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11412 fEncodedData.append_uleb128(it->operand1);
11413 fEncodedData.append_uleb128(it->operand2);
11414 break;
11415 }
11416 }
11417
11418 // align to pointer size
11419 fEncodedData.pad_to_size(sizeof(pint_t));
11420
11421 if (log) fprintf(stderr, "total binding info size = %ld\n", fEncodedData.size());
11422
11423 }
11424
11425
11426
11427 struct WeakBindingSorter
11428 {
11429 bool operator()(const BindingInfo& left, const BindingInfo& right)
11430 {
11431 // sort by symbol, type, address
11432 if ( left.fSymbolName != right.fSymbolName )
11433 return ( strcmp(left.fSymbolName, right.fSymbolName) < 0 );
11434 if ( left.fType != right.fType )
11435 return (left.fType < right.fType);
11436 return (left.fAddress < right.fAddress);
11437 }
11438 };
11439
11440
11441
11442 template <typename A>
11443 void CompressedWeakBindingInfoLinkEditAtom<A>::encode()
11444 {
11445 // add regular atoms that override a dylib's weak definitions
11446 for(std::set<const class ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
11447 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
11448 if ( fWriter.shouldExport(**it) )
11449 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, (*it)->getName(), true, 0, 0));
11450 }
11451
11452 // add all exported weak definitions
11453 for(std::vector<class ObjectFile::Atom*>::iterator it = fWriter.fAllAtoms->begin(); it != fWriter.fAllAtoms->end(); ++it) {
11454 ObjectFile::Atom* atom = *it;
11455 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) && fWriter.shouldExport(*atom) ) {
11456 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, atom->getName(), false, 0, 0));
11457 }
11458 }
11459
11460 // sort by symbol, type, address
11461 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11462 std::vector<BindingInfo>& info = fWriter.fWeakBindingInfo;
11463 if ( info.size() == 0 )
11464 return;
11465 std::sort(info.begin(), info.end(), WeakBindingSorter());
11466
11467 // convert to temp encoding that can be more easily optimized
11468 std::vector<binding_tmp> mid;
11469 mid.reserve(info.size());
11470 const SegmentInfo* currentSegment = NULL;
11471 unsigned int segIndex = 0;
11472 const char* symbolName = NULL;
11473 uint8_t type = 0;
11474 uint64_t address = (uint64_t)(-1);
11475 int64_t addend = 0;
11476 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11477 if ( symbolName != it->fSymbolName ) {
11478 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11479 symbolName = it->fSymbolName;
11480 }
11481 if ( it->fType != 0 ) {
11482 if ( type != it->fType ) {
11483 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11484 type = it->fType;
11485 }
11486 if ( address != it->fAddress ) {
11487 // non weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
11488 // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
11489 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11490 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress) ) {
11491 segIndex = 0;
11492 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11493 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11494 currentSegment = *segit;
11495 break;
11496 }
11497 ++segIndex;
11498 }
11499 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11500 }
11501 else {
11502 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11503 }
11504 address = it->fAddress;
11505 }
11506 if ( addend != it->fAddend ) {
11507 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11508 addend = it->fAddend;
11509 }
11510 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11511 address += sizeof(pint_t);
11512 }
11513 }
11514 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11515
11516
11517 // optimize phase 1, combine bind/add pairs
11518 binding_tmp* dst = &mid[0];
11519 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11520 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11521 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11522 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11523 dst->operand1 = src[1].operand1;
11524 ++src;
11525 ++dst;
11526 }
11527 else {
11528 *dst++ = *src;
11529 }
11530 }
11531 dst->opcode = BIND_OPCODE_DONE;
11532
11533 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11534 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11535 dst = &mid[0];
11536 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11537 uint64_t delta = src->operand1;
11538 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11539 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11540 && (src[1].operand1 == delta) ) {
11541 // found at least two in a row, this is worth compressing
11542 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11543 dst->operand1 = 1;
11544 dst->operand2 = delta;
11545 ++src;
11546 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11547 && (src->operand1 == delta) ) {
11548 dst->operand1++;
11549 ++src;
11550 }
11551 --src;
11552 ++dst;
11553 }
11554 else {
11555 *dst++ = *src;
11556 }
11557 }
11558 dst->opcode = BIND_OPCODE_DONE;
11559
11560 // optimize phase 3, use immediate encodings
11561 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11562 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11563 && (p->operand1 < (15*sizeof(pint_t)))
11564 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11565 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11566 p->operand1 = p->operand1/sizeof(pint_t);
11567 }
11568 }
11569 dst->opcode = BIND_OPCODE_DONE;
11570
11571
11572 // convert to compressed encoding
11573 const static bool log = false;
11574 fEncodedData.reserve(info.size()*2);
11575 bool done = false;
11576 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11577 switch ( it->opcode ) {
11578 case BIND_OPCODE_DONE:
11579 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11580 fEncodedData.append_byte(BIND_OPCODE_DONE);
11581 done = true;
11582 break;
11583 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11584 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11585 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11586 break;
11587 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11588 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11589 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11590 fEncodedData.append_uleb128(it->operand1);
11591 break;
11592 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11593 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11594 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11595 break;
11596 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11597 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11598 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11599 fEncodedData.append_string(it->name);
11600 break;
11601 case BIND_OPCODE_SET_TYPE_IMM:
11602 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11603 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11604 break;
11605 case BIND_OPCODE_SET_ADDEND_SLEB:
11606 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11607 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11608 fEncodedData.append_sleb128(it->operand1);
11609 break;
11610 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11611 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11612 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11613 fEncodedData.append_uleb128(it->operand2);
11614 break;
11615 case BIND_OPCODE_ADD_ADDR_ULEB:
11616 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11617 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11618 fEncodedData.append_uleb128(it->operand1);
11619 break;
11620 case BIND_OPCODE_DO_BIND:
11621 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11622 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11623 break;
11624 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11625 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11626 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11627 fEncodedData.append_uleb128(it->operand1);
11628 break;
11629 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11630 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11631 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11632 break;
11633 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11634 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11635 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11636 fEncodedData.append_uleb128(it->operand1);
11637 fEncodedData.append_uleb128(it->operand2);
11638 break;
11639 }
11640 }
11641
11642 // align to pointer size
11643 fEncodedData.pad_to_size(sizeof(pint_t));
11644
11645 if (log) fprintf(stderr, "total weak binding info size = %ld\n", fEncodedData.size());
11646
11647 }
11648
11649 template <typename A>
11650 void CompressedLazyBindingInfoLinkEditAtom<A>::encode()
11651 {
11652 // stream all lazy bindings and record start offsets
11653 const SegmentInfo* currentSegment = NULL;
11654 uint8_t segIndex = 0;
11655 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11656 std::vector<class LazyPointerAtom<A>*>& allLazys = fWriter.fAllSynthesizedLazyPointers;
11657 for (typename std::vector<class LazyPointerAtom<A>*>::iterator it = allLazys.begin(); it != allLazys.end(); ++it) {
11658 LazyPointerAtom<A>* lazyPointerAtom = *it;
11659 ObjectFile::Atom* lazyPointerTargetAtom = lazyPointerAtom->getTarget();
11660
11661 // skip lazy pointers that are bound non-lazily because they are coalesced
11662 if ( ! fWriter.targetRequiresWeakBinding(*lazyPointerTargetAtom) ) {
11663 // record start offset for use by stub helper
11664 lazyPointerAtom->setLazyBindingInfoOffset(fEncodedData.size());
11665
11666 // write address to bind
11667 pint_t address = lazyPointerAtom->getAddress();
11668 if ( (currentSegment == NULL) || (address < currentSegment->fBaseAddress)
11669 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= address) ) {
11670 segIndex = 0;
11671 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11672 if ( ((*segit)->fBaseAddress <= address) && (address < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11673 currentSegment = *segit;
11674 break;
11675 }
11676 ++segIndex;
11677 }
11678 }
11679 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
11680 fEncodedData.append_uleb128(lazyPointerAtom->getAddress() - currentSegment->fBaseAddress);
11681
11682 // write ordinal
11683 int ordinal = fWriter.compressedOrdinalForImortedAtom(lazyPointerTargetAtom);
11684 if ( ordinal <= 0 ) {
11685 // special lookups are encoded as negative numbers in BindingInfo
11686 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (ordinal & BIND_IMMEDIATE_MASK) );
11687 }
11688 else if ( ordinal <= 15 ) {
11689 // small ordinals are encoded in opcode
11690 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
11691 }
11692 else {
11693 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11694 fEncodedData.append_uleb128(ordinal);
11695 }
11696 // write symbol name
11697 bool weak_import = fWriter.fWeakImportMap[lazyPointerTargetAtom];
11698 if ( weak_import )
11699 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | BIND_SYMBOL_FLAGS_WEAK_IMPORT);
11700 else
11701 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
11702 fEncodedData.append_string(lazyPointerTargetAtom->getName());
11703 // write do bind
11704 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11705 fEncodedData.append_byte(BIND_OPCODE_DONE);
11706 }
11707 }
11708 // align to pointer size
11709 fEncodedData.pad_to_size(sizeof(pint_t));
11710
11711 //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", fEncodedData.size(), allLazys.size());
11712 }
11713
11714 struct TrieEntriesSorter
11715 {
11716 TrieEntriesSorter(Options& o) : fOptions(o) {}
11717
11718 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
11719 {
11720 unsigned int leftOrder;
11721 unsigned int rightOrder;
11722 fOptions.exportedSymbolOrder(left.name, &leftOrder);
11723 fOptions.exportedSymbolOrder(right.name, &rightOrder);
11724 if ( leftOrder != rightOrder )
11725 return (leftOrder < rightOrder);
11726 else
11727 return (left.address < right.address);
11728 }
11729 private:
11730 Options& fOptions;
11731 };
11732
11733
11734 template <typename A>
11735 void CompressedExportInfoLinkEditAtom<A>::encode()
11736 {
11737 // make vector of mach_o::trie::Entry for all exported symbols
11738 std::vector<class ObjectFile::Atom*>& exports = fWriter.fExportedAtoms;
11739 uint64_t imageBaseAddress = fWriter.fMachHeaderAtom->getAddress();
11740 std::vector<mach_o::trie::Entry> entries;
11741 entries.reserve(exports.size());
11742 for (std::vector<ObjectFile::Atom*>::iterator it = exports.begin(); it != exports.end(); ++it) {
11743 ObjectFile::Atom* atom = *it;
11744 uint64_t flags = 0;
11745 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
11746 flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
11747 uint64_t address = atom->getAddress() - imageBaseAddress;
11748 if ( atom->isThumb() )
11749 address |= 1;
11750 mach_o::trie::Entry entry;
11751 entry.name = atom->getName();
11752 entry.flags = flags;
11753 entry.address = address;
11754 entries.push_back(entry);
11755 }
11756
11757 // sort vector by -exported_symbols_order, and any others by address
11758 std::sort(entries.begin(), entries.end(), TrieEntriesSorter(fWriter.fOptions));
11759
11760 // create trie
11761 mach_o::trie::makeTrie(entries, fEncodedData.bytes());
11762
11763 // align to pointer size
11764 fEncodedData.pad_to_size(sizeof(pint_t));
11765 }
11766
11767
11768
11769
11770
11771 }; // namespace executable
11772 }; // namespace mach_o
11773
11774
11775 #endif // __EXECUTABLE_MACH_O__