]> git.saurik.com Git - apple/ld64.git/blob - src/ld/MachOWriterExecutable.hpp
9e02efacf92a88781d667c99f1681dce776b3f4f
[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 class SectionRelocationsLinkEditAtom<A>* fSectionRelocationsAtom;
457 class CompressedRebaseInfoLinkEditAtom<A>* fCompressedRebaseInfoAtom;
458 class CompressedBindingInfoLinkEditAtom<A>* fCompressedBindingInfoAtom;
459 class CompressedWeakBindingInfoLinkEditAtom<A>* fCompressedWeakBindingInfoAtom;
460 class CompressedLazyBindingInfoLinkEditAtom<A>* fCompressedLazyBindingInfoAtom;
461 class CompressedExportInfoLinkEditAtom<A>* fCompressedExportInfoAtom;
462 class LocalRelocationsLinkEditAtom<A>* fLocalRelocationsAtom;
463 class ExternalRelocationsLinkEditAtom<A>* fExternalRelocationsAtom;
464 class SymbolTableLinkEditAtom<A>* fSymbolTableAtom;
465 class SegmentSplitInfoContentAtom<A>* fSplitCodeToDataContentAtom;
466 class IndirectTableLinkEditAtom<A>* fIndirectTableAtom;
467 class ModuleInfoLinkEditAtom<A>* fModuleInfoAtom;
468 class StringsLinkEditAtom<A>* fStringsAtom;
469 class PageZeroAtom<A>* fPageZeroAtom;
470 class NonLazyPointerAtom<A>* fFastStubGOTAtom;
471 macho_nlist<P>* fSymbolTable;
472 std::vector<macho_relocation_info<P> > fSectionRelocs;
473 std::vector<macho_relocation_info<P> > fInternalRelocs;
474 std::vector<macho_relocation_info<P> > fExternalRelocs;
475 std::vector<RebaseInfo> fRebaseInfo;
476 std::vector<BindingInfo> fBindingInfo;
477 std::vector<BindingInfo> fWeakBindingInfo;
478 std::map<const ObjectFile::Atom*,ObjectFile::Atom*> fStubsMap;
479 std::map<ObjectFile::Atom*,ObjectFile::Atom*> fGOTMap;
480 std::vector<class StubAtom<A>*> fAllSynthesizedStubs;
481 std::vector<ObjectFile::Atom*> fAllSynthesizedStubHelpers;
482 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyPointers;
483 std::vector<class LazyPointerAtom<A>*> fAllSynthesizedLazyDylibPointers;
484 std::vector<class NonLazyPointerAtom<A>*> fAllSynthesizedNonLazyPointers;
485 uint32_t fSymbolTableCount;
486 uint32_t fSymbolTableStabsCount;
487 uint32_t fSymbolTableStabsStartIndex;
488 uint32_t fSymbolTableLocalCount;
489 uint32_t fSymbolTableLocalStartIndex;
490 uint32_t fSymbolTableExportCount;
491 uint32_t fSymbolTableExportStartIndex;
492 uint32_t fSymbolTableImportCount;
493 uint32_t fSymbolTableImportStartIndex;
494 uint32_t fLargestAtomSize;
495 bool fEmitVirtualSections;
496 bool fHasWeakExports;
497 bool fReferencesWeakImports;
498 bool fCanScatter;
499 bool fWritableSegmentPastFirst4GB;
500 bool fNoReExportedDylibs;
501 bool fBiggerThanTwoGigs;
502 bool fSlideable;
503 std::map<const ObjectFile::Atom*,bool> fWeakImportMap;
504 std::set<const ObjectFile::Reader*> fDylibReadersWithNonWeakImports;
505 std::set<const ObjectFile::Reader*> fDylibReadersWithWeakImports;
506 SegmentInfo* fFirstWritableSegment;
507 ObjectFile::Reader::CpuConstraint fCpuConstraint;
508 uint32_t fAnonNameIndex;
509 };
510
511
512 class Segment : public ObjectFile::Segment
513 {
514 public:
515 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
516 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
517 virtual const char* getName() const { return fName; }
518 virtual bool isContentReadable() const { return fReadable; }
519 virtual bool isContentWritable() const { return fWritable; }
520 virtual bool isContentExecutable() const { return fExecutable; }
521 virtual bool hasFixedAddress() const { return fFixedAddress; }
522
523 static Segment fgTextSegment;
524 static Segment fgPageZeroSegment;
525 static Segment fgLinkEditSegment;
526 static Segment fgStackSegment;
527 static Segment fgImportSegment;
528 static Segment fgROImportSegment;
529 static Segment fgDataSegment;
530 static Segment fgObjCSegment;
531 static Segment fgHeaderSegment;
532
533
534 private:
535 const char* fName;
536 const bool fReadable;
537 const bool fWritable;
538 const bool fExecutable;
539 const bool fFixedAddress;
540 };
541
542 Segment Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
543 Segment Segment::fgTextSegment("__TEXT", true, false, true, false);
544 Segment Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
545 Segment Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
546 Segment Segment::fgImportSegment("__IMPORT", true, true, true, false);
547 Segment Segment::fgROImportSegment("__IMPORT", true, false, true, false);
548 Segment Segment::fgDataSegment("__DATA", true, true, false, false);
549 Segment Segment::fgObjCSegment("__OBJC", true, true, false, false);
550 Segment Segment::fgHeaderSegment("__HEADER", true, false, true, false);
551
552
553 template <typename A>
554 class WriterAtom : public ObjectFile::Atom
555 {
556 public:
557 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
558 WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
559
560 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
561 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
562 virtual const char* getName() const { return NULL; }
563 virtual const char* getDisplayName() const { return this->getName(); }
564 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
565 virtual DefinitionKind getDefinitionKind() const { return kRegularDefinition; }
566 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
567 virtual bool dontDeadStrip() const { return true; }
568 virtual bool isZeroFill() const { return false; }
569 virtual bool isThumb() const { return false; }
570 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
571 virtual bool mustRemainInSection() const { return true; }
572 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
573 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
574 virtual uint32_t getOrdinal() const { return 0; }
575 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
576 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(2); }
577 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
578 virtual void setScope(Scope) { }
579
580
581 protected:
582 virtual ~WriterAtom() {}
583 typedef typename A::P P;
584 typedef typename A::P::E E;
585
586 static Segment& headerSegment(Writer<A>& writer) { return (writer.fOptions.outputKind()==Options::kPreload)
587 ? Segment::fgHeaderSegment : Segment::fgTextSegment; }
588
589 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
590
591 Writer<A>& fWriter;
592 Segment& fSegment;
593 };
594
595 template <typename A> std::vector<ObjectFile::Reference*> WriterAtom<A>::fgEmptyReferenceList;
596
597
598 template <typename A>
599 class PageZeroAtom : public WriterAtom<A>
600 {
601 public:
602 PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
603 fSize(fWriter.fOptions.zeroPageSize()) {}
604 virtual const char* getDisplayName() const { return "page zero content"; }
605 virtual bool isZeroFill() const { return true; }
606 virtual uint64_t getSize() const { return fSize; }
607 virtual const char* getSectionName() const { return "._zeropage"; }
608 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
609 void setSize(uint64_t size) { fSize = size; }
610 private:
611 using WriterAtom<A>::fWriter;
612 typedef typename A::P P;
613 uint64_t fSize;
614 };
615
616
617 template <typename A>
618 class DsoHandleAtom : public WriterAtom<A>
619 {
620 public:
621 DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
622 virtual const char* getName() const { return "___dso_handle"; }
623 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
624 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
625 virtual uint64_t getSize() const { return 0; }
626 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
627 virtual const char* getSectionName() const { return "._mach_header"; }
628 virtual void copyRawContent(uint8_t buffer[]) const {}
629 };
630
631
632 template <typename A>
633 class MachHeaderAtom : public WriterAtom<A>
634 {
635 public:
636 MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)) {}
637 virtual const char* getName() const;
638 virtual const char* getDisplayName() const;
639 virtual ObjectFile::Atom::Scope getScope() const;
640 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const;
641 virtual uint64_t getSize() const { return sizeof(macho_header<typename A::P>); }
642 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
643 virtual const char* getSectionName() const { return "._mach_header"; }
644 virtual uint32_t getOrdinal() const { return 1; }
645 virtual void copyRawContent(uint8_t buffer[]) const;
646 private:
647 using WriterAtom<A>::fWriter;
648 typedef typename A::P P;
649 void setHeaderInfo(macho_header<typename A::P>& header) const;
650 };
651
652 template <typename A>
653 class CustomStackAtom : public WriterAtom<A>
654 {
655 public:
656 CustomStackAtom(Writer<A>& writer);
657 virtual const char* getDisplayName() const { return "custom stack content"; }
658 virtual bool isZeroFill() const { return true; }
659 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
660 virtual const char* getSectionName() const { return "._stack"; }
661 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(12); }
662 private:
663 using WriterAtom<A>::fWriter;
664 typedef typename A::P P;
665 static bool stackGrowsDown();
666 };
667
668 template <typename A>
669 class LoadCommandAtom : public WriterAtom<A>
670 {
671 protected:
672 LoadCommandAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)), fOrdinal(fgCurrentOrdinal++) {}
673 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
674 virtual const char* getSectionName() const { return "._load_commands"; }
675 virtual uint32_t getOrdinal() const { return fOrdinal; }
676 static uint64_t alignedSize(uint64_t size);
677 protected:
678 uint32_t fOrdinal;
679 static uint32_t fgCurrentOrdinal;
680 };
681
682 template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
683
684 template <typename A>
685 class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
686 {
687 public:
688 SegmentLoadCommandsAtom(Writer<A>& writer)
689 : LoadCommandAtom<A>(writer), fCommandCount(0), fSize(0)
690 { writer.fSegmentCommands = this; }
691 virtual const char* getDisplayName() const { return "segment load commands"; }
692 virtual uint64_t getSize() const { return fSize; }
693 virtual void copyRawContent(uint8_t buffer[]) const;
694
695 void computeSize();
696 void setup();
697 unsigned int commandCount() { return fCommandCount; }
698 private:
699 using WriterAtom<A>::fWriter;
700 typedef typename A::P P;
701 unsigned int fCommandCount;
702 uint32_t fSize;
703 };
704
705
706 template <typename A>
707 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
708 {
709 public:
710 SymbolTableLoadCommandsAtom(Writer<A>&);
711 virtual const char* getDisplayName() const { return "symbol table load commands"; }
712 virtual uint64_t getSize() const;
713 virtual void copyRawContent(uint8_t buffer[]) const;
714 unsigned int commandCount();
715 void needDynamicTable();
716 private:
717 using WriterAtom<A>::fWriter;
718 typedef typename A::P P;
719 bool fNeedsDynamicSymbolTable;
720 macho_symtab_command<typename A::P> fSymbolTable;
721 macho_dysymtab_command<typename A::P> fDynamicSymbolTable;
722 };
723
724 template <typename A>
725 class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
726 {
727 public:
728 ThreadsLoadCommandsAtom(Writer<A>& writer)
729 : LoadCommandAtom<A>(writer) {}
730 virtual const char* getDisplayName() const { return "thread load commands"; }
731 virtual uint64_t getSize() const;
732 virtual void copyRawContent(uint8_t buffer[]) const;
733 private:
734 using WriterAtom<A>::fWriter;
735 typedef typename A::P P;
736 uint8_t* fBuffer;
737 uint32_t fBufferSize;
738 };
739
740 template <typename A>
741 class DyldLoadCommandsAtom : public LoadCommandAtom<A>
742 {
743 public:
744 DyldLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
745 virtual const char* getDisplayName() const { return "dyld load command"; }
746 virtual uint64_t getSize() const;
747 virtual void copyRawContent(uint8_t buffer[]) const;
748 private:
749 using WriterAtom<A>::fWriter;
750 typedef typename A::P P;
751 };
752
753 template <typename A>
754 class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
755 {
756 public:
757 SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
758 virtual const char* getDisplayName() const { return "segment split info load command"; }
759 virtual uint64_t getSize() const;
760 virtual void copyRawContent(uint8_t buffer[]) const;
761 private:
762 using WriterAtom<A>::fWriter;
763 typedef typename A::P P;
764 };
765
766 template <typename A>
767 class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
768 {
769 public:
770 AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client) :
771 LoadCommandAtom<A>(writer), clientString(client) {}
772 virtual const char* getDisplayName() const { return "allowable_client load command"; }
773 virtual uint64_t getSize() const;
774 virtual void copyRawContent(uint8_t buffer[]) const;
775 private:
776 using WriterAtom<A>::fWriter;
777 typedef typename A::P P;
778 const char* clientString;
779 };
780
781 template <typename A>
782 class DylibLoadCommandsAtom : public LoadCommandAtom<A>
783 {
784 public:
785 DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info)
786 : LoadCommandAtom<A>(writer), fInfo(info),
787 fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
788 virtual const char* getDisplayName() const { return "dylib load command"; }
789 virtual uint64_t getSize() const;
790 virtual void copyRawContent(uint8_t buffer[]) const;
791 virtual void optimizeAway() { fOptimizedAway = true; }
792 bool linkedWeak() { return fInfo.options.fWeakImport; }
793 private:
794 using WriterAtom<A>::fWriter;
795 typedef typename A::P P;
796 ExecutableFile::DyLibUsed fInfo;
797 bool fOptimizedAway;
798 };
799
800 template <typename A>
801 class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
802 {
803 public:
804 DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
805 virtual const char* getDisplayName() const { return "dylib ID load command"; }
806 virtual uint64_t getSize() const;
807 virtual void copyRawContent(uint8_t buffer[]) const;
808 private:
809 using WriterAtom<A>::fWriter;
810 typedef typename A::P P;
811 };
812
813 template <typename A>
814 class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
815 {
816 public:
817 RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
818 virtual const char* getDisplayName() const { return "routines load command"; }
819 virtual uint64_t getSize() const { return sizeof(macho_routines_command<typename A::P>); }
820 virtual void copyRawContent(uint8_t buffer[]) const;
821 private:
822 using WriterAtom<A>::fWriter;
823 typedef typename A::P P;
824 };
825
826 template <typename A>
827 class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
828 {
829 public:
830 SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
831 : LoadCommandAtom<A>(writer), fName(name) {}
832 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
833 virtual uint64_t getSize() const;
834 virtual void copyRawContent(uint8_t buffer[]) const;
835 private:
836 typedef typename A::P P;
837 const char* fName;
838 };
839
840 template <typename A>
841 class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
842 {
843 public:
844 SubLibraryLoadCommandsAtom(Writer<A>& writer, const char* nameStart, int nameLen)
845 : LoadCommandAtom<A>(writer), fNameStart(nameStart), fNameLength(nameLen) {}
846 virtual const char* getDisplayName() const { return "sub-library load command"; }
847 virtual uint64_t getSize() const;
848 virtual void copyRawContent(uint8_t buffer[]) const;
849 private:
850 using WriterAtom<A>::fWriter;
851 typedef typename A::P P;
852 const char* fNameStart;
853 int fNameLength;
854 };
855
856 template <typename A>
857 class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
858 {
859 public:
860 UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
861 : LoadCommandAtom<A>(writer), fName(name) {}
862 virtual const char* getDisplayName() const { return "umbrella load command"; }
863 virtual uint64_t getSize() const;
864 virtual void copyRawContent(uint8_t buffer[]) const;
865 private:
866 using WriterAtom<A>::fWriter;
867 typedef typename A::P P;
868 const char* fName;
869 };
870
871 template <typename A>
872 class UUIDLoadCommandAtom : public LoadCommandAtom<A>
873 {
874 public:
875 UUIDLoadCommandAtom(Writer<A>& writer)
876 : LoadCommandAtom<A>(writer), fEmit(false) {}
877 virtual const char* getDisplayName() const { return "uuid load command"; }
878 virtual uint64_t getSize() const { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
879 virtual void copyRawContent(uint8_t buffer[]) const;
880 virtual void generate();
881 void setContent(const uint8_t uuid[16]);
882 const uint8_t* getUUID() { return fUUID; }
883 private:
884 using WriterAtom<A>::fWriter;
885 typedef typename A::P P;
886 uuid_t fUUID;
887 bool fEmit;
888 };
889
890
891 template <typename A>
892 class RPathLoadCommandsAtom : public LoadCommandAtom<A>
893 {
894 public:
895 RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
896 : LoadCommandAtom<A>(writer), fPath(path) {}
897 virtual const char* getDisplayName() const { return "rpath load command"; }
898 virtual uint64_t getSize() const;
899 virtual void copyRawContent(uint8_t buffer[]) const;
900 private:
901 using WriterAtom<A>::fWriter;
902 typedef typename A::P P;
903 const char* fPath;
904 };
905
906 template <typename A>
907 class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
908 {
909 public:
910 EncryptionLoadCommandsAtom(Writer<A>& writer)
911 : LoadCommandAtom<A>(writer), fStartOffset(0),
912 fEndOffset(0) {}
913 virtual const char* getDisplayName() const { return "encryption info load command"; }
914 virtual uint64_t getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
915 virtual void copyRawContent(uint8_t buffer[]) const;
916 void setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
917 void setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
918 private:
919 using WriterAtom<A>::fWriter;
920 typedef typename A::P P;
921 uint32_t fStartOffset;
922 uint32_t fEndOffset;
923 };
924
925 template <typename A>
926 class DyldInfoLoadCommandsAtom : public LoadCommandAtom<A>
927 {
928 public:
929 DyldInfoLoadCommandsAtom(Writer<A>& writer)
930 : LoadCommandAtom<A>(writer) {}
931 virtual const char* getDisplayName() const { return "dyld info load command"; }
932 virtual uint64_t getSize() const { return sizeof(macho_dyld_info_command<typename A::P>); }
933 virtual void copyRawContent(uint8_t buffer[]) const;
934 private:
935 using WriterAtom<A>::fWriter;
936 typedef typename A::P P;
937 };
938
939
940 template <typename A>
941 class LoadCommandsPaddingAtom : public WriterAtom<A>
942 {
943 public:
944 LoadCommandsPaddingAtom(Writer<A>& writer)
945 : WriterAtom<A>(writer, headerSegment(writer)), fSize(0) {}
946 virtual const char* getDisplayName() const { return "header padding"; }
947 virtual uint64_t getSize() const { return fSize; }
948 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
949 virtual void copyRawContent(uint8_t buffer[]) const;
950
951 void setSize(uint64_t newSize);
952 private:
953 using WriterAtom<A>::fWriter;
954 typedef typename A::P P;
955 uint64_t fSize;
956 };
957
958 template <typename A>
959 class UnwindInfoAtom : public WriterAtom<A>
960 {
961 public:
962 UnwindInfoAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment),
963 fHeaderSize(0), fPagesSize(0), fAlignment(4) {}
964 virtual const char* getName() const { return "unwind info"; }
965 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
966 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
967 virtual uint64_t getSize() const { return fHeaderSize+fPagesSize; }
968 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
969 virtual const char* getSectionName() const { return "__unwind_info"; }
970 virtual uint32_t getOrdinal() const { return 1; }
971 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)fReferences; }
972 virtual void copyRawContent(uint8_t buffer[]) const;
973
974 void addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
975 ObjectFile::Reference* lsda, ObjectFile::Atom* personalityPointer);
976 void generate();
977
978 private:
979 using WriterAtom<A>::fWriter;
980 typedef typename A::P P;
981 struct Info { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; };
982 struct LSDAEntry { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; };
983 struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; };
984 struct CompressedFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fromFunc; };
985
986 void compressDuplicates(std::vector<Info>& uniqueInfos);
987 void findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings);
988 void makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap);
989 unsigned int makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize, unsigned int endIndex,
990 uint8_t*& pageEnd);
991 unsigned int makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
992 const std::map<uint32_t,unsigned int> commonEncodings,
993 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
994 void makePersonalityIndex(std::vector<Info>& uniqueInfos);
995
996
997 uint32_t fHeaderSize;
998 uint32_t fPagesSize;
999 uint8_t* fHeaderContent;
1000 uint8_t* fPagesContent;
1001 uint8_t* fPagesContentForDelete;
1002 ObjectFile::Alignment fAlignment;
1003 std::vector<Info> fInfos;
1004 std::map<ObjectFile::Atom*, uint32_t> fPersonalityIndexMap;
1005 std::vector<LSDAEntry> fLSDAIndex;
1006 std::vector<RegFixUp> fRegFixUps;
1007 std::vector<CompressedFixUp> fCompressedFixUps;
1008 std::vector<ObjectFile::Reference*> fReferences;
1009 };
1010
1011
1012
1013 template <typename A>
1014 class LinkEditAtom : public WriterAtom<A>
1015 {
1016 public:
1017 LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
1018 uint64_t getFileOffset() const;
1019 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
1020 virtual uint32_t getOrdinal() const { return fOrdinal; }
1021 private:
1022 uint32_t fOrdinal;
1023 static uint32_t fgCurrentOrdinal;
1024 private:
1025 typedef typename A::P P;
1026 };
1027
1028 template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
1029
1030 template <typename A>
1031 class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
1032 {
1033 public:
1034 SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1035 virtual const char* getDisplayName() const { return "section relocations"; }
1036 virtual uint64_t getSize() const;
1037 virtual const char* getSectionName() const { return "._section_relocs"; }
1038 virtual void copyRawContent(uint8_t buffer[]) const;
1039 private:
1040 using WriterAtom<A>::fWriter;
1041 typedef typename A::P P;
1042 };
1043
1044 template <typename A>
1045 class CompressedInfoLinkEditAtom : public LinkEditAtom<A>
1046 {
1047 public:
1048 CompressedInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1049 virtual uint64_t getSize() const { return fEncodedData.size(); }
1050 virtual void copyRawContent(uint8_t buffer[]) const { memcpy(buffer, fEncodedData.start(), fEncodedData.size()); }
1051 protected:
1052 typedef typename A::P::uint_t pint_t;
1053 ByteStream fEncodedData;
1054 private:
1055 using WriterAtom<A>::fWriter;
1056 typedef typename A::P P;
1057 };
1058
1059
1060
1061 template <typename A>
1062 class CompressedRebaseInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1063 {
1064 public:
1065 CompressedRebaseInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1066 virtual const char* getDisplayName() const { return "compressed rebase info"; }
1067 virtual const char* getSectionName() const { return "._rebase info"; }
1068 void encode();
1069 private:
1070 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1071 using CompressedInfoLinkEditAtom<A>::fWriter;
1072 typedef typename A::P P;
1073 typedef typename A::P::uint_t pint_t;
1074 };
1075
1076 template <typename A>
1077 class CompressedBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1078 {
1079 public:
1080 CompressedBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1081 virtual const char* getDisplayName() const { return "compressed binding info"; }
1082 virtual const char* getSectionName() const { return "._binding info"; }
1083 void encode();
1084 private:
1085 using CompressedInfoLinkEditAtom<A>::fWriter;
1086 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1087 typedef typename A::P P;
1088 typedef typename A::P::uint_t pint_t;
1089 };
1090
1091 template <typename A>
1092 class CompressedWeakBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1093 {
1094 public:
1095 CompressedWeakBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1096 virtual const char* getDisplayName() const { return "compressed weak binding info"; }
1097 virtual const char* getSectionName() const { return "._wkbinding info"; }
1098 void encode();
1099 private:
1100 using CompressedInfoLinkEditAtom<A>::fWriter;
1101 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1102 typedef typename A::P P;
1103 typedef typename A::P::uint_t pint_t;
1104 };
1105
1106 template <typename A>
1107 class CompressedLazyBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1108 {
1109 public:
1110 CompressedLazyBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
1111 virtual const char* getDisplayName() const { return "compressed lazy binding info"; }
1112 virtual const char* getSectionName() const { return "._lzbinding info"; }
1113 void encode();
1114 private:
1115 std::vector<uint32_t> fStarts;
1116
1117 using CompressedInfoLinkEditAtom<A>::fWriter;
1118 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1119 typedef typename A::P P;
1120 typedef typename A::P::uint_t pint_t;
1121 };
1122
1123
1124 template <typename A>
1125 class CompressedExportInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
1126 {
1127 public:
1128 CompressedExportInfoLinkEditAtom(Writer<A>& writer)
1129 : CompressedInfoLinkEditAtom<A>(writer), fStartNode(strdup("")) { }
1130 virtual const char* getDisplayName() const { return "compressed export info"; }
1131 virtual const char* getSectionName() const { return "._export info"; }
1132 void encode();
1133 private:
1134 using WriterAtom<A>::fWriter;
1135 using CompressedInfoLinkEditAtom<A>::fEncodedData;
1136 typedef typename A::P P;
1137 typedef typename A::P::uint_t pint_t;
1138 struct node;
1139
1140 struct edge
1141 {
1142 edge(const char* s, struct node* n) : fSubString(s), fChild(n) { }
1143 ~edge() { }
1144 const char* fSubString;
1145 struct node* fChild;
1146
1147 };
1148
1149 struct node
1150 {
1151 node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false),
1152 fHaveExportInfo(false), fTrieOffset(0) {}
1153 ~node() { }
1154 const char* fCummulativeString;
1155 std::vector<edge> fChildren;
1156 uint64_t fAddress;
1157 uint32_t fFlags;
1158 bool fOrdered;
1159 bool fHaveExportInfo;
1160 uint32_t fTrieOffset;
1161
1162 void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
1163 const char* partialStr = &fullStr[strlen(fCummulativeString)];
1164 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1165 edge& e = *it;
1166 int subStringLen = strlen(e.fSubString);
1167 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1168 // already have matching edge, go down that path
1169 e.fChild->addSymbol(fullStr, address, flags);
1170 return;
1171 }
1172 else {
1173 for (int i=subStringLen-1; i > 0; --i) {
1174 if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
1175 // found a common substring, splice in new node
1176 // was A -> C, now A -> B -> C
1177 char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
1178 bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
1179 //node* aNode = this;
1180 node* bNode = new node(bNodeCummStr);
1181 node* cNode = e.fChild;
1182 char* abEdgeStr = strdup(e.fSubString);
1183 abEdgeStr[i] = '\0';
1184 char* bcEdgeStr = strdup(&e.fSubString[i]);
1185 edge& abEdge = e;
1186 abEdge.fSubString = abEdgeStr;
1187 abEdge.fChild = bNode;
1188 edge bcEdge(bcEdgeStr, cNode);
1189 bNode->fChildren.push_back(bcEdge);
1190 bNode->addSymbol(fullStr, address, flags);
1191 return;
1192 }
1193 }
1194 }
1195 }
1196 // no commonality with any existing child, make a new edge that is this whole string
1197 node* newNode = new node(strdup(fullStr));
1198 edge newEdge(strdup(partialStr), newNode);
1199 fChildren.push_back(newEdge);
1200 newNode->fAddress = address;
1201 newNode->fFlags = flags;
1202 newNode->fHaveExportInfo = true;
1203 }
1204
1205 void addOrderedNodes(const char* name, std::vector<node*>& orderedNodes) {
1206 if ( !fOrdered ) {
1207 orderedNodes.push_back(this);
1208 //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
1209 fOrdered = true;
1210 }
1211 const char* partialStr = &name[strlen(fCummulativeString)];
1212 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1213 edge& e = *it;
1214 int subStringLen = strlen(e.fSubString);
1215 if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
1216 // already have matching edge, go down that path
1217 e.fChild->addOrderedNodes(name, orderedNodes);
1218 return;
1219 }
1220 }
1221 }
1222
1223 // byte for terminal node size in bytes, or 0x00 if not terminal node
1224 // teminal node (uleb128 flags, uleb128 addr)
1225 // byte for child node count
1226 // each child: zero terminated substring, uleb128 node offset
1227 bool updateOffset(uint32_t& offset) {
1228 uint32_t nodeSize = 1; // byte for length of export info
1229 if ( fHaveExportInfo )
1230 nodeSize += ByteStream::uleb128_size(fFlags) + ByteStream::uleb128_size(fAddress);
1231
1232 // add children
1233 ++nodeSize; // byte for count of chidren
1234 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1235 edge& e = *it;
1236 nodeSize += strlen(e.fSubString) + 1 + ByteStream::uleb128_size(e.fChild->fTrieOffset);
1237 }
1238 bool result = (fTrieOffset != offset);
1239 fTrieOffset = offset;
1240 //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
1241 offset += nodeSize;
1242 // return true if fTrieOffset was changed
1243 return result;
1244 }
1245
1246 void appendToStream(ByteStream& out) {
1247 if ( fHaveExportInfo ) {
1248 // nodes with export info: size, flags, address
1249 out.append_byte(out.uleb128_size(fFlags) + out.uleb128_size(fAddress));
1250 out.append_uleb128(fFlags);
1251 out.append_uleb128(fAddress);
1252 }
1253 else {
1254 // no export info
1255 out.append_byte(0);
1256 }
1257 // write number of children
1258 out.append_byte(fChildren.size());
1259 // write each child
1260 for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
1261 edge& e = *it;
1262 out.append_string(e.fSubString);
1263 out.append_uleb128(e.fChild->fTrieOffset);
1264 }
1265 }
1266
1267 };
1268
1269
1270 struct node fStartNode;
1271 };
1272
1273 template <typename A>
1274 class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
1275 {
1276 public:
1277 LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1278 virtual const char* getDisplayName() const { return "local relocations"; }
1279 virtual uint64_t getSize() const;
1280 virtual const char* getSectionName() const { return "._local_relocs"; }
1281 virtual void copyRawContent(uint8_t buffer[]) const;
1282 private:
1283 using WriterAtom<A>::fWriter;
1284 typedef typename A::P P;
1285 };
1286
1287 template <typename A>
1288 class SymbolTableLinkEditAtom : public LinkEditAtom<A>
1289 {
1290 public:
1291 SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1292 virtual const char* getDisplayName() const { return "symbol table"; }
1293 virtual uint64_t getSize() const;
1294 virtual const char* getSectionName() const { return "._symbol_table"; }
1295 virtual void copyRawContent(uint8_t buffer[]) const;
1296 private:
1297 using WriterAtom<A>::fWriter;
1298 typedef typename A::P P;
1299 };
1300
1301 template <typename A>
1302 class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
1303 {
1304 public:
1305 ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1306 virtual const char* getDisplayName() const { return "external relocations"; }
1307 virtual uint64_t getSize() const;
1308 virtual const char* getSectionName() const { return "._extern_relocs"; }
1309 virtual void copyRawContent(uint8_t buffer[]) const;
1310 private:
1311 using WriterAtom<A>::fWriter;
1312 typedef typename A::P P;
1313 };
1314
1315 struct IndirectEntry {
1316 uint32_t indirectIndex;
1317 uint32_t symbolIndex;
1318 };
1319
1320
1321 template <typename A>
1322 class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
1323 {
1324 public:
1325 SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
1326 virtual const char* getDisplayName() const { return "split segment info"; }
1327 virtual uint64_t getSize() const;
1328 virtual const char* getSectionName() const { return "._split_info"; }
1329 virtual void copyRawContent(uint8_t buffer[]) const;
1330 bool canEncode() { return !fCantEncode; }
1331 void setCantEncode() { fCantEncode = true; }
1332 void add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
1333 void add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
1334 void addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
1335 void add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
1336 void encode();
1337
1338 private:
1339 using WriterAtom<A>::fWriter;
1340 typedef typename A::P P;
1341 typedef typename A::P::uint_t pint_t;
1342 struct AtomAndOffset {
1343 AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
1344 const ObjectFile::Atom* atom;
1345 uint32_t offset;
1346 };
1347 void uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
1348
1349 std::vector<AtomAndOffset> fKind1Locations;
1350 std::vector<AtomAndOffset> fKind2Locations;
1351 std::vector<AtomAndOffset> fKind3Locations;
1352 std::vector<AtomAndOffset> fKind4Locations;
1353 std::vector<uint8_t> fEncodedData;
1354 bool fCantEncode;
1355 };
1356
1357 template <typename A>
1358 class IndirectTableLinkEditAtom : public LinkEditAtom<A>
1359 {
1360 public:
1361 IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
1362 virtual const char* getDisplayName() const { return "indirect symbol table"; }
1363 virtual uint64_t getSize() const;
1364 virtual const char* getSectionName() const { return "._indirect_syms"; }
1365 virtual void copyRawContent(uint8_t buffer[]) const;
1366
1367 std::vector<IndirectEntry> fTable;
1368
1369 private:
1370 using WriterAtom<A>::fWriter;
1371 typedef typename A::P P;
1372 };
1373
1374 template <typename A>
1375 class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
1376 {
1377 public:
1378 ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
1379 virtual const char* getDisplayName() const { return "module table"; }
1380 virtual uint64_t getSize() const;
1381 virtual const char* getSectionName() const { return "._module_info"; }
1382 virtual void copyRawContent(uint8_t buffer[]) const;
1383
1384 void setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
1385 uint32_t getTableOfContentsFileOffset() const;
1386 uint32_t getModuleTableFileOffset() const;
1387 uint32_t getReferencesFileOffset() const;
1388 uint32_t getReferencesCount() const;
1389
1390 private:
1391 using WriterAtom<A>::fWriter;
1392 typedef typename A::P P;
1393 typedef typename A::P::uint_t pint_t;
1394 uint32_t fModuleNameOffset;
1395 };
1396
1397
1398 class CStringEquals
1399 {
1400 public:
1401 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
1402 };
1403
1404 template <typename A>
1405 class StringsLinkEditAtom : public LinkEditAtom<A>
1406 {
1407 public:
1408 StringsLinkEditAtom(Writer<A>& writer);
1409 virtual const char* getDisplayName() const { return "string pool"; }
1410 virtual uint64_t getSize() const;
1411 virtual const char* getSectionName() const { return "._string_pool"; }
1412 virtual void copyRawContent(uint8_t buffer[]) const;
1413
1414 int32_t add(const char* name);
1415 int32_t addUnique(const char* name);
1416 int32_t emptyString() { return 1; }
1417 const char* stringForIndex(int32_t) const;
1418
1419 private:
1420 using WriterAtom<A>::fWriter;
1421 typedef typename A::P P;
1422 enum { kBufferSize = 0x01000000 };
1423 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
1424
1425 std::vector<char*> fFullBuffers;
1426 char* fCurrentBuffer;
1427 uint32_t fCurrentBufferUsed;
1428 StringToOffset fUniqueStrings;
1429 };
1430
1431
1432
1433 template <typename A>
1434 class UndefinedSymbolProxyAtom : public WriterAtom<A>
1435 {
1436 public:
1437 UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
1438 virtual const char* getName() const { return fName; }
1439 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
1440 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kExternalDefinition; }
1441 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1442 virtual uint64_t getSize() const { return 0; }
1443 virtual const char* getSectionName() const { return "._imports"; }
1444 private:
1445 using WriterAtom<A>::fWriter;
1446 typedef typename A::P P;
1447 const char* fName;
1448 };
1449
1450 template <typename A>
1451 class BranchIslandAtom : public WriterAtom<A>
1452 {
1453 public:
1454 BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
1455 virtual const char* getName() const { return fName; }
1456 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1457 virtual uint64_t getSize() const;
1458 virtual const char* getSectionName() const { return "__text"; }
1459 virtual void copyRawContent(uint8_t buffer[]) const;
1460 private:
1461 using WriterAtom<A>::fWriter;
1462 const char* fName;
1463 ObjectFile::Atom& fTarget;
1464 uint32_t fTargetOffset;
1465 };
1466
1467 template <typename A>
1468 class StubAtom : public WriterAtom<A>
1469 {
1470 public:
1471 StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
1472 virtual const char* getName() const { return fName; }
1473 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1474 virtual uint64_t getSize() const;
1475 virtual ObjectFile::Alignment getAlignment() const;
1476 virtual const char* getSectionName() const { return "__symbol_stub1"; }
1477 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1478 virtual void copyRawContent(uint8_t buffer[]) const;
1479 ObjectFile::Atom* getTarget() { return &fTarget; }
1480 private:
1481 static const char* stubName(const char* importName);
1482 bool pic() const { return fWriter.fSlideable; }
1483 using WriterAtom<A>::fWriter;
1484 const char* fName;
1485 ObjectFile::Atom& fTarget;
1486 std::vector<ObjectFile::Reference*> fReferences;
1487 bool fForLazyDylib;
1488 };
1489
1490
1491 template <typename A>
1492 class FastStubHelperHelperAtom : public WriterAtom<A>
1493 {
1494 public:
1495 FastStubHelperHelperAtom(Writer<A>& writer);
1496 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1497 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1498 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1499 virtual uint64_t getSize() const;
1500 virtual const char* getSectionName() const { return "__stub_helper"; }
1501 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1502 virtual void copyRawContent(uint8_t buffer[]) const;
1503 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1504 protected:
1505 using WriterAtom<A>::fWriter;
1506 std::vector<ObjectFile::Reference*> fReferences;
1507 };
1508
1509 template <typename A>
1510 class HybridStubHelperHelperAtom : public WriterAtom<A>
1511 {
1512 public:
1513 HybridStubHelperHelperAtom(Writer<A>& writer);
1514 virtual const char* getName() const { return " stub helpers"; } // name sorts to start of helpers
1515 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
1516 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1517 virtual uint64_t getSize() const;
1518 virtual const char* getSectionName() const { return "__stub_helper"; }
1519 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1520 virtual void copyRawContent(uint8_t buffer[]) const;
1521 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1522 protected:
1523 using WriterAtom<A>::fWriter;
1524 std::vector<ObjectFile::Reference*> fReferences;
1525 };
1526
1527 template <typename A>
1528 class StubHelperAtom : public WriterAtom<A>
1529 {
1530 public:
1531 StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1532 LazyPointerAtom<A>& lazyPointer, bool forLazyDylib)
1533 : WriterAtom<A>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
1534 fTarget(target), fLazyPointerAtom(lazyPointer) {
1535 writer.fAllSynthesizedStubHelpers.push_back(this);
1536 }
1537
1538 virtual const char* getName() const { return fName; }
1539 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1540 virtual const char* getSectionName() const { return "__stub_helper"; }
1541 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1542 ObjectFile::Atom* getTarget() { return &fTarget; }
1543 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1544 protected:
1545 static const char* stubName(const char* importName);
1546 using WriterAtom<A>::fWriter;
1547 const char* fName;
1548 ObjectFile::Atom& fTarget;
1549 LazyPointerAtom<A>& fLazyPointerAtom;
1550 std::vector<ObjectFile::Reference*> fReferences;
1551 };
1552
1553 template <typename A>
1554 class ClassicStubHelperAtom : public StubHelperAtom<A>
1555 {
1556 public:
1557 ClassicStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1558 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1559
1560 virtual uint64_t getSize() const;
1561 virtual void copyRawContent(uint8_t buffer[]) const;
1562 };
1563
1564
1565 template <typename A>
1566 class HybridStubHelperAtom : public StubHelperAtom<A>
1567 {
1568 public:
1569 HybridStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1570 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1571
1572 virtual uint64_t getSize() const;
1573 virtual void copyRawContent(uint8_t buffer[]) const;
1574 static class HybridStubHelperHelperAtom<A>* fgHelperHelperAtom;
1575 };
1576 template <typename A> class HybridStubHelperHelperAtom<A>* HybridStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1577
1578 template <typename A>
1579 class FastStubHelperAtom : public StubHelperAtom<A>
1580 {
1581 public:
1582 FastStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target,
1583 class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
1584 virtual uint64_t getSize() const;
1585 virtual void copyRawContent(uint8_t buffer[]) const;
1586 static FastStubHelperHelperAtom<A>* fgHelperHelperAtom;
1587 };
1588 template <typename A> FastStubHelperHelperAtom<A>* FastStubHelperAtom<A>::fgHelperHelperAtom = NULL;
1589
1590
1591
1592 template <typename A>
1593 class LazyPointerAtom : public WriterAtom<A>
1594 {
1595 public:
1596 LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target,
1597 StubAtom<A>& stub, bool forLazyDylib);
1598 virtual const char* getName() const { return fName; }
1599 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1600 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1601 virtual const char* getSectionName() const { return fForLazyDylib ? "__ld_symbol_ptr" : "__la_symbol_ptr"; }
1602 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1603 virtual void copyRawContent(uint8_t buffer[]) const;
1604 ObjectFile::Atom* getTarget() { return &fExternalTarget; }
1605 void setLazyBindingInfoOffset(uint32_t off) { fLazyBindingOffset = off; }
1606 uint32_t getLazyBindingInfoOffset() { return fLazyBindingOffset; }
1607 private:
1608 using WriterAtom<A>::fWriter;
1609 static const char* lazyPointerName(const char* importName);
1610 const char* fName;
1611 ObjectFile::Atom& fTarget;
1612 ObjectFile::Atom& fExternalTarget;
1613 std::vector<ObjectFile::Reference*> fReferences;
1614 bool fForLazyDylib;
1615 uint32_t fLazyBindingOffset;
1616 };
1617
1618
1619 template <typename A>
1620 class NonLazyPointerAtom : public WriterAtom<A>
1621 {
1622 public:
1623 NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
1624 NonLazyPointerAtom(Writer<A>& writer, const char* targetName);
1625 NonLazyPointerAtom(Writer<A>& writer);
1626 virtual const char* getName() const { return fName; }
1627 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1628 virtual uint64_t getSize() const { return sizeof(typename A::P::uint_t); }
1629 virtual const char* getSectionName() const { return (fWriter.fOptions.outputKind() == Options::kKextBundle) ? "__got" : "__nl_symbol_ptr"; }
1630 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
1631 virtual void copyRawContent(uint8_t buffer[]) const;
1632 ObjectFile::Atom* getTarget() { return fTarget; }
1633 private:
1634 using WriterAtom<A>::fWriter;
1635 static const char* nonlazyPointerName(const char* importName);
1636 const char* fName;
1637 ObjectFile::Atom* fTarget;
1638 std::vector<ObjectFile::Reference*> fReferences;
1639 };
1640
1641
1642 template <typename A>
1643 class ObjCInfoAtom : public WriterAtom<A>
1644 {
1645 public:
1646 ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
1647 bool objcReplacementClasses);
1648 virtual const char* getName() const { return "objc$info"; }
1649 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1650 virtual uint64_t getSize() const { return 8; }
1651 virtual const char* getSectionName() const;
1652 virtual void copyRawContent(uint8_t buffer[]) const;
1653 private:
1654 Segment& getInfoSegment() const;
1655 uint32_t fContent[2];
1656 };
1657
1658
1659 template <typename A>
1660 class WriterReference : public ObjectFile::Reference
1661 {
1662 public:
1663 typedef typename A::ReferenceKinds Kinds;
1664
1665 WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
1666 uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
1667 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target), fTargetName(target->getName()),
1668 fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
1669 WriterReference(uint32_t offset, Kinds kind, const char* targetName)
1670 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(NULL), fTargetName(targetName),
1671 fTargetOffset(0), fFromTarget(NULL), fFromTargetOffset(0) {}
1672
1673 virtual ~WriterReference() {}
1674
1675 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return (fTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kUnboundByName; }
1676 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
1677 virtual uint8_t getKind() const { return (uint8_t)fKind; }
1678 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
1679 virtual const char* getTargetName() const { return fTargetName; }
1680 virtual ObjectFile::Atom& getTarget() const { return *fTarget; }
1681 virtual uint64_t getTargetOffset() const { return fTargetOffset; }
1682 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget; }
1683 virtual const char* getFromTargetName() const { return fFromTarget->getName(); }
1684 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fTarget = &target; fTargetOffset = offset; }
1685 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget = &target; }
1686 virtual void setFromTargetName(const char* name) { }
1687 virtual void setFromTargetOffset(uint64_t offset) { fFromTargetOffset = offset; }
1688 virtual const char* getDescription() const { return "writer reference"; }
1689 virtual uint64_t getFromTargetOffset() const { return fFromTargetOffset; }
1690
1691 private:
1692 Kinds fKind;
1693 uint32_t fFixUpOffsetInSrc;
1694 ObjectFile::Atom* fTarget;
1695 const char* fTargetName;
1696 uint32_t fTargetOffset;
1697 ObjectFile::Atom* fFromTarget;
1698 uint32_t fFromTargetOffset;
1699 };
1700
1701
1702 template <typename A>
1703 const char* StubHelperAtom<A>::stubName(const char* name)
1704 {
1705 char* buf;
1706 asprintf(&buf, "%s$stubHelper", name);
1707 return buf;
1708 }
1709
1710 template <>
1711 ClassicStubHelperAtom<x86_64>::ClassicStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1712 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1713 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1714 {
1715 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &fLazyPointerAtom));
1716 if ( forLazyDylib ) {
1717 if ( fWriter.fDyldLazyDylibHelper == NULL )
1718 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
1719 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldLazyDylibHelper));
1720 }
1721 else {
1722 if ( fWriter.fDyldClassicHelperAtom == NULL )
1723 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1724 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldClassicHelperAtom));
1725 }
1726 }
1727
1728
1729 template <>
1730 uint64_t ClassicStubHelperAtom<x86_64>::getSize() const
1731 {
1732 return 12;
1733 }
1734
1735 template <>
1736 void ClassicStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1737 {
1738 buffer[0] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1739 buffer[1] = 0x8D;
1740 buffer[2] = 0x1D;
1741 buffer[3] = 0x00;
1742 buffer[4] = 0x00;
1743 buffer[5] = 0x00;
1744 buffer[6] = 0x00;
1745 buffer[7] = 0xE9; // jmp dyld_stub_binding_helper
1746 buffer[8] = 0x00;
1747 buffer[9] = 0x00;
1748 buffer[10] = 0x00;
1749 buffer[11] = 0x00;
1750 }
1751
1752
1753 template <>
1754 FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(Writer<x86_64>& writer)
1755 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1756 {
1757 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1758 fReferences.push_back(new WriterReference<x86_64>(11, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1759 }
1760
1761 template <>
1762 uint64_t FastStubHelperHelperAtom<x86_64>::getSize() const
1763 {
1764 return 16;
1765 }
1766
1767 template <>
1768 void FastStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1769 {
1770 buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
1771 buffer[1] = 0x8D;
1772 buffer[2] = 0x1D;
1773 buffer[3] = 0x00;
1774 buffer[4] = 0x00;
1775 buffer[5] = 0x00;
1776 buffer[6] = 0x00;
1777 buffer[7] = 0x41; // pushq %r11
1778 buffer[8] = 0x53;
1779 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1780 buffer[10] = 0x25;
1781 buffer[11] = 0x00;
1782 buffer[12] = 0x00;
1783 buffer[13] = 0x00;
1784 buffer[14] = 0x00;
1785 buffer[15] = 0x90; // nop
1786 }
1787
1788
1789 template <>
1790 HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(Writer<x86_64>& writer)
1791 : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
1792 {
1793 if ( writer.fDyldClassicHelperAtom == NULL )
1794 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1795 fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32_1, writer.fFastStubGOTAtom));
1796 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
1797 fReferences.push_back(new WriterReference<x86_64>(21, x86_64::kPCRel32, writer.fFastStubGOTAtom));
1798 fReferences.push_back(new WriterReference<x86_64>(30, x86_64::kPCRel32, writer.fDyldClassicHelperAtom));
1799 }
1800
1801 template <>
1802 uint64_t HybridStubHelperHelperAtom<x86_64>::getSize() const
1803 {
1804 return 34;
1805 }
1806
1807 template <>
1808 void HybridStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1809 {
1810 buffer[0] = 0x48; // cmpl $0x00,_fast_lazy_bind
1811 buffer[1] = 0x83;
1812 buffer[2] = 0x3D;
1813 buffer[3] = 0x00;
1814 buffer[4] = 0x00;
1815 buffer[5] = 0x00;
1816 buffer[6] = 0x00;
1817 buffer[7] = 0x00;
1818 buffer[8] = 0x74; // je 16
1819 buffer[9] = 0x0F;
1820 buffer[10] = 0x4C; // leaq imageCache(%rip),%r11
1821 buffer[11] = 0x8D;
1822 buffer[12] = 0x1D;
1823 buffer[13] = 0x00;
1824 buffer[14] = 0x00;
1825 buffer[15] = 0x00;
1826 buffer[16] = 0x00;
1827 buffer[17] = 0x41; // pushq %r11
1828 buffer[18] = 0x53;
1829 buffer[19] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1830 buffer[20] = 0x25;
1831 buffer[21] = 0x00;
1832 buffer[22] = 0x00;
1833 buffer[23] = 0x00;
1834 buffer[24] = 0x00;
1835 buffer[25] = 0x48; // addq $8,%rsp
1836 buffer[26] = 0x83;
1837 buffer[27] = 0xC4;
1838 buffer[28] = 0x08;
1839 buffer[29] = 0xE9; // jmp dyld_stub_binding_helper
1840 buffer[30] = 0x00;
1841 buffer[31] = 0x00;
1842 buffer[32] = 0x00;
1843 buffer[33] = 0x00;
1844 }
1845
1846
1847 template <>
1848 HybridStubHelperAtom<x86_64>::HybridStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1849 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1850 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1851 {
1852 if ( fgHelperHelperAtom == NULL ) {
1853 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(fWriter);
1854 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1855 }
1856 fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, &fLazyPointerAtom));
1857 fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, fgHelperHelperAtom));
1858 }
1859
1860 template <>
1861 uint64_t HybridStubHelperAtom<x86_64>::getSize() const
1862 {
1863 return 18;
1864 }
1865
1866 template <>
1867 void HybridStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1868 {
1869 buffer[0] = 0x68; // pushq $lazy-info-offset
1870 buffer[1] = 0x00;
1871 buffer[2] = 0x00;
1872 buffer[3] = 0x00;
1873 buffer[4] = 0x00;
1874 buffer[5] = 0x4C; // lea foo$lazy_ptr(%rip),%r11
1875 buffer[6] = 0x8D;
1876 buffer[7] = 0x1D;
1877 buffer[8] = 0x00;
1878 buffer[9] = 0x00;
1879 buffer[10] = 0x00;
1880 buffer[11] = 0x00;
1881 buffer[12] = 0xE9; // jmp helper-helper
1882 buffer[13] = 0x00;
1883 buffer[14] = 0x00;
1884 buffer[15] = 0x00;
1885 buffer[16] = 0x00;
1886 buffer[17] = 0x90; // nop
1887
1888 // the lazy binding info is created later than this helper atom, so there
1889 // is no Reference to update. Instead we blast the offset here.
1890 uint32_t offset;
1891 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1892 memcpy(&buffer[1], &offset, 4);
1893 }
1894
1895 template <>
1896 FastStubHelperAtom<x86_64>::FastStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target,
1897 class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
1898 : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
1899 {
1900 if ( fgHelperHelperAtom == NULL ) {
1901 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(fWriter);
1902 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
1903 }
1904 fReferences.push_back(new WriterReference<x86_64>(6, x86_64::kPCRel32, fgHelperHelperAtom));
1905 }
1906
1907 template <>
1908 uint64_t FastStubHelperAtom<x86_64>::getSize() const
1909 {
1910 return 10;
1911 }
1912
1913 template <>
1914 void FastStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
1915 {
1916 buffer[0] = 0x68; // pushq $lazy-info-offset
1917 buffer[1] = 0x00;
1918 buffer[2] = 0x00;
1919 buffer[3] = 0x00;
1920 buffer[4] = 0x00;
1921 buffer[5] = 0xE9; // jmp helperhelper
1922 buffer[6] = 0x00;
1923 buffer[7] = 0x00;
1924 buffer[8] = 0x00;
1925 buffer[9] = 0x00;
1926
1927 // the lazy binding info is created later than this helper atom, so there
1928 // is no Reference to update. Instead we blast the offset here.
1929 uint32_t offset;
1930 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
1931 memcpy(&buffer[1], &offset, 4);
1932 }
1933
1934 template <>
1935 FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(Writer<x86>& writer)
1936 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1937 {
1938 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1939 fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, writer.fFastStubGOTAtom));
1940 }
1941
1942 template <>
1943 uint64_t FastStubHelperHelperAtom<x86>::getSize() const
1944 {
1945 return 12;
1946 }
1947
1948 template <>
1949 void FastStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1950 {
1951 buffer[0] = 0x68; // pushl $dyld_ImageLoaderCache
1952 buffer[1] = 0x00;
1953 buffer[2] = 0x00;
1954 buffer[3] = 0x00;
1955 buffer[4] = 0x00;
1956 buffer[5] = 0xFF; // jmp *_fast_lazy_bind(%rip)
1957 buffer[6] = 0x25;
1958 buffer[7] = 0x00;
1959 buffer[8] = 0x00;
1960 buffer[9] = 0x00;
1961 buffer[10] = 0x00;
1962 buffer[11] = 0x90; // nop
1963 }
1964
1965
1966 template <>
1967 HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(Writer<x86>& writer)
1968 : WriterAtom<x86>(writer, Segment::fgTextSegment)
1969 {
1970 if ( writer.fDyldClassicHelperAtom == NULL )
1971 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
1972 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, writer.fFastStubGOTAtom));
1973 fReferences.push_back(new WriterReference<x86>(18, x86::kPCRel32, writer.fDyldClassicHelperAtom));
1974 fReferences.push_back(new WriterReference<x86>(26, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
1975 fReferences.push_back(new WriterReference<x86>(32, x86::kAbsolute32, writer.fFastStubGOTAtom));
1976 }
1977
1978 template <>
1979 uint64_t HybridStubHelperHelperAtom<x86>::getSize() const
1980 {
1981 return 36;
1982 }
1983
1984
1985 template <>
1986 void HybridStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
1987 {
1988 buffer[0] = 0x83; // cmpl $0x00,_fast_lazy_bind
1989 buffer[1] = 0x3D;
1990 buffer[2] = 0x00;
1991 buffer[3] = 0x00;
1992 buffer[4] = 0x00;
1993 buffer[5] = 0x00;
1994 buffer[6] = 0x00;
1995 buffer[7] = 0x75; // jne 22
1996 buffer[8] = 0x0D;
1997 buffer[9] = 0x89; // %eax,4(%esp)
1998 buffer[10] = 0x44;
1999 buffer[11] = 0x24;
2000 buffer[12] = 0x04;
2001 buffer[13] = 0x58; // popl %eax
2002 buffer[14] = 0x87; // xchgl (%esp),%eax
2003 buffer[15] = 0x04;
2004 buffer[16] = 0x24;
2005 buffer[17] = 0xE9; // jmpl dyld_stub_binding_helper
2006 buffer[18] = 0x00;
2007 buffer[19] = 0x00;
2008 buffer[20] = 0x00;
2009 buffer[21] = 0x00;
2010 buffer[22] = 0x83; // addl $0x04,%esp
2011 buffer[23] = 0xC4;
2012 buffer[24] = 0x04;
2013 buffer[25] = 0x68; // pushl imageloadercahce
2014 buffer[26] = 0x00;
2015 buffer[27] = 0x00;
2016 buffer[28] = 0x00;
2017 buffer[29] = 0x00;
2018 buffer[30] = 0xFF; // jmp *_fast_lazy_bind(%rip)
2019 buffer[31] = 0x25;
2020 buffer[32] = 0x00;
2021 buffer[33] = 0x00;
2022 buffer[34] = 0x00;
2023 buffer[35] = 0x00;
2024 }
2025
2026
2027 template <>
2028 ClassicStubHelperAtom<x86>::ClassicStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2029 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2030 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2031 {
2032 fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, &fLazyPointerAtom));
2033 if ( forLazyDylib ) {
2034 if ( fWriter.fDyldLazyDylibHelper == NULL )
2035 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2036 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldLazyDylibHelper));
2037 }
2038 else {
2039 if ( fWriter.fDyldClassicHelperAtom == NULL )
2040 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2041 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldClassicHelperAtom));
2042 }
2043 }
2044
2045 template <>
2046 uint64_t ClassicStubHelperAtom<x86>::getSize() const
2047 {
2048 return 10;
2049 }
2050
2051 template <>
2052 void ClassicStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2053 {
2054 buffer[0] = 0x68; // pushl $foo$lazy_ptr
2055 buffer[1] = 0x00;
2056 buffer[2] = 0x00;
2057 buffer[3] = 0x00;
2058 buffer[4] = 0x00;
2059 buffer[5] = 0xE9; // jmp helperhelper
2060 buffer[6] = 0x00;
2061 buffer[7] = 0x00;
2062 buffer[8] = 0x00;
2063 buffer[9] = 0x00;
2064 }
2065
2066 template <>
2067 HybridStubHelperAtom<x86>::HybridStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2068 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2069 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2070 {
2071 if ( fgHelperHelperAtom == NULL ) {
2072 fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(fWriter);
2073 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2074 }
2075 fReferences.push_back(new WriterReference<x86>(6, x86::kAbsolute32, &fLazyPointerAtom));
2076 fReferences.push_back(new WriterReference<x86>(11, x86::kPCRel32, fgHelperHelperAtom));
2077 }
2078
2079
2080 template <>
2081 uint64_t HybridStubHelperAtom<x86>::getSize() const
2082 {
2083 return 16;
2084 }
2085
2086 template <>
2087 void HybridStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2088 {
2089 buffer[0] = 0x68; // pushl $lazy-info-offset
2090 buffer[1] = 0x00;
2091 buffer[2] = 0x00;
2092 buffer[3] = 0x00;
2093 buffer[4] = 0x00;
2094 buffer[5] = 0x68; // pushl $foo$lazy_ptr
2095 buffer[6] = 0x00;
2096 buffer[7] = 0x00;
2097 buffer[8] = 0x00;
2098 buffer[9] = 0x00;
2099 buffer[10] = 0xE9; // jmp dyld_hybrid_stub_binding_helper
2100 buffer[11] = 0x00;
2101 buffer[12] = 0x00;
2102 buffer[13] = 0x00;
2103 buffer[14] = 0x00;
2104 buffer[15] = 0x90; // nop
2105
2106 // the lazy binding info is created later than this helper atom, so there
2107 // is no Reference to update. Instead we blast the offset here.
2108 uint32_t offset;
2109 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2110 memcpy(&buffer[1], &offset, 4);
2111 }
2112
2113
2114 template <>
2115 FastStubHelperAtom<x86>::FastStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target,
2116 class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
2117 : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
2118 {
2119 if ( fgHelperHelperAtom == NULL ) {
2120 fgHelperHelperAtom = new FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(fWriter);
2121 fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
2122 }
2123 fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fgHelperHelperAtom));
2124 }
2125
2126
2127 template <>
2128 uint64_t FastStubHelperAtom<x86>::getSize() const
2129 {
2130 return 10;
2131 }
2132
2133 template <>
2134 void FastStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
2135 {
2136 buffer[0] = 0x68; // pushl $lazy-info-offset
2137 buffer[1] = 0x00;
2138 buffer[2] = 0x00;
2139 buffer[3] = 0x00;
2140 buffer[4] = 0x00;
2141 buffer[5] = 0xE9; // jmp helperhelper
2142 buffer[6] = 0x00;
2143 buffer[7] = 0x00;
2144 buffer[8] = 0x00;
2145 buffer[9] = 0x00;
2146
2147 // the lazy binding info is created later than this helper atom, so there
2148 // is no Reference to update. Instead we blast the offset here.
2149 uint32_t offset;
2150 LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
2151 memcpy(&buffer[1], &offset, 4);
2152 }
2153
2154
2155
2156 // specialize lazy pointer for x86_64 to initially pointer to stub helper
2157 template <>
2158 LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
2159 : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2160 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fLazyBindingOffset(0)
2161 {
2162 if ( forLazyDylib )
2163 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2164 else
2165 writer.fAllSynthesizedLazyPointers.push_back(this);
2166
2167 ObjectFile::Atom* helper;
2168 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2169 if ( writer.fOptions.makeClassicDyldInfo() )
2170 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2171 if ( writer.targetRequiresWeakBinding(target) )
2172 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2173 else
2174 helper = new HybridStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2175 else {
2176 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2177 helper = &target;
2178 else
2179 helper = new FastStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2180 }
2181 }
2182 else {
2183 helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
2184 }
2185 fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
2186 }
2187
2188
2189 // specialize lazy pointer for x86 to initially pointer to stub helper
2190 template <>
2191 LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
2192 : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2193 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
2194 {
2195 if ( forLazyDylib )
2196 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2197 else
2198 writer.fAllSynthesizedLazyPointers.push_back(this);
2199
2200 ObjectFile::Atom* helper;
2201 if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
2202 if ( writer.fOptions.makeClassicDyldInfo() ) {
2203 // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
2204 if ( writer.targetRequiresWeakBinding(target) )
2205 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2206 else
2207 helper = new HybridStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2208 }
2209 else {
2210 if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
2211 helper = &target;
2212 else
2213 helper = new FastStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2214 }
2215 }
2216 else {
2217 helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
2218 }
2219 fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, helper));
2220 }
2221
2222 template <typename A>
2223 LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
2224 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target),
2225 fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib)
2226 {
2227 if ( forLazyDylib )
2228 writer.fAllSynthesizedLazyDylibPointers.push_back(this);
2229 else
2230 writer.fAllSynthesizedLazyPointers.push_back(this);
2231
2232 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2233 }
2234
2235
2236
2237 template <typename A>
2238 const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
2239 {
2240 char* buf;
2241 asprintf(&buf, "%s$lazy_pointer", name);
2242 return buf;
2243 }
2244
2245 template <typename A>
2246 void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2247 {
2248 bzero(buffer, getSize());
2249 }
2250
2251
2252 template <typename A>
2253 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
2254 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(&target)
2255 {
2256 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2257 fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
2258 }
2259
2260 template <typename A>
2261 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer)
2262 : WriterAtom<A>(writer, Segment::fgDataSegment), fName("none"), fTarget(NULL)
2263 {
2264 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2265 }
2266
2267 template <typename A>
2268 NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, const char* targetName)
2269 : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(targetName)), fTarget(NULL)
2270 {
2271 writer.fAllSynthesizedNonLazyPointers.push_back(this);
2272 fReferences.push_back(new WriterReference<A>(0, A::kPointer, targetName));
2273 }
2274
2275 template <typename A>
2276 const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
2277 {
2278 char* buf;
2279 asprintf(&buf, "%s$non_lazy_pointer", name);
2280 return buf;
2281 }
2282
2283 template <typename A>
2284 void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
2285 {
2286 bzero(buffer, getSize());
2287 }
2288
2289
2290
2291 template <>
2292 bool StubAtom<ppc64>::pic() const
2293 {
2294 // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
2295 // Usually that only happens if page zero is very large
2296 return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
2297 }
2298
2299
2300 template <>
2301 bool StubAtom<arm>::pic() const
2302 {
2303 return fWriter.fSlideable;
2304 }
2305
2306 template <>
2307 ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
2308 {
2309 return 2;
2310 }
2311
2312 template <>
2313 ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
2314 {
2315 return 2;
2316 }
2317
2318 template <>
2319 ObjectFile::Alignment StubAtom<arm>::getAlignment() const
2320 {
2321 return 2;
2322 }
2323
2324 template <>
2325 StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2326 : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2327 fTarget(target), fForLazyDylib(forLazyDylib)
2328 {
2329 writer.fAllSynthesizedStubs.push_back(this);
2330 LazyPointerAtom<ppc>* lp;
2331 if ( fWriter.fOptions.prebind() ) {
2332 // for prebound ppc, lazy pointer starts out pointing to target symbol's address
2333 // if target is a weak definition within this linkage unit or zero if in some dylib
2334 lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
2335 }
2336 else {
2337 // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2338 if ( forLazyDylib ) {
2339 if ( writer.fDyldLazyDylibHelper == NULL )
2340 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2341 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2342 }
2343 else {
2344 if ( writer.fDyldClassicHelperAtom == NULL )
2345 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2346 lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2347 }
2348 }
2349 if ( pic() ) {
2350 // picbase is 8 bytes into atom
2351 fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
2352 fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
2353 }
2354 else {
2355 fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
2356 fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
2357 }
2358 }
2359
2360 template <>
2361 StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2362 : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())),
2363 fTarget(target), fForLazyDylib(forLazyDylib)
2364 {
2365 writer.fAllSynthesizedStubs.push_back(this);
2366
2367 LazyPointerAtom<ppc64>* lp;
2368 if ( forLazyDylib ) {
2369 if ( writer.fDyldLazyDylibHelper == NULL )
2370 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2371 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
2372 }
2373 else {
2374 if ( writer.fDyldClassicHelperAtom == NULL )
2375 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2376 lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
2377 }
2378 if ( pic() ) {
2379 // picbase is 8 bytes into atom
2380 fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
2381 fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
2382 }
2383 else {
2384 fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
2385 fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
2386 }
2387 }
2388
2389 template <>
2390 StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2391 : WriterAtom<x86>(writer, (writer.fOptions.makeCompressedDyldInfo()|| forLazyDylib) ? Segment::fgTextSegment : Segment::fgImportSegment),
2392 fName(NULL), fTarget(target), fForLazyDylib(forLazyDylib)
2393 {
2394 if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) {
2395 fName = stubName(target.getName());
2396 LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
2397 fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
2398 writer.fAllSynthesizedStubs.push_back(this);
2399 }
2400 else {
2401 if ( &target == NULL )
2402 fName = "cache-line-crossing-stub";
2403 else {
2404 fName = stubName(target.getName());
2405 writer.fAllSynthesizedStubs.push_back(this);
2406 }
2407 }
2408 }
2409
2410
2411 template <>
2412 StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2413 : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2414 {
2415 writer.fAllSynthesizedStubs.push_back(this);
2416
2417 LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
2418 fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
2419 }
2420
2421 template <>
2422 StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
2423 : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
2424 {
2425 writer.fAllSynthesizedStubs.push_back(this);
2426
2427 LazyPointerAtom<arm>* lp;
2428 if ( fWriter.fOptions.prebind() && !forLazyDylib ) {
2429 // for prebound arm, lazy pointer starts out pointing to target symbol's address
2430 // if target is a weak definition within this linkage unit or zero if in some dylib
2431 lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
2432 }
2433 else {
2434 // for non-prebound arm, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
2435 ObjectFile::Atom* helper;
2436 if ( forLazyDylib ) {
2437 if ( writer.fDyldLazyDylibHelper == NULL )
2438 throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
2439 helper = writer.fDyldLazyDylibHelper;
2440 }
2441 else {
2442 if ( writer.fDyldClassicHelperAtom == NULL )
2443 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
2444 helper = writer.fDyldClassicHelperAtom;
2445 }
2446 lp = new LazyPointerAtom<arm>(writer, *helper, *this, forLazyDylib);
2447 }
2448 if ( pic() )
2449 fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
2450 else
2451 fReferences.push_back(new WriterReference<arm>(8, arm::kPointer, lp));
2452 }
2453
2454 template <typename A>
2455 const char* StubAtom<A>::stubName(const char* name)
2456 {
2457 char* buf;
2458 asprintf(&buf, "%s$stub", name);
2459 return buf;
2460 }
2461
2462 template <>
2463 uint64_t StubAtom<ppc>::getSize() const
2464 {
2465 return ( pic() ? 32 : 16 );
2466 }
2467
2468 template <>
2469 uint64_t StubAtom<ppc64>::getSize() const
2470 {
2471 return ( pic() ? 32 : 16 );
2472 }
2473
2474
2475 template <>
2476 uint64_t StubAtom<arm>::getSize() const
2477 {
2478 return ( pic() ? 16 : 12 );
2479 }
2480
2481 template <>
2482 uint64_t StubAtom<x86>::getSize() const
2483 {
2484 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2485 return 6;
2486 else
2487 return 5;
2488 }
2489
2490 template <>
2491 uint64_t StubAtom<x86_64>::getSize() const
2492 {
2493 return 6;
2494 }
2495
2496 template <>
2497 ObjectFile::Alignment StubAtom<x86>::getAlignment() const
2498 {
2499 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2500 return 1;
2501 else
2502 return 0; // special case x86 self-modifying stubs to be byte aligned
2503 }
2504
2505 template <>
2506 void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
2507 {
2508 if ( pic() ) {
2509 OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
2510 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2511 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2512 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2513 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2514 OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2515 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2516 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2517 }
2518 else {
2519 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2520 OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
2521 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2522 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2523 }
2524 }
2525
2526 template <>
2527 void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
2528 {
2529 if ( pic() ) {
2530 OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
2531 OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
2532 OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
2533 OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
2534 OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
2535 OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
2536 OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
2537 OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
2538 }
2539 else {
2540 OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
2541 OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
2542 OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
2543 OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
2544 }
2545 }
2546
2547 template <>
2548 void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
2549 {
2550 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib ) {
2551 buffer[0] = 0xFF; // jmp *foo$lazy_pointer
2552 buffer[1] = 0x25;
2553 buffer[2] = 0x00;
2554 buffer[3] = 0x00;
2555 buffer[4] = 0x00;
2556 buffer[5] = 0x00;
2557 }
2558 else {
2559 if ( fWriter.fOptions.prebind() ) {
2560 uint32_t address = this->getAddress();
2561 int32_t rel32 = 0 - (address+5);
2562 buffer[0] = 0xE9;
2563 buffer[1] = rel32 & 0xFF;
2564 buffer[2] = (rel32 >> 8) & 0xFF;
2565 buffer[3] = (rel32 >> 16) & 0xFF;
2566 buffer[4] = (rel32 >> 24) & 0xFF;
2567 }
2568 else {
2569 buffer[0] = 0xF4;
2570 buffer[1] = 0xF4;
2571 buffer[2] = 0xF4;
2572 buffer[3] = 0xF4;
2573 buffer[4] = 0xF4;
2574 }
2575 }
2576 }
2577
2578 template <>
2579 void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
2580 {
2581 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
2582 buffer[1] = 0x25;
2583 buffer[2] = 0x00;
2584 buffer[3] = 0x00;
2585 buffer[4] = 0x00;
2586 buffer[5] = 0x00;
2587 }
2588
2589 template <>
2590 void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
2591 {
2592 if ( pic() ) {
2593 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
2594 OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
2595 OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
2596 OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
2597 }
2598 else {
2599 OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
2600 OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
2601 OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
2602 }
2603 }
2604
2605 // x86_64 stubs are 6 bytes
2606 template <>
2607 ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
2608 {
2609 return 1;
2610 }
2611
2612 template <>
2613 const char* StubAtom<ppc>::getSectionName() const
2614 {
2615 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
2616 }
2617
2618 template <>
2619 const char* StubAtom<ppc64>::getSectionName() const
2620 {
2621 return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
2622 }
2623
2624 template <>
2625 const char* StubAtom<arm>::getSectionName() const
2626 {
2627 return ( pic() ? "__picsymbolstub4" : "__symbol_stub4");
2628 }
2629
2630 template <>
2631 const char* StubAtom<x86>::getSectionName() const
2632 {
2633 if ( fWriter.fOptions.makeCompressedDyldInfo() || fForLazyDylib )
2634 return "__symbol_stub";
2635 else
2636 return "__jump_table";
2637 }
2638
2639
2640
2641
2642 struct AtomByNameSorter
2643 {
2644 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
2645 {
2646 return (strcmp(left->getName(), right->getName()) < 0);
2647 }
2648 };
2649
2650 template <typename P>
2651 struct ExternalRelocSorter
2652 {
2653 bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
2654 {
2655 // sort first by symbol number
2656 if ( left.r_symbolnum() != right.r_symbolnum() )
2657 return (left.r_symbolnum() < right.r_symbolnum());
2658 // then sort all uses of the same symbol by address
2659 return (left.r_address() < right.r_address());
2660 }
2661 };
2662
2663
2664 template <typename A>
2665 Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
2666 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
2667 fAllAtoms(NULL), fStabs(NULL), fRegularDefAtomsThatOverrideADylibsWeakDef(NULL), fLoadCommandsSection(NULL),
2668 fLoadCommandsSegment(NULL), fMachHeaderAtom(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
2669 fSymbolTableCommands(NULL), fHeaderPadding(NULL), fUnwindInfoAtom(NULL),
2670 fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL),
2671 fDyldClassicHelperAtom(NULL), fDyldCompressedHelperAtom(NULL), fDyldLazyDylibHelper(NULL),
2672 fSectionRelocationsAtom(NULL), fCompressedRebaseInfoAtom(NULL), fCompressedBindingInfoAtom(NULL),
2673 fCompressedWeakBindingInfoAtom(NULL), fCompressedLazyBindingInfoAtom(NULL), fCompressedExportInfoAtom(NULL),
2674 fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
2675 fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
2676 fStringsAtom(NULL), fPageZeroAtom(NULL), fFastStubGOTAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0),
2677 fSymbolTableStabsCount(0), fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
2678 fLargestAtomSize(1),
2679 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
2680 fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
2681 fBiggerThanTwoGigs(false), fSlideable(false),
2682 fFirstWritableSegment(NULL), fAnonNameIndex(1000)
2683 {
2684 switch ( fOptions.outputKind() ) {
2685 case Options::kDynamicExecutable:
2686 case Options::kStaticExecutable:
2687 if ( fOptions.zeroPageSize() != 0 )
2688 fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
2689 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2690 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2691 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2692 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2693 if ( fOptions.makeCompressedDyldInfo() )
2694 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2695 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2696 if ( fOptions.outputKind() == Options::kDynamicExecutable )
2697 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2698 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2699 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2700 if ( fOptions.hasCustomStack() )
2701 fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
2702 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2703 if ( fOptions.needsUnwindInfoSection() )
2704 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2705 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2706 if ( fOptions.makeCompressedDyldInfo() ) {
2707 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2708 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2709 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2710 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2711 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2712 }
2713 if ( fOptions.makeClassicDyldInfo() )
2714 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2715 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2716 if ( fOptions.makeClassicDyldInfo() )
2717 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2718 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2719 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2720 break;
2721 case Options::kPreload:
2722 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2723 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2724 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2725 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2726 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2727 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2728 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2729 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2730 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2731 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2732 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2733 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2734 break;
2735 case Options::kDynamicLibrary:
2736 case Options::kDynamicBundle:
2737 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2738 case Options::kKextBundle:
2739 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2740 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2741 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
2742 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
2743 if ( fOptions.initFunctionName() != NULL )
2744 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
2745 }
2746 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2747 if ( fOptions.makeCompressedDyldInfo() )
2748 fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
2749 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2750 if ( fOptions.sharedRegionEligible() )
2751 fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
2752 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2753 if ( fOptions.needsUnwindInfoSection() )
2754 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2755 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2756 if ( fOptions.makeCompressedDyldInfo() ) {
2757 fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
2758 fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
2759 fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
2760 fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
2761 fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
2762 }
2763 if ( fOptions.makeClassicDyldInfo() )
2764 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2765 if ( fOptions.sharedRegionEligible() ) {
2766 fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
2767 }
2768 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2769 if ( fOptions.makeClassicDyldInfo() )
2770 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2771 if ( fOptions.outputKind() != Options::kKextBundle )
2772 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2773 if ( this->needsModuleTable() )
2774 fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
2775 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2776 break;
2777 case Options::kObjectFile:
2778 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2779 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2780 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2781 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2782 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2783 fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
2784 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2785 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2786 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2787 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2788 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2789 break;
2790 case Options::kDyld:
2791 fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
2792 fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
2793 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
2794 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
2795 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
2796 fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
2797 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
2798 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
2799 if ( fOptions.needsUnwindInfoSection() )
2800 fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
2801 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
2802 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
2803 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
2804 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
2805 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
2806 break;
2807 }
2808
2809 // add extra commmands
2810 bool hasReExports = false;
2811 uint32_t ordinal = 1;
2812 switch ( fOptions.outputKind() ) {
2813 case Options::kDynamicExecutable:
2814 if ( fOptions.makeEncryptable() ) {
2815 fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
2816 fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
2817 }
2818 // fall through
2819 case Options::kDynamicLibrary:
2820 case Options::kDynamicBundle:
2821 {
2822 // add dylib load command atoms for all dynamic libraries
2823 const unsigned int libCount = dynamicLibraries.size();
2824 for (unsigned int i=0; i < libCount; ++i) {
2825 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
2826 //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
2827
2828 if ( dylibInfo.options.fReExport ) {
2829 hasReExports = true;
2830 }
2831 else {
2832 const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
2833 if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
2834 const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
2835 if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
2836 hasReExports = true;
2837 }
2838 }
2839
2840 if ( dylibInfo.options.fWeakImport ) {
2841 fForcedWeakImportReaders.insert(dylibInfo.reader);
2842 }
2843
2844 if ( dylibInfo.options.fBundleLoader ) {
2845 fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
2846 }
2847 else {
2848 // see if a DylibLoadCommandsAtom has already been created for this install path
2849 bool newDylib = true;
2850 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
2851 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
2852 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
2853 if ( !seenDylibInfo.options.fBundleLoader ) {
2854 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
2855 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
2856 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
2857 fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
2858 fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
2859 newDylib = false;
2860 break;
2861 }
2862 }
2863 }
2864
2865 if ( newDylib ) {
2866 // assign new ordinal and check for other paired load commands
2867 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
2868 DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
2869 fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
2870 fWriterSynthesizedAtoms.push_back(dyliblc);
2871 if ( dylibInfo.options.fReExport
2872 && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
2873 && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
2874 // see if child has sub-framework that is this
2875 bool isSubFramework = false;
2876 const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
2877 if ( childInUmbrella != NULL ) {
2878 const char* myLeaf = strrchr(fOptions.installPath(), '/');
2879 if ( myLeaf != NULL ) {
2880 if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
2881 isSubFramework = true;
2882 }
2883 }
2884 // LC_SUB_FRAMEWORK is in child, so do nothing in parent
2885 if ( ! isSubFramework ) {
2886 // this dylib also needs a sub_x load command
2887 bool isFrameworkReExport = false;
2888 const char* lastSlash = strrchr(dylibInstallPath, '/');
2889 if ( lastSlash != NULL ) {
2890 char frameworkName[strlen(lastSlash)+20];
2891 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
2892 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
2893 }
2894 if ( isFrameworkReExport ) {
2895 // needs a LC_SUB_UMBRELLA command
2896 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
2897 }
2898 else {
2899 // needs a LC_SUB_LIBRARY command
2900 const char* nameStart = &lastSlash[1];
2901 if ( lastSlash == NULL )
2902 nameStart = dylibInstallPath;
2903 int len = strlen(nameStart);
2904 const char* dot = strchr(nameStart, '.');
2905 if ( dot != NULL )
2906 len = dot - nameStart;
2907 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
2908 }
2909 }
2910 }
2911 }
2912 }
2913 }
2914 // add umbrella command if needed
2915 if ( fOptions.umbrellaName() != NULL ) {
2916 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
2917 }
2918 // add allowable client commands if used
2919 std::vector<const char*>& allowableClients = fOptions.allowableClients();
2920 for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
2921 fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
2922 }
2923 break;
2924 case Options::kStaticExecutable:
2925 case Options::kObjectFile:
2926 case Options::kDyld:
2927 case Options::kPreload:
2928 case Options::kKextBundle:
2929 break;
2930 }
2931 fNoReExportedDylibs = !hasReExports;
2932
2933 // add any rpath load commands
2934 for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
2935 fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
2936 }
2937
2938 // set up fSlideable
2939 switch ( fOptions.outputKind() ) {
2940 case Options::kObjectFile:
2941 case Options::kStaticExecutable:
2942 fSlideable = false;
2943 break;
2944 case Options::kDynamicExecutable:
2945 fSlideable = fOptions.positionIndependentExecutable();
2946 break;
2947 case Options::kDyld:
2948 case Options::kDynamicLibrary:
2949 case Options::kDynamicBundle:
2950 case Options::kPreload:
2951 case Options::kKextBundle:
2952 fSlideable = true;
2953 break;
2954 }
2955
2956 //fprintf(stderr, "ordinals table:\n");
2957 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
2958 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
2959 //}
2960 }
2961
2962 template <typename A>
2963 Writer<A>::~Writer()
2964 {
2965 if ( fFilePath != NULL )
2966 free((void*)fFilePath);
2967 if ( fSymbolTable != NULL )
2968 delete [] fSymbolTable;
2969 }
2970
2971
2972 // for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
2973 template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
2974 template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
2975
2976
2977 template <typename A>
2978 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
2979 {
2980 if ( fOptions.outputKind() == Options::kKextBundle ) {
2981 return new UndefinedSymbolProxyAtom<A>(*this, name);
2982 }
2983 else if ( fOptions.outputKind() == Options::kObjectFile ) {
2984 // when doing -r -exported_symbols_list, don't create proxy for a symbol
2985 // that is supposed to be exported. We want an error instead
2986 // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
2987 if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) )
2988 return NULL;
2989 else
2990 return new UndefinedSymbolProxyAtom<A>(*this, name);
2991 }
2992 else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
2993 return new UndefinedSymbolProxyAtom<A>(*this, name);
2994 else
2995 return NULL;
2996 }
2997
2998 template <typename A>
2999 uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
3000 {
3001 // flat namespace images use zero for all ordinals
3002 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3003 return 0;
3004
3005 // is an UndefinedSymbolProxyAtom
3006 if ( lib == this )
3007 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3008 return DYNAMIC_LOOKUP_ORDINAL;
3009
3010 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
3011 if ( pos != fLibraryToOrdinal.end() )
3012 return pos->second;
3013
3014 throw "can't find ordinal for imported symbol";
3015 }
3016
3017 template <typename A>
3018 bool Writer<A>::targetRequiresWeakBinding(const ObjectFile::Atom& target)
3019 {
3020 switch ( target.getDefinitionKind() ) {
3021 case ObjectFile::Atom::kExternalWeakDefinition:
3022 case ObjectFile::Atom::kWeakDefinition:
3023 return true;
3024 case ObjectFile::Atom::kExternalDefinition:
3025 case ObjectFile::Atom::kAbsoluteSymbol:
3026 case ObjectFile::Atom::kRegularDefinition:
3027 case ObjectFile::Atom::kTentativeDefinition:
3028 break;
3029 }
3030 return false;
3031 }
3032
3033 template <typename A>
3034 int Writer<A>::compressedOrdinalForImortedAtom(ObjectFile::Atom* target)
3035 {
3036 // flat namespace images use zero for all ordinals
3037 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
3038 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3039
3040 // is an UndefinedSymbolProxyAtom
3041 ObjectFile::Reader* lib = target->getFile();
3042 if ( lib == this )
3043 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
3044 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
3045
3046 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos;
3047 switch ( target->getDefinitionKind() ) {
3048 case ObjectFile::Atom::kExternalDefinition:
3049 case ObjectFile::Atom::kExternalWeakDefinition:
3050 pos = fLibraryToOrdinal.find(lib);
3051 if ( pos != fLibraryToOrdinal.end() ) {
3052 if ( pos->second == EXECUTABLE_ORDINAL )
3053 return BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
3054 else
3055 return pos->second;
3056 }
3057 break;
3058 case ObjectFile::Atom::kWeakDefinition:
3059 throw "compressedOrdinalForImortedAtom() should not have been called on a weak definition";
3060 case ObjectFile::Atom::kAbsoluteSymbol:
3061 case ObjectFile::Atom::kRegularDefinition:
3062 case ObjectFile::Atom::kTentativeDefinition:
3063 return BIND_SPECIAL_DYLIB_SELF;
3064 }
3065
3066 throw "can't find ordinal for imported symbol";
3067 }
3068
3069
3070 template <typename A>
3071 ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
3072 {
3073 return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
3074 }
3075
3076
3077 template <typename A>
3078 uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
3079 std::vector<class ObjectFile::Reader::Stab>& stabs,
3080 class ObjectFile::Atom* entryPointAtom,
3081 class ObjectFile::Atom* dyldClassicHelperAtom,
3082 class ObjectFile::Atom* dyldCompressedHelperAtom,
3083 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
3084 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
3085 bool biggerThanTwoGigs,
3086 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
3087 bool hasExternalWeakDefinitions)
3088 {
3089 fAllAtoms = &atoms;
3090 fStabs = &stabs;
3091 fEntryPoint = entryPointAtom;
3092 fDyldClassicHelperAtom = dyldClassicHelperAtom;
3093 fDyldCompressedHelperAtom = dyldCompressedHelperAtom;
3094 fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
3095 fCanScatter = canScatter;
3096 fCpuConstraint = cpuConstraint;
3097 fBiggerThanTwoGigs = biggerThanTwoGigs;
3098 fHasWeakExports = hasExternalWeakDefinitions; // dyld needs to search this image as if it had weak exports
3099 fRegularDefAtomsThatOverrideADylibsWeakDef = &atomsThatOverrideWeak;
3100
3101
3102 try {
3103 // Set for create UUID
3104 if (createUUID)
3105 fUUIDAtom->generate();
3106
3107 // remove uneeded dylib load commands
3108 optimizeDylibReferences();
3109
3110 // check for mdynamic-no-pic codegen
3111 scanForAbsoluteReferences();
3112
3113 // create inter-library stubs
3114 synthesizeStubs();
3115
3116 // create table of unwind info
3117 synthesizeUnwindInfoTable();
3118
3119 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
3120 partitionIntoSections();
3121
3122 // segment load command can now be sized and padding can be set
3123 adjustLoadCommandsAndPadding();
3124
3125 // assign each section a file offset
3126 assignFileOffsets();
3127
3128 // if need to add branch islands, reassign file offsets
3129 if ( addBranchIslands() )
3130 assignFileOffsets();
3131
3132 // now that addresses are assigned, create unwind info
3133 if ( fUnwindInfoAtom != NULL ) {
3134 fUnwindInfoAtom->generate();
3135 // re-layout
3136 adjustLoadCommandsAndPadding();
3137 assignFileOffsets();
3138 }
3139
3140 // make spit-seg info now that all atoms exist
3141 createSplitSegContent();
3142
3143 // build symbol table and relocations
3144 buildLinkEdit();
3145
3146 // write map file if requested
3147 writeMap();
3148
3149 // write everything
3150 return writeAtoms();
3151 } catch (...) {
3152 // clean up if any errors
3153 (void)unlink(fFilePath);
3154 throw;
3155 }
3156 }
3157
3158 template <typename A>
3159 void Writer<A>::buildLinkEdit()
3160 {
3161 this->collectExportedAndImportedAndLocalAtoms();
3162 this->buildSymbolTable();
3163 this->buildFixups();
3164 this->adjustLinkEditSections();
3165 }
3166
3167
3168
3169 template <typename A>
3170 uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
3171 {
3172 return atom->getAddress();
3173 // SectionInfo* info = (SectionInfo*)atom->getSection();
3174 // return info->getBaseAddress() + atom->getSectionOffset();
3175 }
3176
3177 template <>
3178 bool Writer<x86_64>::stringsNeedLabelsInObjects()
3179 {
3180 return true;
3181 }
3182
3183 template <typename A>
3184 bool Writer<A>::stringsNeedLabelsInObjects()
3185 {
3186 return false;
3187 }
3188
3189 template <typename A>
3190 const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
3191 {
3192 static unsigned int counter = 0;
3193 const char* name;
3194 if ( stringsNeedLabelsInObjects()
3195 && (atom->getContentType() == ObjectFile::Atom::kCStringType)
3196 && (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) )
3197 asprintf((char**)&name, "LC%u", counter++);
3198 else
3199 name = atom->getName();
3200 return name;
3201 return atom->getName();
3202 }
3203
3204 template <typename A>
3205 void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3206 {
3207 // set n_strx
3208 entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
3209
3210 // set n_type
3211 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
3212 entry->set_n_type(N_EXT | N_ABS);
3213 }
3214 else {
3215 entry->set_n_type(N_EXT | N_SECT);
3216 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
3217 if ( fOptions.keepPrivateExterns() )
3218 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
3219 }
3220 }
3221
3222 // set n_sect (section number of implementation )
3223 uint8_t sectionIndex = atom->getSection()->getIndex();
3224 entry->set_n_sect(sectionIndex);
3225
3226 // the __mh_execute_header is magic and must be an absolute symbol
3227 if ( (sectionIndex==0)
3228 && (fOptions.outputKind() == Options::kDynamicExecutable)
3229 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
3230 entry->set_n_type(N_EXT | N_ABS);
3231
3232 // set n_desc
3233 uint16_t desc = 0;
3234 if ( atom->isThumb() )
3235 desc |= N_ARM_THUMB_DEF;
3236 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3237 desc |= REFERENCED_DYNAMICALLY;
3238 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
3239 desc |= N_WEAK_DEF;
3240 fHasWeakExports = true;
3241 }
3242 entry->set_n_desc(desc);
3243
3244 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3245 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3246 entry->set_n_value(atom->getSectionOffset());
3247 else
3248 entry->set_n_value(this->getAtomLoadAddress(atom));
3249 }
3250
3251 template <typename A>
3252 void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3253 {
3254 // set n_strx
3255 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
3256
3257 // set n_type
3258 if ( fOptions.outputKind() == Options::kObjectFile ) {
3259 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3260 && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
3261 entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
3262 else
3263 entry->set_n_type(N_UNDF | N_EXT);
3264 }
3265 else {
3266 if ( fOptions.prebind() )
3267 entry->set_n_type(N_PBUD | N_EXT);
3268 else
3269 entry->set_n_type(N_UNDF | N_EXT);
3270 }
3271
3272 // set n_sect
3273 entry->set_n_sect(0);
3274
3275 uint16_t desc = 0;
3276 if ( fOptions.outputKind() != Options::kObjectFile ) {
3277 // set n_desc ( high byte is library ordinal, low byte is reference type )
3278 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
3279 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
3280 desc = REFERENCE_FLAG_UNDEFINED_LAZY;
3281 else
3282 desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
3283 try {
3284 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
3285 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
3286 SET_LIBRARY_ORDINAL(desc, ordinal);
3287 }
3288 catch (const char* msg) {
3289 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3290 }
3291 }
3292 else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
3293 uint8_t align = atom->getAlignment().powerOf2;
3294 // always record custom alignment of common symbols to match what compiler does
3295 SET_COMM_ALIGN(desc, align);
3296 }
3297 if ( atom->isThumb() )
3298 desc |= N_ARM_THUMB_DEF;
3299 if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
3300 desc |= REFERENCED_DYNAMICALLY;
3301 if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
3302 desc |= N_REF_TO_WEAK;
3303 fReferencesWeakImports = true;
3304 }
3305 // set weak_import attribute
3306 if ( fWeakImportMap[atom] )
3307 desc |= N_WEAK_REF;
3308 entry->set_n_desc(desc);
3309
3310 // set n_value, zero for import proxy and size for tentative definition
3311 entry->set_n_value(atom->getSize());
3312 }
3313
3314
3315 template <typename A>
3316 void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
3317 {
3318 // set n_strx
3319 const char* symbolName = this->symbolTableName(atom);
3320 char anonName[32];
3321 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
3322 sprintf(anonName, "l%u", fAnonNameIndex++);
3323 symbolName = anonName;
3324 }
3325 entry->set_n_strx(this->fStringsAtom->add(symbolName));
3326
3327 // set n_type
3328 uint8_t type = N_SECT;
3329 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3330 type = N_ABS;
3331 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
3332 type |= N_PEXT;
3333 entry->set_n_type(type);
3334
3335 // set n_sect (section number of implementation )
3336 uint8_t sectIndex = atom->getSection()->getIndex();
3337 if ( sectIndex == 0 ) {
3338 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
3339 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
3340 sectIndex = 1;
3341 }
3342 entry->set_n_sect(sectIndex);
3343
3344 // set n_desc
3345 uint16_t desc = 0;
3346 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
3347 desc |= N_WEAK_DEF;
3348 if ( atom->isThumb() )
3349 desc |= N_ARM_THUMB_DEF;
3350 entry->set_n_desc(desc);
3351
3352 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3353 if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
3354 entry->set_n_value(atom->getSectionOffset());
3355 else
3356 entry->set_n_value(this->getAtomLoadAddress(atom));
3357 }
3358
3359
3360 template <typename A>
3361 void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3362 {
3363 macho_nlist<P> entry;
3364
3365 // set n_strx
3366 entry.set_n_strx(fStringsAtom->add(name));
3367
3368 // set n_type
3369 entry.set_n_type(N_SECT);
3370
3371 // set n_sect (section number of implementation )
3372 entry.set_n_sect(atom.getSection()->getIndex());
3373
3374 // set n_desc
3375 entry.set_n_desc(0);
3376
3377 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3378 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3379
3380 // add
3381 fLocalExtraLabels.push_back(entry);
3382 }
3383
3384
3385
3386 template <typename A>
3387 void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
3388 {
3389 macho_nlist<P> entry;
3390
3391 // set n_strx
3392 entry.set_n_strx(fStringsAtom->add(name));
3393
3394 // set n_type
3395 entry.set_n_type(N_SECT|N_EXT);
3396
3397 // set n_sect (section number of implementation )
3398 entry.set_n_sect(atom.getSection()->getIndex());
3399
3400 // set n_desc
3401 entry.set_n_desc(0);
3402
3403 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
3404 entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
3405
3406 // add
3407 fGlobalExtraLabels.push_back(entry);
3408 }
3409
3410 template <typename A>
3411 void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
3412 {
3413 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3414 for (uint32_t i=0; i < count; ++i, ++entry) {
3415 ObjectFile::Atom* atom = atoms[i];
3416 if ( &atoms == &fExportedAtoms ) {
3417 this->setExportNlist(atom, entry);
3418 }
3419 else if ( &atoms == &fImportedAtoms ) {
3420 this->setImportNlist(atom, entry);
3421 }
3422 else {
3423 this->setLocalNlist(atom, entry);
3424 }
3425 }
3426 }
3427
3428 template <typename A>
3429 void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
3430 {
3431 for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
3432 fSymbolTable[startIndex++] = *it;
3433 }
3434
3435
3436 template <typename A>
3437 struct NListNameSorter
3438 {
3439 NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
3440
3441 bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
3442 {
3443 return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
3444 }
3445 private:
3446 StringsLinkEditAtom<A>* fStringPool;
3447 };
3448
3449
3450 template <typename A>
3451 void Writer<A>::buildSymbolTable()
3452 {
3453 fSymbolTableStabsStartIndex = 0;
3454 fSymbolTableStabsCount = fStabs->size();
3455 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
3456 fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
3457 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
3458 fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
3459 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
3460 fSymbolTableImportCount = fImportedAtoms.size();
3461
3462 // allocate symbol table
3463 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
3464 fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
3465
3466 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
3467 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fLocalSymbolAtoms.size());
3468 if ( fLocalExtraLabels.size() != 0 )
3469 copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
3470 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fExportedAtoms.size());
3471 if ( fGlobalExtraLabels.size() != 0 ) {
3472 copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
3473 // re-sort combined range
3474 std::sort( &fSymbolTable[fSymbolTableExportStartIndex],
3475 &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount],
3476 NListNameSorter<A>(fStringsAtom) );
3477 }
3478 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
3479 addStabs(fSymbolTableStabsStartIndex);
3480
3481 // set up module table
3482 if ( fModuleInfoAtom != NULL )
3483 fModuleInfoAtom->setName();
3484 }
3485
3486
3487
3488 template <typename A>
3489 bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
3490 {
3491 switch ( atom.getSymbolTableInclusion() ) {
3492 case ObjectFile::Atom::kSymbolTableNotIn:
3493 return false;
3494 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3495 return true;
3496 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3497 case ObjectFile::Atom::kSymbolTableIn:
3498 switch ( atom.getScope() ) {
3499 case ObjectFile::Atom::scopeGlobal:
3500 return true;
3501 case ObjectFile::Atom::scopeLinkageUnit:
3502 return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
3503 default:
3504 return false;
3505 }
3506 break;
3507 }
3508 return false;
3509 }
3510
3511 template <typename A>
3512 void Writer<A>::collectExportedAndImportedAndLocalAtoms()
3513 {
3514 const int atomCount = fAllAtoms->size();
3515 // guess at sizes of each bucket to minimize re-allocations
3516 fImportedAtoms.reserve(100);
3517 fExportedAtoms.reserve(atomCount/2);
3518 fLocalSymbolAtoms.reserve(atomCount);
3519 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
3520 ObjectFile::Atom* atom = *it;
3521 // only named atoms go in symbol table
3522 if ( atom->getName() != NULL ) {
3523 // put atom into correct bucket: imports, exports, locals
3524 //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
3525 switch ( atom->getDefinitionKind() ) {
3526 case ObjectFile::Atom::kExternalDefinition:
3527 case ObjectFile::Atom::kExternalWeakDefinition:
3528 fImportedAtoms.push_back(atom);
3529 break;
3530 case ObjectFile::Atom::kTentativeDefinition:
3531 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
3532 fImportedAtoms.push_back(atom);
3533 break;
3534 }
3535 // else fall into
3536 case ObjectFile::Atom::kWeakDefinition:
3537 if ( stringsNeedLabelsInObjects()
3538 && (fOptions.outputKind() == Options::kObjectFile)
3539 && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn)
3540 && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
3541 && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
3542 fLocalSymbolAtoms.push_back(atom);
3543 break;
3544 }
3545 // else fall into
3546 case ObjectFile::Atom::kRegularDefinition:
3547 case ObjectFile::Atom::kAbsoluteSymbol:
3548 if ( this->shouldExport(*atom) )
3549 fExportedAtoms.push_back(atom);
3550 else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
3551 && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
3552 fLocalSymbolAtoms.push_back(atom);
3553 break;
3554 }
3555 }
3556 // when geneating a .o file, dtrace static probes become local labels
3557 if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
3558 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3559 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3560 ObjectFile::Reference* ref = *rit;
3561 if ( ref->getKind() == A::kDtraceProbe ) {
3562 // dtrace probe points to be add back into generated .o file
3563 this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3564 }
3565 }
3566 }
3567 // when linking kernel, old style dtrace static probes become global labels
3568 else if ( fOptions.readerOptions().fForStatic ) {
3569 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3570 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
3571 ObjectFile::Reference* ref = *rit;
3572 if ( ref->getKind() == A::kDtraceProbe ) {
3573 // dtrace probe points to be add back into generated .o file
3574 this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
3575 }
3576 }
3577 }
3578 }
3579
3580 // sort exported atoms by name
3581 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
3582 // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
3583 std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
3584 }
3585
3586
3587 template <typename A>
3588 uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
3589 {
3590 switch ( stab.type ) {
3591 case N_FUN:
3592 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3593 // end of function N_FUN has size
3594 return stab.atom->getSize();
3595 }
3596 else {
3597 // start of function N_FUN has address
3598 return getAtomLoadAddress(stab.atom);
3599 }
3600 case N_LBRAC:
3601 case N_RBRAC:
3602 case N_SLINE:
3603 if ( stab.atom == NULL )
3604 // some weird assembly files have slines not associated with a function
3605 return stab.value;
3606 else
3607 // all these stab types need their value changed from an offset in the atom to an address
3608 return getAtomLoadAddress(stab.atom) + stab.value;
3609 case N_STSYM:
3610 case N_LCSYM:
3611 case N_BNSYM:
3612 // all these need address of atom
3613 return getAtomLoadAddress(stab.atom);;
3614 case N_ENSYM:
3615 return stab.atom->getSize();
3616 case N_SO:
3617 if ( stab.atom == NULL ) {
3618 return 0;
3619 }
3620 else {
3621 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
3622 // end of translation unit N_SO has address of end of last atom
3623 return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
3624 }
3625 else {
3626 // start of translation unit N_SO has address of end of first atom
3627 return getAtomLoadAddress(stab.atom);
3628 }
3629 }
3630 break;
3631 default:
3632 return stab.value;
3633 }
3634 }
3635
3636 template <typename A>
3637 uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
3638 {
3639 switch (stab.type) {
3640 case N_SO:
3641 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
3642 return this->fStringsAtom->emptyString();
3643 break;
3644 }
3645 // fall into uniquing case
3646 case N_SOL:
3647 case N_BINCL:
3648 case N_EXCL:
3649 return this->fStringsAtom->addUnique(stab.string);
3650 break;
3651 default:
3652 if ( stab.string == NULL )
3653 return 0;
3654 else if ( stab.string[0] == '\0' )
3655 return this->fStringsAtom->emptyString();
3656 else
3657 return this->fStringsAtom->add(stab.string);
3658 }
3659 return 0;
3660 }
3661
3662 template <typename A>
3663 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
3664 {
3665 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
3666 if ( stab.type == N_FUN )
3667 return stab.other;
3668 else if ( stab.atom != NULL )
3669 return stab.atom->getSection()->getIndex();
3670 else
3671 return stab.other;
3672 }
3673
3674 template <typename A>
3675 void Writer<A>::addStabs(uint32_t startIndex)
3676 {
3677 macho_nlist<P>* entry = &fSymbolTable[startIndex];
3678 for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
3679 const ObjectFile::Reader::Stab& stab = *it;
3680 entry->set_n_type(stab.type);
3681 entry->set_n_sect(sectionIndexForStab(stab));
3682 entry->set_n_desc(stab.desc);
3683 entry->set_n_value(valueForStab(stab));
3684 entry->set_n_strx(stringOffsetForStab(stab));
3685 }
3686 }
3687
3688
3689
3690 template <typename A>
3691 uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
3692 {
3693 // search imports
3694 int i = 0;
3695 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
3696 if ( &atom == *it )
3697 return i + fSymbolTableImportStartIndex;
3698 ++i;
3699 }
3700
3701 // search locals
3702 i = 0;
3703 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
3704 if ( &atom == *it )
3705 return i + fSymbolTableLocalStartIndex;
3706 ++i;
3707 }
3708
3709 // search exports
3710 i = 0;
3711 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
3712 if ( &atom == *it )
3713 return i + fSymbolTableExportStartIndex;
3714 ++i;
3715 }
3716
3717 throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
3718 }
3719
3720
3721 template <>
3722 bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3723 {
3724 switch ( target.getSymbolTableInclusion() ) {
3725 case ObjectFile::Atom::kSymbolTableNotIn:
3726 return false;
3727 case ObjectFile::Atom::kSymbolTableInAsAbsolute:
3728 case ObjectFile::Atom::kSymbolTableIn:
3729 case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
3730 return true;
3731 };
3732 return false;
3733 }
3734
3735 template <typename A>
3736 bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
3737 {
3738 switch ( target.getDefinitionKind() ) {
3739 case ObjectFile::Atom::kRegularDefinition:
3740 case ObjectFile::Atom::kWeakDefinition:
3741 case ObjectFile::Atom::kAbsoluteSymbol:
3742 return false;
3743 case ObjectFile::Atom::kTentativeDefinition:
3744 if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
3745 return false;
3746 else
3747 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
3748 case ObjectFile::Atom::kExternalDefinition:
3749 case ObjectFile::Atom::kExternalWeakDefinition:
3750 return shouldExport(target);
3751 }
3752 return false;
3753 }
3754
3755 template <typename A>
3756 void Writer<A>::buildFixups()
3757 {
3758 if ( fOptions.outputKind() == Options::kObjectFile ) {
3759 this->buildObjectFileFixups();
3760 }
3761 else {
3762 if ( fOptions.keepRelocations() )
3763 this->buildObjectFileFixups();
3764 this->buildExecutableFixups();
3765 }
3766 }
3767
3768 template <>
3769 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3770 {
3771 ObjectFile::Atom& target = ref->getTarget();
3772 bool external = this->makesExternalRelocatableReference(target);
3773 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
3774 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3775 macho_relocation_info<P> reloc1;
3776 macho_relocation_info<P> reloc2;
3777 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
3778
3779 switch ( kind ) {
3780 case x86_64::kNoFixUp:
3781 case x86_64::kGOTNoFixUp:
3782 case x86_64::kFollowOn:
3783 case x86_64::kGroupSubordinate:
3784 return 0;
3785
3786 case x86_64::kPointer:
3787 case x86_64::kPointerWeakImport:
3788 reloc1.set_r_address(address);
3789 reloc1.set_r_symbolnum(symbolIndex);
3790 reloc1.set_r_pcrel(false);
3791 reloc1.set_r_length(3);
3792 reloc1.set_r_extern(external);
3793 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3794 fSectionRelocs.push_back(reloc1);
3795 return 1;
3796
3797 case x86_64::kPointer32:
3798 reloc1.set_r_address(address);
3799 reloc1.set_r_symbolnum(symbolIndex);
3800 reloc1.set_r_pcrel(false);
3801 reloc1.set_r_length(2);
3802 reloc1.set_r_extern(external);
3803 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3804 fSectionRelocs.push_back(reloc1);
3805 return 1;
3806
3807 case x86_64::kPointerDiff32:
3808 case x86_64::kPointerDiff:
3809 {
3810 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3811 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
3812 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
3813 reloc1.set_r_address(address);
3814 reloc1.set_r_symbolnum(symbolIndex);
3815 reloc1.set_r_pcrel(false);
3816 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
3817 reloc1.set_r_extern(external);
3818 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
3819 reloc2.set_r_address(address);
3820 reloc2.set_r_symbolnum(fromSymbolIndex);
3821 reloc2.set_r_pcrel(false);
3822 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
3823 reloc2.set_r_extern(fromExternal);
3824 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
3825 fSectionRelocs.push_back(reloc1);
3826 fSectionRelocs.push_back(reloc2);
3827 return 2;
3828 }
3829
3830 case x86_64::kBranchPCRel32:
3831 case x86_64::kBranchPCRel32WeakImport:
3832 case x86_64::kDtraceProbeSite:
3833 case x86_64::kDtraceIsEnabledSite:
3834 reloc1.set_r_address(address);
3835 reloc1.set_r_symbolnum(symbolIndex);
3836 reloc1.set_r_pcrel(true);
3837 reloc1.set_r_length(2);
3838 reloc1.set_r_extern(external);
3839 reloc1.set_r_type(X86_64_RELOC_BRANCH);
3840 fSectionRelocs.push_back(reloc1);
3841 return 1;
3842
3843 case x86_64::kPCRel32:
3844 reloc1.set_r_address(address);
3845 reloc1.set_r_symbolnum(symbolIndex);
3846 reloc1.set_r_pcrel(true);
3847 reloc1.set_r_length(2);
3848 reloc1.set_r_extern(external);
3849 reloc1.set_r_type(X86_64_RELOC_SIGNED);
3850 fSectionRelocs.push_back(reloc1);
3851 return 1;
3852
3853 case x86_64::kPCRel32_1:
3854 reloc1.set_r_address(address);
3855 reloc1.set_r_symbolnum(symbolIndex);
3856 reloc1.set_r_pcrel(true);
3857 reloc1.set_r_length(2);
3858 reloc1.set_r_extern(external);
3859 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
3860 fSectionRelocs.push_back(reloc1);
3861 return 1;
3862
3863 case x86_64::kPCRel32_2:
3864 reloc1.set_r_address(address);
3865 reloc1.set_r_symbolnum(symbolIndex);
3866 reloc1.set_r_pcrel(true);
3867 reloc1.set_r_length(2);
3868 reloc1.set_r_extern(external);
3869 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
3870 fSectionRelocs.push_back(reloc1);
3871 return 1;
3872
3873 case x86_64::kPCRel32_4:
3874 reloc1.set_r_address(address);
3875 reloc1.set_r_symbolnum(symbolIndex);
3876 reloc1.set_r_pcrel(true);
3877 reloc1.set_r_length(2);
3878 reloc1.set_r_extern(external);
3879 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
3880 fSectionRelocs.push_back(reloc1);
3881 return 1;
3882
3883 case x86_64::kBranchPCRel8:
3884 reloc1.set_r_address(address);
3885 reloc1.set_r_symbolnum(symbolIndex);
3886 reloc1.set_r_pcrel(true);
3887 reloc1.set_r_length(0);
3888 reloc1.set_r_extern(external);
3889 reloc1.set_r_type(X86_64_RELOC_BRANCH);
3890 fSectionRelocs.push_back(reloc1);
3891 return 1;
3892
3893 case x86_64::kPCRel32GOT:
3894 case x86_64::kPCRel32GOTWeakImport:
3895 reloc1.set_r_address(address);
3896 reloc1.set_r_symbolnum(symbolIndex);
3897 reloc1.set_r_pcrel(true);
3898 reloc1.set_r_length(2);
3899 reloc1.set_r_extern(external);
3900 reloc1.set_r_type(X86_64_RELOC_GOT);
3901 fSectionRelocs.push_back(reloc1);
3902 return 1;
3903
3904 case x86_64::kPCRel32GOTLoad:
3905 case x86_64::kPCRel32GOTLoadWeakImport:
3906 reloc1.set_r_address(address);
3907 reloc1.set_r_symbolnum(symbolIndex);
3908 reloc1.set_r_pcrel(true);
3909 reloc1.set_r_length(2);
3910 reloc1.set_r_extern(external);
3911 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
3912 fSectionRelocs.push_back(reloc1);
3913 return 1;
3914
3915 case x86_64::kPointerDiff24:
3916 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
3917
3918 case x86_64::kImageOffset32:
3919 throw "internal linker error, kImageOffset32 can't be encoded into object files";
3920
3921 case x86_64::kDtraceTypeReference:
3922 case x86_64::kDtraceProbe:
3923 // generates no relocs
3924 return 0;
3925 }
3926 return 0;
3927 }
3928
3929
3930 template <>
3931 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
3932 {
3933 ObjectFile::Atom& target = ref->getTarget();
3934 bool isExtern = this->makesExternalRelocatableReference(target);
3935 uint32_t symbolIndex = 0;
3936 if ( isExtern )
3937 symbolIndex = this->symbolIndex(target);
3938 uint32_t sectionNum = target.getSection()->getIndex();
3939 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
3940 macho_relocation_info<P> reloc1;
3941 macho_relocation_info<P> reloc2;
3942 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
3943 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
3944 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
3945
3946 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
3947 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
3948 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
3949
3950
3951 switch ( kind ) {
3952 case x86::kNoFixUp:
3953 case x86::kFollowOn:
3954 case x86::kGroupSubordinate:
3955 return 0;
3956
3957 case x86::kPointer:
3958 case x86::kPointerWeakImport:
3959 case x86::kAbsolute32:
3960 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
3961 // use scattered reloc is target offset is non-zero
3962 sreloc1->set_r_scattered(true);
3963 sreloc1->set_r_pcrel(false);
3964 sreloc1->set_r_length(2);
3965 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
3966 sreloc1->set_r_address(address);
3967 sreloc1->set_r_value(target.getAddress());
3968 }
3969 else {
3970 reloc1.set_r_address(address);
3971 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
3972 reloc1.set_r_pcrel(false);
3973 reloc1.set_r_length(2);
3974 reloc1.set_r_extern(isExtern);
3975 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3976 }
3977 fSectionRelocs.push_back(reloc1);
3978 return 1;
3979
3980 case x86::kPointerDiff16:
3981 case x86::kPointerDiff:
3982 {
3983 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
3984 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
3985 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
3986 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
3987 sreloc1->set_r_scattered(true);
3988 sreloc1->set_r_pcrel(false);
3989 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
3990 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
3991 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
3992 else
3993 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
3994 sreloc1->set_r_address(address);
3995 sreloc1->set_r_value(target.getAddress());
3996
3997 sreloc2->set_r_scattered(true);
3998 sreloc2->set_r_pcrel(false);
3999 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
4000 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
4001 sreloc2->set_r_address(0);
4002 if ( &ref->getFromTarget() == atom )
4003 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4004 else
4005 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4006 fSectionRelocs.push_back(reloc2);
4007 fSectionRelocs.push_back(reloc1);
4008 return 2;
4009 }
4010
4011 case x86::kPCRel32WeakImport:
4012 case x86::kPCRel32:
4013 case x86::kPCRel16:
4014 case x86::kPCRel8:
4015 case x86::kDtraceProbeSite:
4016 case x86::kDtraceIsEnabledSite:
4017 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4018 // use scattered reloc is target offset is non-zero
4019 sreloc1->set_r_scattered(true);
4020 sreloc1->set_r_pcrel(true);
4021 sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4022 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4023 sreloc1->set_r_address(address);
4024 sreloc1->set_r_value(target.getAddress());
4025 }
4026 else {
4027 reloc1.set_r_address(address);
4028 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4029 reloc1.set_r_pcrel(true);
4030 reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
4031 reloc1.set_r_extern(isExtern);
4032 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4033 }
4034 fSectionRelocs.push_back(reloc1);
4035 return 1;
4036
4037 case x86::kPointerDiff24:
4038 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
4039
4040 case x86::kImageOffset32:
4041 throw "internal linker error, kImageOffset32 can't be encoded into object files";
4042
4043 case x86::kDtraceTypeReference:
4044 case x86::kDtraceProbe:
4045 // generates no relocs
4046 return 0;
4047
4048 }
4049 return 0;
4050 }
4051
4052 template <>
4053 uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4054 {
4055 ObjectFile::Atom& target = ref->getTarget();
4056 bool isExtern = this->makesExternalRelocatableReference(target);
4057 uint32_t symbolIndex = 0;
4058 if ( isExtern )
4059 symbolIndex = this->symbolIndex(target);
4060 uint32_t sectionNum = target.getSection()->getIndex();
4061 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4062 macho_relocation_info<P> reloc1;
4063 macho_relocation_info<P> reloc2;
4064 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4065 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4066 arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
4067
4068 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
4069 warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
4070 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
4071
4072
4073 switch ( kind ) {
4074 case arm::kNoFixUp:
4075 case arm::kFollowOn:
4076 case arm::kGroupSubordinate:
4077 return 0;
4078
4079 case arm::kPointer:
4080 case arm::kReadOnlyPointer:
4081 case arm::kPointerWeakImport:
4082 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4083 // use scattered reloc is target offset is non-zero
4084 sreloc1->set_r_scattered(true);
4085 sreloc1->set_r_pcrel(false);
4086 sreloc1->set_r_length(2);
4087 sreloc1->set_r_type(ARM_RELOC_VANILLA);
4088 sreloc1->set_r_address(address);
4089 sreloc1->set_r_value(target.getAddress());
4090 }
4091 else {
4092 reloc1.set_r_address(address);
4093 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4094 reloc1.set_r_pcrel(false);
4095 reloc1.set_r_length(2);
4096 reloc1.set_r_extern(isExtern);
4097 reloc1.set_r_type(ARM_RELOC_VANILLA);
4098 }
4099 fSectionRelocs.push_back(reloc1);
4100 return 1;
4101
4102 case arm::kPointerDiff:
4103 {
4104 sreloc1->set_r_scattered(true);
4105 sreloc1->set_r_pcrel(false);
4106 sreloc1->set_r_length(2);
4107 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4108 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
4109 else
4110 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
4111 sreloc1->set_r_address(address);
4112 sreloc1->set_r_value(target.getAddress());
4113 sreloc2->set_r_scattered(true);
4114 sreloc2->set_r_pcrel(false);
4115 sreloc2->set_r_length(2);
4116 sreloc2->set_r_type(ARM_RELOC_PAIR);
4117 sreloc2->set_r_address(0);
4118 if ( &ref->getFromTarget() == atom )
4119 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4120 else
4121 sreloc2->set_r_value(ref->getFromTarget().getAddress());
4122 fSectionRelocs.push_back(reloc2);
4123 fSectionRelocs.push_back(reloc1);
4124 return 2;
4125 }
4126
4127 case arm::kBranch24WeakImport:
4128 case arm::kBranch24:
4129 case arm::kDtraceProbeSite:
4130 case arm::kDtraceIsEnabledSite:
4131 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4132 // use scattered reloc is target offset is non-zero
4133 sreloc1->set_r_scattered(true);
4134 sreloc1->set_r_pcrel(true);
4135 sreloc1->set_r_length(2);
4136 sreloc1->set_r_type(ARM_RELOC_BR24);
4137 sreloc1->set_r_address(address);
4138 sreloc1->set_r_value(target.getAddress());
4139 }
4140 else {
4141 reloc1.set_r_address(address);
4142 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4143 reloc1.set_r_pcrel(true);
4144 reloc1.set_r_length(2);
4145 reloc1.set_r_extern(isExtern);
4146 reloc1.set_r_type(ARM_RELOC_BR24);
4147 }
4148 fSectionRelocs.push_back(reloc1);
4149 return 1;
4150
4151 case arm::kThumbBranch22WeakImport:
4152 case arm::kThumbBranch22:
4153 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
4154 // use scattered reloc if target offset is non-zero
4155 sreloc1->set_r_scattered(true);
4156 sreloc1->set_r_pcrel(true);
4157 sreloc1->set_r_length(2);
4158 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
4159 sreloc1->set_r_address(address);
4160 sreloc1->set_r_value(target.getAddress());
4161 }
4162 else {
4163 reloc1.set_r_address(address);
4164 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
4165 reloc1.set_r_pcrel(true);
4166 reloc1.set_r_length(2);
4167 reloc1.set_r_extern(isExtern);
4168 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
4169 }
4170 fSectionRelocs.push_back(reloc1);
4171 return 1;
4172
4173 case arm::kDtraceTypeReference:
4174 case arm::kDtraceProbe:
4175 // generates no relocs
4176 return 0;
4177
4178 }
4179 return 0;
4180 }
4181
4182 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
4183 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4184 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
4185 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
4186 template <> uint64_t Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
4187
4188 template <>
4189 uint8_t Writer<ppc>::getRelocPointerSize()
4190 {
4191 return 2;
4192 }
4193
4194 template <>
4195 uint8_t Writer<ppc64>::getRelocPointerSize()
4196 {
4197 return 3;
4198 }
4199
4200 template <>
4201 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4202 {
4203 return addObjectRelocs_powerpc(atom, ref);
4204 }
4205
4206 template <>
4207 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4208 {
4209 return addObjectRelocs_powerpc(atom, ref);
4210 }
4211
4212 //
4213 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
4214 // they use a common addObjectRelocs_powerpc() method.
4215 //
4216 template <typename A>
4217 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
4218 {
4219 ObjectFile::Atom& target = ref->getTarget();
4220 bool isExtern = this->makesExternalRelocatableReference(target);
4221 uint32_t symbolIndex = 0;
4222 if ( isExtern )
4223 symbolIndex = this->symbolIndex(target);
4224 uint32_t sectionNum = target.getSection()->getIndex();
4225 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
4226 macho_relocation_info<P> reloc1;
4227 macho_relocation_info<P> reloc2;
4228 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
4229 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
4230 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
4231
4232 switch ( kind ) {
4233 case A::kNoFixUp:
4234 case A::kFollowOn:
4235 case A::kGroupSubordinate:
4236 return 0;
4237
4238 case A::kPointer:
4239 case A::kPointerWeakImport:
4240 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
4241 // use scattered reloc is target offset is outside target
4242 sreloc1->set_r_scattered(true);
4243 sreloc1->set_r_pcrel(false);
4244 sreloc1->set_r_length(getRelocPointerSize());
4245 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
4246 sreloc1->set_r_address(address);
4247 sreloc1->set_r_value(target.getAddress());
4248 }
4249 else {
4250 reloc1.set_r_address(address);
4251 if ( isExtern )
4252 reloc1.set_r_symbolnum(symbolIndex);
4253 else
4254 reloc1.set_r_symbolnum(sectionNum);
4255 reloc1.set_r_pcrel(false);
4256 reloc1.set_r_length(getRelocPointerSize());
4257 reloc1.set_r_extern(isExtern);
4258 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4259 }
4260 fSectionRelocs.push_back(reloc1);
4261 return 1;
4262
4263 case A::kPointerDiff16:
4264 case A::kPointerDiff32:
4265 case A::kPointerDiff64:
4266 {
4267 sreloc1->set_r_scattered(true);
4268 sreloc1->set_r_pcrel(false);
4269 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
4270 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
4271 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
4272 else
4273 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
4274 sreloc1->set_r_address(address);
4275 sreloc1->set_r_value(target.getAddress());
4276 sreloc2->set_r_scattered(true);
4277 sreloc2->set_r_pcrel(false);
4278 sreloc2->set_r_length(sreloc1->r_length());
4279 sreloc2->set_r_type(PPC_RELOC_PAIR);
4280 sreloc2->set_r_address(0);
4281 sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
4282 fSectionRelocs.push_back(reloc2);
4283 fSectionRelocs.push_back(reloc1);
4284 return 2;
4285 }
4286
4287 case A::kBranch24WeakImport:
4288 case A::kBranch24:
4289 case A::kDtraceProbeSite:
4290 case A::kDtraceIsEnabledSite:
4291 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4292 reloc1.set_r_address(address);
4293 if ( isExtern )
4294 reloc1.set_r_symbolnum(symbolIndex);
4295 else
4296 reloc1.set_r_symbolnum(sectionNum);
4297 reloc1.set_r_pcrel(true);
4298 reloc1.set_r_length(2);
4299 reloc1.set_r_type(PPC_RELOC_BR24);
4300 reloc1.set_r_extern(isExtern);
4301 }
4302 else {
4303 sreloc1->set_r_scattered(true);
4304 sreloc1->set_r_pcrel(true);
4305 sreloc1->set_r_length(2);
4306 sreloc1->set_r_type(PPC_RELOC_BR24);
4307 sreloc1->set_r_address(address);
4308 sreloc1->set_r_value(target.getAddress());
4309 }
4310 fSectionRelocs.push_back(reloc1);
4311 return 1;
4312
4313 case A::kBranch14:
4314 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4315 reloc1.set_r_address(address);
4316 if ( isExtern )
4317 reloc1.set_r_symbolnum(symbolIndex);
4318 else
4319 reloc1.set_r_symbolnum(sectionNum);
4320 reloc1.set_r_pcrel(true);
4321 reloc1.set_r_length(2);
4322 reloc1.set_r_type(PPC_RELOC_BR14);
4323 reloc1.set_r_extern(isExtern);
4324 }
4325 else {
4326 sreloc1->set_r_scattered(true);
4327 sreloc1->set_r_pcrel(true);
4328 sreloc1->set_r_length(2);
4329 sreloc1->set_r_type(PPC_RELOC_BR14);
4330 sreloc1->set_r_address(address);
4331 sreloc1->set_r_value(target.getAddress());
4332 }
4333 fSectionRelocs.push_back(reloc1);
4334 return 1;
4335
4336 case A::kPICBaseLow16:
4337 case A::kPICBaseLow14:
4338 {
4339 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
4340 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4341 sreloc1->set_r_scattered(true);
4342 sreloc1->set_r_pcrel(false);
4343 sreloc1->set_r_length(2);
4344 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
4345 sreloc1->set_r_address(address);
4346 sreloc1->set_r_value(target.getAddress());
4347 sreloc2->set_r_scattered(true);
4348 sreloc2->set_r_pcrel(false);
4349 sreloc2->set_r_length(2);
4350 sreloc2->set_r_type(PPC_RELOC_PAIR);
4351 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
4352 sreloc2->set_r_value(fromAddr);
4353 fSectionRelocs.push_back(reloc2);
4354 fSectionRelocs.push_back(reloc1);
4355 return 2;
4356 }
4357
4358 case A::kPICBaseHigh16:
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(PPC_RELOC_HA16_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) & 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::kAbsLow14:
4380 case A::kAbsLow16:
4381 {
4382 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4383 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4384 reloc1.set_r_address(address);
4385 if ( isExtern )
4386 reloc1.set_r_symbolnum(symbolIndex);
4387 else
4388 reloc1.set_r_symbolnum(sectionNum);
4389 reloc1.set_r_pcrel(false);
4390 reloc1.set_r_length(2);
4391 reloc1.set_r_extern(isExtern);
4392 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4393 }
4394 else {
4395 sreloc1->set_r_scattered(true);
4396 sreloc1->set_r_pcrel(false);
4397 sreloc1->set_r_length(2);
4398 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4399 sreloc1->set_r_address(address);
4400 sreloc1->set_r_value(target.getAddress());
4401 }
4402 if ( isExtern )
4403 reloc2.set_r_address(ref->getTargetOffset() >> 16);
4404 else
4405 reloc2.set_r_address(toAddr >> 16);
4406 reloc2.set_r_symbolnum(0);
4407 reloc2.set_r_pcrel(false);
4408 reloc2.set_r_length(2);
4409 reloc2.set_r_extern(false);
4410 reloc2.set_r_type(PPC_RELOC_PAIR);
4411 fSectionRelocs.push_back(reloc2);
4412 fSectionRelocs.push_back(reloc1);
4413 return 2;
4414 }
4415
4416 case A::kAbsHigh16:
4417 {
4418 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4419 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4420 reloc1.set_r_address(address);
4421 if ( isExtern )
4422 reloc1.set_r_symbolnum(symbolIndex);
4423 else
4424 reloc1.set_r_symbolnum(sectionNum);
4425 reloc1.set_r_pcrel(false);
4426 reloc1.set_r_length(2);
4427 reloc1.set_r_extern(isExtern);
4428 reloc1.set_r_type(PPC_RELOC_HI16);
4429 }
4430 else {
4431 sreloc1->set_r_scattered(true);
4432 sreloc1->set_r_pcrel(false);
4433 sreloc1->set_r_length(2);
4434 sreloc1->set_r_type(PPC_RELOC_HI16);
4435 sreloc1->set_r_address(address);
4436 sreloc1->set_r_value(target.getAddress());
4437 }
4438 if ( isExtern )
4439 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4440 else
4441 reloc2.set_r_address(toAddr & 0xFFFF);
4442 reloc2.set_r_symbolnum(0);
4443 reloc2.set_r_pcrel(false);
4444 reloc2.set_r_length(2);
4445 reloc2.set_r_extern(false);
4446 reloc2.set_r_type(PPC_RELOC_PAIR);
4447 fSectionRelocs.push_back(reloc2);
4448 fSectionRelocs.push_back(reloc1);
4449 return 2;
4450 }
4451
4452 case A::kAbsHigh16AddLow:
4453 {
4454 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
4455 uint32_t overflow = 0;
4456 if ( (toAddr & 0x00008000) != 0 )
4457 overflow = 0x10000;
4458 if ( (ref->getTargetOffset() == 0) || isExtern ) {
4459 reloc1.set_r_address(address);
4460 if ( isExtern )
4461 reloc1.set_r_symbolnum(symbolIndex);
4462 else
4463 reloc1.set_r_symbolnum(sectionNum);
4464 reloc1.set_r_pcrel(false);
4465 reloc1.set_r_length(2);
4466 reloc1.set_r_extern(isExtern);
4467 reloc1.set_r_type(PPC_RELOC_HA16);
4468 }
4469 else {
4470 sreloc1->set_r_scattered(true);
4471 sreloc1->set_r_pcrel(false);
4472 sreloc1->set_r_length(2);
4473 sreloc1->set_r_type(PPC_RELOC_HA16);
4474 sreloc1->set_r_address(address);
4475 sreloc1->set_r_value(target.getAddress());
4476 }
4477 if ( isExtern )
4478 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
4479 else
4480 reloc2.set_r_address(toAddr & 0xFFFF);
4481 reloc2.set_r_symbolnum(0);
4482 reloc2.set_r_pcrel(false);
4483 reloc2.set_r_length(2);
4484 reloc2.set_r_extern(false);
4485 reloc2.set_r_type(PPC_RELOC_PAIR);
4486 fSectionRelocs.push_back(reloc2);
4487 fSectionRelocs.push_back(reloc1);
4488 return 2;
4489 }
4490
4491 case A::kDtraceTypeReference:
4492 case A::kDtraceProbe:
4493 // generates no relocs
4494 return 0;
4495 }
4496 return 0;
4497 }
4498
4499
4500
4501 //
4502 // There are cases when an entry in the indirect symbol table is the magic value
4503 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
4504 // the content of the corresponding part of the __nl_symbol_pointer section
4505 // must also change.
4506 //
4507 template <typename A>
4508 bool Writer<A>::indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const
4509 {
4510 // cannot use INDIRECT_SYMBOL_LOCAL to tentative definitions in object files
4511 // because tentative defs don't have addresses
4512 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition )
4513 return false;
4514
4515 // must use INDIRECT_SYMBOL_LOCAL if there is an addend
4516 if ( ref->getTargetOffset() != 0 )
4517 return true;
4518
4519 // don't use INDIRECT_SYMBOL_LOCAL for external symbols
4520 return ! this->shouldExport(ref->getTarget());
4521 }
4522
4523
4524 template <typename A>
4525 void Writer<A>::buildObjectFileFixups()
4526 {
4527 uint32_t relocIndex = 0;
4528 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
4529 const int segCount = segmentInfos.size();
4530 for(int i=0; i < segCount; ++i) {
4531 SegmentInfo* curSegment = segmentInfos[i];
4532 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4533 const int sectionCount = sectionInfos.size();
4534 for(int j=0; j < sectionCount; ++j) {
4535 SectionInfo* curSection = sectionInfos[j];
4536 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
4537 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
4538 if ( ! curSection->fAllZeroFill ) {
4539 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4540 || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
4541 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
4542 curSection->fRelocOffset = relocIndex;
4543 const int atomCount = sectionAtoms.size();
4544 for (int k=0; k < atomCount; ++k) {
4545 ObjectFile::Atom* atom = sectionAtoms[k];
4546 //fprintf(stderr, "buildObjectFileFixups(): atom %s has %lu references\n", atom->getDisplayName(), atom->getReferences().size());
4547 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
4548 const int refCount = refs.size();
4549 for (int l=0; l < refCount; ++l) {
4550 ObjectFile::Reference* ref = refs[l];
4551 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
4552 || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
4553 uint32_t offsetInSection = atom->getSectionOffset();
4554 uint32_t indexInSection = offsetInSection / atom->getSize();
4555 uint32_t undefinedSymbolIndex;
4556 if ( curSection->fAllStubs ) {
4557 ObjectFile::Atom& stubTarget =ref->getTarget();
4558 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
4559 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
4560 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
4561 }
4562 else if ( curSection->fAllNonLazyPointers) {
4563 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
4564 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
4565 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4566 else
4567 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
4568 }
4569 else {
4570 // should never get here, fAllLazyPointers not used in generated .o files
4571 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
4572 }
4573 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
4574 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
4575 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
4576 fIndirectTableAtom->fTable.push_back(entry);
4577 if ( curSection->fAllLazyPointers ) {
4578 ObjectFile::Atom& target = ref->getTarget();
4579 ObjectFile::Atom& fromTarget = ref->getFromTarget();
4580 if ( &fromTarget == NULL ) {
4581 warning("lazy pointer %s missing initial binding", atom->getDisplayName());
4582 }
4583 else {
4584 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
4585 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
4586 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
4587 macho_relocation_info<P> reloc1;
4588 reloc1.set_r_address(atom->getSectionOffset());
4589 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
4590 reloc1.set_r_pcrel(false);
4591 reloc1.set_r_length();
4592 reloc1.set_r_extern(isExtern);
4593 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
4594 fSectionRelocs.push_back(reloc1);
4595 ++relocIndex;
4596 }
4597 }
4598 else if ( curSection->fAllStubs ) {
4599 relocIndex += this->addObjectRelocs(atom, ref);
4600 }
4601 }
4602 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
4603 relocIndex += this->addObjectRelocs(atom, ref);
4604 }
4605 }
4606 }
4607 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
4608 }
4609 }
4610 }
4611
4612 // reverse the relocs
4613 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
4614
4615 // now reverse section reloc offsets
4616 for(int i=0; i < segCount; ++i) {
4617 SegmentInfo* curSegment = segmentInfos[i];
4618 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
4619 const int sectionCount = sectionInfos.size();
4620 for(int j=0; j < sectionCount; ++j) {
4621 SectionInfo* curSection = sectionInfos[j];
4622 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
4623 }
4624 }
4625
4626 }
4627
4628
4629 template <>
4630 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
4631 {
4632 uint64_t result;
4633 if ( fOptions.outputKind() == Options::kKextBundle ) {
4634 // for x86_64 kext bundles, the r_address field in relocs
4635 // is the offset from the start address of the first segment
4636 result = address - fSegmentInfos[0]->fBaseAddress;
4637 if ( result > 0xFFFFFFFF ) {
4638 throwf("kext bundle too large: address can't fit in 31-bit r_address field in %s from %s",
4639 atom->getDisplayName(), atom->getFile()->getPath());
4640 }
4641 }
4642 else {
4643 // for x86_64, the r_address field in relocs for final linked images
4644 // is the offset from the start address of the first writable segment
4645 result = address - fFirstWritableSegment->fBaseAddress;
4646 if ( result > 0xFFFFFFFF ) {
4647 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
4648 throwf("text relocs not supported for x86_64 in %s from %s",
4649 atom->getDisplayName(), atom->getFile()->getPath());
4650 else
4651 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
4652 atom->getDisplayName(), atom->getFile()->getPath());
4653 }
4654 }
4655 return result;
4656 }
4657
4658
4659 template <>
4660 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4661 {
4662 switch ( ref.getKind() ) {
4663 case ppc::kAbsLow16:
4664 case ppc::kAbsLow14:
4665 case ppc::kAbsHigh16:
4666 case ppc::kAbsHigh16AddLow:
4667 if ( fSlideable )
4668 return true;
4669 }
4670 return false;
4671 }
4672
4673
4674 template <>
4675 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4676 {
4677 switch ( ref.getKind() ) {
4678 case ppc::kAbsLow16:
4679 case ppc::kAbsLow14:
4680 case ppc::kAbsHigh16:
4681 case ppc::kAbsHigh16AddLow:
4682 if ( fSlideable )
4683 return true;
4684 }
4685 return false;
4686 }
4687
4688 template <>
4689 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4690 {
4691 if ( ref.getKind() == x86::kAbsolute32 ) {
4692 switch ( ref.getTarget().getDefinitionKind() ) {
4693 case ObjectFile::Atom::kTentativeDefinition:
4694 case ObjectFile::Atom::kRegularDefinition:
4695 case ObjectFile::Atom::kWeakDefinition:
4696 // illegal in dylibs/bundles, until we support TEXT relocs
4697 return fSlideable;
4698 case ObjectFile::Atom::kExternalDefinition:
4699 case ObjectFile::Atom::kExternalWeakDefinition:
4700 // illegal until we support TEXT relocs
4701 return true;
4702 case ObjectFile::Atom::kAbsoluteSymbol:
4703 // absolute symbbols only allowed in static executables
4704 return ( fOptions.outputKind() != Options::kStaticExecutable);
4705 }
4706 }
4707 return false;
4708 }
4709
4710 template <>
4711 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4712 {
4713 if ( fOptions.outputKind() == Options::kKextBundle ) {
4714 switch ( ref.getTarget().getDefinitionKind() ) {
4715 case ObjectFile::Atom::kTentativeDefinition:
4716 case ObjectFile::Atom::kRegularDefinition:
4717 case ObjectFile::Atom::kWeakDefinition:
4718 case ObjectFile::Atom::kAbsoluteSymbol:
4719 return false;
4720 case ObjectFile::Atom::kExternalDefinition:
4721 case ObjectFile::Atom::kExternalWeakDefinition:
4722 // true means we need a TEXT relocs
4723 switch ( ref.getKind() ) {
4724 case x86_64::kBranchPCRel32:
4725 case x86_64::kBranchPCRel32WeakImport:
4726 case x86_64::kPCRel32GOTLoad:
4727 case x86_64::kPCRel32GOTLoadWeakImport:
4728 case x86_64::kPCRel32GOT:
4729 case x86_64::kPCRel32GOTWeakImport:
4730 return true;
4731 }
4732 break;
4733 }
4734 }
4735 return false;
4736 }
4737
4738 template <>
4739 bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
4740 {
4741 switch ( fOptions.outputKind()) {
4742 case Options::kStaticExecutable:
4743 case Options::kPreload:
4744 // all relocations allowed in static executables
4745 return false;
4746 default:
4747 break;
4748 }
4749 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4750 switch ( ref.getTarget().getDefinitionKind() ) {
4751 case ObjectFile::Atom::kTentativeDefinition:
4752 case ObjectFile::Atom::kRegularDefinition:
4753 case ObjectFile::Atom::kWeakDefinition:
4754 // illegal in dylibs/bundles, until we support TEXT relocs
4755 return fSlideable;
4756 case ObjectFile::Atom::kExternalDefinition:
4757 case ObjectFile::Atom::kExternalWeakDefinition:
4758 // illegal until we support TEXT relocs
4759 return true;
4760 case ObjectFile::Atom::kAbsoluteSymbol:
4761 // absolute symbbols only allowed in static executables
4762 return true;
4763 }
4764 }
4765 return false;
4766 }
4767
4768 template <>
4769 bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4770 {
4771 if ( ref.getKind() == x86::kAbsolute32 ) {
4772 switch ( ref.getTarget().getDefinitionKind() ) {
4773 case ObjectFile::Atom::kTentativeDefinition:
4774 case ObjectFile::Atom::kRegularDefinition:
4775 case ObjectFile::Atom::kWeakDefinition:
4776 // a reference to the absolute address of something in this same linkage unit can be
4777 // encoded as a local text reloc in a dylib or bundle
4778 if ( fSlideable ) {
4779 macho_relocation_info<P> reloc;
4780 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4781 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4782 reloc.set_r_symbolnum(sectInfo->getIndex());
4783 reloc.set_r_pcrel(false);
4784 reloc.set_r_length();
4785 reloc.set_r_extern(false);
4786 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4787 fInternalRelocs.push_back(reloc);
4788 atomSection->fHasTextLocalRelocs = true;
4789 if ( fOptions.makeCompressedDyldInfo() ) {
4790 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
4791 }
4792 return true;
4793 }
4794 return false;
4795 case ObjectFile::Atom::kExternalDefinition:
4796 case ObjectFile::Atom::kExternalWeakDefinition:
4797 case ObjectFile::Atom::kAbsoluteSymbol:
4798 return false;
4799 }
4800 }
4801 return false;
4802 }
4803
4804 template <>
4805 bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4806 {
4807 macho_relocation_info<P> reloc1;
4808 macho_relocation_info<P> reloc2;
4809 switch ( ref.getTarget().getDefinitionKind() ) {
4810 case ObjectFile::Atom::kTentativeDefinition:
4811 case ObjectFile::Atom::kRegularDefinition:
4812 case ObjectFile::Atom::kWeakDefinition:
4813 switch ( ref.getKind() ) {
4814 case ppc::kAbsLow16:
4815 case ppc::kAbsLow14:
4816 // a reference to the absolute address of something in this same linkage unit can be
4817 // encoded as a local text reloc in a dylib or bundle
4818 if ( fSlideable ) {
4819 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4820 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
4821 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4822 reloc1.set_r_symbolnum(sectInfo->getIndex());
4823 reloc1.set_r_pcrel(false);
4824 reloc1.set_r_length(2);
4825 reloc1.set_r_extern(false);
4826 reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
4827 reloc2.set_r_address(targetAddr >> 16);
4828 reloc2.set_r_symbolnum(0);
4829 reloc2.set_r_pcrel(false);
4830 reloc2.set_r_length(2);
4831 reloc2.set_r_extern(false);
4832 reloc2.set_r_type(PPC_RELOC_PAIR);
4833 fInternalRelocs.push_back(reloc1);
4834 fInternalRelocs.push_back(reloc2);
4835 atomSection->fHasTextLocalRelocs = true;
4836 return true;
4837 }
4838 break;
4839 case ppc::kAbsHigh16:
4840 case ppc::kAbsHigh16AddLow:
4841 if ( fSlideable ) {
4842 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4843 uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
4844 reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4845 reloc1.set_r_symbolnum(sectInfo->getIndex());
4846 reloc1.set_r_pcrel(false);
4847 reloc1.set_r_length(2);
4848 reloc1.set_r_extern(false);
4849 reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
4850 reloc2.set_r_address(targetAddr & 0xFFFF);
4851 reloc2.set_r_symbolnum(0);
4852 reloc2.set_r_pcrel(false);
4853 reloc2.set_r_length(2);
4854 reloc2.set_r_extern(false);
4855 reloc2.set_r_type(PPC_RELOC_PAIR);
4856 fInternalRelocs.push_back(reloc1);
4857 fInternalRelocs.push_back(reloc2);
4858 atomSection->fHasTextLocalRelocs = true;
4859 return true;
4860 }
4861 }
4862 break;
4863 case ObjectFile::Atom::kExternalDefinition:
4864 case ObjectFile::Atom::kExternalWeakDefinition:
4865 case ObjectFile::Atom::kAbsoluteSymbol:
4866 return false;
4867 }
4868 return false;
4869 }
4870
4871 template <>
4872 bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4873 {
4874 if ( ref.getKind() == arm::kReadOnlyPointer ) {
4875 switch ( ref.getTarget().getDefinitionKind() ) {
4876 case ObjectFile::Atom::kTentativeDefinition:
4877 case ObjectFile::Atom::kRegularDefinition:
4878 case ObjectFile::Atom::kWeakDefinition:
4879 // a reference to the absolute address of something in this same linkage unit can be
4880 // encoded as a local text reloc in a dylib or bundle
4881 if ( fSlideable ) {
4882 macho_relocation_info<P> reloc;
4883 SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
4884 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4885 reloc.set_r_symbolnum(sectInfo->getIndex());
4886 reloc.set_r_pcrel(false);
4887 reloc.set_r_length();
4888 reloc.set_r_extern(false);
4889 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4890 fInternalRelocs.push_back(reloc);
4891 atomSection->fHasTextLocalRelocs = true;
4892 return true;
4893 }
4894 return false;
4895 case ObjectFile::Atom::kExternalDefinition:
4896 case ObjectFile::Atom::kExternalWeakDefinition:
4897 case ObjectFile::Atom::kAbsoluteSymbol:
4898 return false;
4899 }
4900 }
4901 return false;
4902 }
4903
4904
4905 template <>
4906 bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
4907 {
4908 // text relocs not supported (usually never needed because of RIP addressing)
4909 return false;
4910 }
4911
4912 template <>
4913 bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
4914 {
4915 // text relocs not supported
4916 return false;
4917 }
4918
4919 template <>
4920 bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4921 {
4922 if ( ref.getKind() == x86::kAbsolute32 ) {
4923 macho_relocation_info<P> reloc;
4924 switch ( ref.getTarget().getDefinitionKind() ) {
4925 case ObjectFile::Atom::kTentativeDefinition:
4926 case ObjectFile::Atom::kRegularDefinition:
4927 case ObjectFile::Atom::kWeakDefinition:
4928 return false;
4929 case ObjectFile::Atom::kExternalDefinition:
4930 case ObjectFile::Atom::kExternalWeakDefinition:
4931 // a reference to the absolute address of something in another linkage unit can be
4932 // encoded as an external text reloc in a dylib or bundle
4933 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4934 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4935 reloc.set_r_pcrel(false);
4936 reloc.set_r_length();
4937 reloc.set_r_extern(true);
4938 reloc.set_r_type(GENERIC_RELOC_VANILLA);
4939 fExternalRelocs.push_back(reloc);
4940 atomSection->fHasTextExternalRelocs = true;
4941 return true;
4942 case ObjectFile::Atom::kAbsoluteSymbol:
4943 return false;
4944 }
4945 }
4946 return false;
4947 }
4948
4949 template <>
4950 bool Writer<x86_64>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
4951 {
4952 if ( fOptions.outputKind() == Options::kKextBundle ) {
4953 macho_relocation_info<P> reloc;
4954 switch ( ref.getTarget().getDefinitionKind() ) {
4955 case ObjectFile::Atom::kTentativeDefinition:
4956 case ObjectFile::Atom::kRegularDefinition:
4957 case ObjectFile::Atom::kWeakDefinition:
4958 case ObjectFile::Atom::kAbsoluteSymbol:
4959 return false;
4960 case ObjectFile::Atom::kExternalDefinition:
4961 case ObjectFile::Atom::kExternalWeakDefinition:
4962 switch ( ref.getKind() ) {
4963 case x86_64::kBranchPCRel32:
4964 case x86_64::kBranchPCRel32WeakImport:
4965 // a branch to something in another linkage unit is
4966 // encoded as an external text reloc in a kext bundle
4967 reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
4968 reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
4969 reloc.set_r_pcrel(true);
4970 reloc.set_r_length(2);
4971 reloc.set_r_extern(true);
4972 reloc.set_r_type(X86_64_RELOC_BRANCH);
4973 fExternalRelocs.push_back(reloc);
4974 atomSection->fHasTextExternalRelocs = true;
4975 return true;
4976 case x86_64::kPCRel32GOTLoad:
4977 case x86_64::kPCRel32GOTLoadWeakImport:
4978 // a load of the GOT entry for a symbol 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_GOT_LOAD);
4986 fExternalRelocs.push_back(reloc);
4987 atomSection->fHasTextExternalRelocs = true;
4988 return true;
4989 case x86_64::kPCRel32GOT:
4990 case x86_64::kPCRel32GOTWeakImport:
4991 // a use 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);
4999 fExternalRelocs.push_back(reloc);
5000 atomSection->fHasTextExternalRelocs = true;
5001 return true;
5002 }
5003 break;
5004 }
5005 }
5006 return false;
5007 }
5008
5009
5010 template <typename A>
5011 bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
5012 {
5013 return false;
5014 }
5015
5016
5017
5018
5019 template <typename A>
5020 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
5021 {
5022 switch ( target.getDefinitionKind() ) {
5023 case ObjectFile::Atom::kTentativeDefinition:
5024 case ObjectFile::Atom::kRegularDefinition:
5025 // in main executables, the only way regular symbols are indirected is if -interposable is used
5026 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
5027 if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
5028 return kRelocExternal;
5029 else if ( fSlideable )
5030 return kRelocInternal;
5031 else
5032 return kRelocNone;
5033 }
5034 // for flat-namespace or interposable two-level-namespace
5035 // all references to exported symbols get indirected
5036 else if ( this->shouldExport(target) &&
5037 ((fOptions.nameSpace() == Options::kFlatNameSpace)
5038 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
5039 || fOptions.interposable(target.getName()))
5040 && (target.getName() != NULL)
5041 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
5042 return kRelocExternal;
5043 else if ( fSlideable )
5044 return kRelocInternal;
5045 else
5046 return kRelocNone;
5047 case ObjectFile::Atom::kWeakDefinition:
5048 // all calls to global weak definitions get indirected
5049 if ( this->shouldExport(target) )
5050 return kRelocExternal;
5051 else if ( fSlideable )
5052 return kRelocInternal;
5053 else
5054 return kRelocNone;
5055 case ObjectFile::Atom::kExternalDefinition:
5056 case ObjectFile::Atom::kExternalWeakDefinition:
5057 return kRelocExternal;
5058 case ObjectFile::Atom::kAbsoluteSymbol:
5059 return kRelocNone;
5060 }
5061 return kRelocNone;
5062 }
5063
5064 template <typename A>
5065 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5066 {
5067 // for 32-bit architectures, the r_address field in relocs
5068 // for final linked images is the offset from the first segment
5069 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
5070 if ( fOptions.outputKind() == Options::kPreload ) {
5071 // kPreload uses a virtual __HEADER segment to cover the load commands
5072 result = address - fSegmentInfos[1]->fBaseAddress;
5073 }
5074 // or the offset from the first writable segment if built split-seg
5075 if ( fOptions.splitSeg() )
5076 result = address - fFirstWritableSegment->fBaseAddress;
5077 if ( result > 0x7FFFFFFF ) {
5078 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
5079 atom->getDisplayName(), atom->getFile()->getPath());
5080 }
5081 return result;
5082 }
5083
5084 template <>
5085 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
5086 {
5087 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
5088 // the 10.5 dyld, iterprets the r_address as:
5089 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
5090 // 2) an offset from the base address of the first writable segment
5091 // For dyld, r_address is always the offset from the base address
5092 uint64_t result;
5093 bool badFor10_4 = false;
5094 if ( fWritableSegmentPastFirst4GB ) {
5095 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
5096 badFor10_4 = true;
5097 result = address - fFirstWritableSegment->fBaseAddress;
5098 if ( result > 0xFFFFFFFF ) {
5099 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
5100 atom->getDisplayName(), atom->getFile()->getPath());
5101 }
5102 }
5103 else {
5104 result = address - fSegmentInfos[0]->fBaseAddress;
5105 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
5106 badFor10_4 = true;
5107 }
5108 if ( badFor10_4 ) {
5109 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",
5110 atom->getDisplayName(), atom->getFile()->getPath());
5111 }
5112 return result;
5113 }
5114
5115
5116 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
5117 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5118 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
5119 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
5120 template <> bool Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
5121
5122 template <typename A>
5123 void Writer<A>::buildExecutableFixups()
5124 {
5125 if ( fIndirectTableAtom != NULL )
5126 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
5127 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
5128 const int segCount = segmentInfos.size();
5129 for(int i=0; i < segCount; ++i) {
5130 SegmentInfo* curSegment = segmentInfos[i];
5131 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5132 const int sectionCount = sectionInfos.size();
5133 for(int j=0; j < sectionCount; ++j) {
5134 SectionInfo* curSection = sectionInfos[j];
5135 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
5136 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5137 if ( ! curSection->fAllZeroFill ) {
5138 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers
5139 || curSection->fAllStubs || curSection->fAllSelfModifyingStubs ) {
5140 if ( fIndirectTableAtom != NULL )
5141 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
5142 }
5143 const int atomCount = sectionAtoms.size();
5144 for (int k=0; k < atomCount; ++k) {
5145 ObjectFile::Atom* atom = sectionAtoms[k];
5146 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
5147 const int refCount = refs.size();
5148 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
5149 if ( curSection->fAllNonLazyPointers && (refCount == 0) ) {
5150 // handle imageloadercache GOT slot
5151 uint32_t offsetInSection = atom->getSectionOffset();
5152 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5153 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5154 // use INDIRECT_SYMBOL_ABS so 10.5 dyld will leave value as zero
5155 IndirectEntry entry = { indirectTableIndex, INDIRECT_SYMBOL_ABS };
5156 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5157 // indirectTableIndex, INDIRECT_SYMBOL_LOCAL, curSection->fSectionName);
5158 fIndirectTableAtom->fTable.push_back(entry);
5159 }
5160 for (int l=0; l < refCount; ++l) {
5161 ObjectFile::Reference* ref = refs[l];
5162 if ( (fOptions.outputKind() != Options::kKextBundle) &&
5163 (curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers) ) {
5164 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
5165 if ( atom->getSize() != sizeof(pint_t) ) {
5166 warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
5167 }
5168 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
5169 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5170 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
5171 }
5172 uint32_t offsetInSection = atom->getSectionOffset();
5173 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
5174 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
5175 if (atom == fFastStubGOTAtom)
5176 undefinedSymbolIndex = INDIRECT_SYMBOL_ABS;
5177 else if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
5178 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
5179 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5180 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5181 //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n",
5182 // indirectTableIndex, undefinedSymbolIndex, curSection->fSectionName);
5183 fIndirectTableAtom->fTable.push_back(entry);
5184 if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
5185 uint8_t preboundLazyType;
5186 if ( fOptions.prebind() && (fDyldClassicHelperAtom != NULL)
5187 && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
5188 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
5189 macho_scattered_relocation_info<P> pblaReloc;
5190 pblaReloc.set_r_scattered(true);
5191 pblaReloc.set_r_pcrel(false);
5192 pblaReloc.set_r_length();
5193 pblaReloc.set_r_type(preboundLazyType);
5194 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5195 pblaReloc.set_r_value(fDyldClassicHelperAtom->getAddress());
5196 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
5197 }
5198 else if ( fSlideable ) {
5199 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
5200 macho_relocation_info<P> dyldHelperReloc;
5201 uint32_t sectionNum = 1;
5202 if ( fDyldClassicHelperAtom != NULL )
5203 sectionNum = ((SectionInfo*)(fDyldClassicHelperAtom->getSection()))->getIndex();
5204 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
5205 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
5206 dyldHelperReloc.set_r_symbolnum(sectionNum);
5207 dyldHelperReloc.set_r_pcrel(false);
5208 dyldHelperReloc.set_r_length();
5209 dyldHelperReloc.set_r_extern(false);
5210 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
5211 fInternalRelocs.push_back(dyldHelperReloc);
5212 if ( fOptions.makeCompressedDyldInfo() ) {
5213 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5214 }
5215 }
5216 if ( fOptions.makeCompressedDyldInfo() ) {
5217 uint8_t type = BIND_TYPE_POINTER;
5218 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5219 if ( pointerTarget->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
5220 // This is a referece to a weak def in some dylib (e.g. operator new)
5221 // need to bind into to directly bind this
5222 // later weak binding info may override
5223 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5224 fBindingInfo.push_back(BindingInfo(type, ordinal, pointerTarget->getName(), false, addresss, 0));
5225 }
5226 if ( targetRequiresWeakBinding(*pointerTarget) ) {
5227 // note: lazy pointers to weak symbols are not bound lazily
5228 fWeakBindingInfo.push_back(BindingInfo(type, pointerTarget->getName(), false, addresss, 0));
5229 }
5230 }
5231 }
5232 if ( curSection->fAllNonLazyPointers && fOptions.makeCompressedDyldInfo() ) {
5233 if ( pointerTarget != NULL ) {
5234 switch ( this->relocationNeededInFinalLinkedImage(*pointerTarget) ) {
5235 case kRelocNone:
5236 // no rebase or binding info needed
5237 break;
5238 case kRelocInternal:
5239 // a non-lazy pointer that has been optimized to LOCAL needs rebasing info
5240 // but not the magic fFastStubGOTAtom atom
5241 if (atom != fFastStubGOTAtom)
5242 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5243 break;
5244 case kRelocExternal:
5245 {
5246 uint8_t type = BIND_TYPE_POINTER;
5247 uint64_t addresss = atom->getAddress();
5248 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5249 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, 0));
5250 // if this is a non-lazy pointer to a weak definition with this linkage unit
5251 // the pointer needs to initially point within linkage unit and have
5252 // rease command to slide it.
5253 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
5254 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
5255 }
5256 else {
5257 int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
5258 bool weak_import = fWeakImportMap[pointerTarget];
5259 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, 0));
5260 }
5261 }
5262 }
5263 }
5264 }
5265 }
5266 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
5267 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
5268 if ( fOptions.allowTextRelocs() ) {
5269 if ( fOptions.warnAboutTextRelocs() )
5270 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5271 }
5272 else {
5273 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
5274 atom->getDisplayName(), atom->getFile()->getPath());
5275 }
5276 }
5277 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
5278 case kRelocNone:
5279 // no reloc needed
5280 break;
5281 case kRelocInternal:
5282 {
5283 macho_relocation_info<P> internalReloc;
5284 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
5285 uint32_t sectionNum = sectInfo->getIndex();
5286 // special case _mh_dylib_header and friends which are not in any real section
5287 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
5288 sectionNum = 1;
5289 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5290 internalReloc.set_r_symbolnum(sectionNum);
5291 internalReloc.set_r_pcrel(false);
5292 internalReloc.set_r_length();
5293 internalReloc.set_r_extern(false);
5294 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5295 fInternalRelocs.push_back(internalReloc);
5296 if ( fOptions.makeCompressedDyldInfo() ) {
5297 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, atom->getAddress() + ref->getFixUpOffset()));
5298 }
5299 }
5300 break;
5301 case kRelocExternal:
5302 {
5303 macho_relocation_info<P> externalReloc;
5304 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
5305 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
5306 externalReloc.set_r_pcrel(false);
5307 externalReloc.set_r_length();
5308 externalReloc.set_r_extern(true);
5309 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
5310 fExternalRelocs.push_back(externalReloc);
5311 if ( fOptions.makeCompressedDyldInfo() ) {
5312 int64_t addend = ref->getTargetOffset();
5313 uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
5314 if ( !fOptions.makeClassicDyldInfo() ) {
5315 if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
5316 // pointers to internal weak defs need a rebase
5317 fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, addresss));
5318 }
5319 }
5320 uint8_t type = BIND_TYPE_POINTER;
5321 if ( targetRequiresWeakBinding(ref->getTarget()) ) {
5322 fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, addend));
5323 }
5324 else {
5325 int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
5326 bool weak_import = fWeakImportMap[&(ref->getTarget())];
5327 fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, addend));
5328 }
5329 }
5330 }
5331 break;
5332 }
5333 }
5334 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
5335 // new x86 stubs always require text relocs
5336 if ( curSection->fAllStubs || curSection->fAllStubHelpers ) {
5337 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5338 // relocs added to fInternalRelocs
5339 }
5340 }
5341 else if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
5342 if ( fOptions.warnAboutTextRelocs() )
5343 warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
5344 if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
5345 // relocs added to fInternalRelocs
5346 }
5347 else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
5348 // relocs added to fExternalRelocs
5349 }
5350 else {
5351 throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
5352 }
5353 }
5354 else {
5355 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
5356 "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
5357 }
5358 }
5359 }
5360 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
5361 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
5362 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
5363 uint32_t offsetInSection = atom->getSectionOffset();
5364 uint32_t indexInSection = offsetInSection / atom->getSize();
5365 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
5366 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
5367 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
5368 fIndirectTableAtom->fTable.push_back(entry);
5369 }
5370 }
5371 }
5372 }
5373 }
5374 if ( fSplitCodeToDataContentAtom != NULL )
5375 fSplitCodeToDataContentAtom->encode();
5376 if ( fCompressedRebaseInfoAtom != NULL )
5377 fCompressedRebaseInfoAtom->encode();
5378 if ( fCompressedBindingInfoAtom != NULL )
5379 fCompressedBindingInfoAtom->encode();
5380 if ( fCompressedWeakBindingInfoAtom != NULL )
5381 fCompressedWeakBindingInfoAtom->encode();
5382 if ( fCompressedLazyBindingInfoAtom != NULL )
5383 fCompressedLazyBindingInfoAtom->encode();
5384 if ( fCompressedExportInfoAtom != NULL )
5385 fCompressedExportInfoAtom->encode();
5386 }
5387
5388
5389 template <>
5390 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5391 {
5392 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
5393 case ppc::kPICBaseHigh16:
5394 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5395 break;
5396 case ppc::kPointerDiff32:
5397 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5398 break;
5399 case ppc::kPointerDiff64:
5400 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5401 break;
5402 case ppc::kNoFixUp:
5403 case ppc::kGroupSubordinate:
5404 case ppc::kPointer:
5405 case ppc::kPointerWeakImport:
5406 case ppc::kPICBaseLow16:
5407 case ppc::kPICBaseLow14:
5408 // ignore
5409 break;
5410 default:
5411 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5412 fSplitCodeToDataContentAtom->setCantEncode();
5413 }
5414 }
5415
5416 template <>
5417 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5418 {
5419 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
5420 case ppc64::kPICBaseHigh16:
5421 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
5422 break;
5423 case ppc64::kPointerDiff32:
5424 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5425 break;
5426 case ppc64::kPointerDiff64:
5427 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5428 break;
5429 case ppc64::kNoFixUp:
5430 case ppc64::kGroupSubordinate:
5431 case ppc64::kPointer:
5432 case ppc64::kPointerWeakImport:
5433 case ppc64::kPICBaseLow16:
5434 case ppc64::kPICBaseLow14:
5435 // ignore
5436 break;
5437 default:
5438 warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
5439 fSplitCodeToDataContentAtom->setCantEncode();
5440 }
5441 }
5442
5443 template <>
5444 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5445 {
5446 switch ( (x86::ReferenceKinds)ref->getKind() ) {
5447 case x86::kPointerDiff:
5448 case x86::kImageOffset32:
5449 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
5450 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5451 else
5452 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5453 break;
5454 case x86::kNoFixUp:
5455 case x86::kGroupSubordinate:
5456 case x86::kPointer:
5457 case x86::kPointerWeakImport:
5458 // ignore
5459 break;
5460 case x86::kPCRel32:
5461 case x86::kPCRel32WeakImport:
5462 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
5463 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
5464 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
5465 break;
5466 }
5467 // fall into warning case
5468 default:
5469 if ( fOptions.makeCompressedDyldInfo() && (ref->getKind() == x86::kAbsolute32) ) {
5470 // will be encoded in rebase info
5471 }
5472 else {
5473 warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
5474 fSplitCodeToDataContentAtom->setCantEncode();
5475 }
5476 }
5477 }
5478
5479 template <>
5480 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5481 {
5482 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
5483 case x86_64::kPCRel32:
5484 case x86_64::kPCRel32_1:
5485 case x86_64::kPCRel32_2:
5486 case x86_64::kPCRel32_4:
5487 case x86_64::kPCRel32GOTLoad:
5488 case x86_64::kPCRel32GOTLoadWeakImport:
5489 case x86_64::kPCRel32GOT:
5490 case x86_64::kPCRel32GOTWeakImport:
5491 case x86_64::kPointerDiff32:
5492 case x86_64::kImageOffset32:
5493 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5494 break;
5495 case x86_64::kPointerDiff:
5496 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
5497 break;
5498 case x86_64::kNoFixUp:
5499 case x86_64::kGroupSubordinate:
5500 case x86_64::kPointer:
5501 case x86_64::kGOTNoFixUp:
5502 // ignore
5503 break;
5504 default:
5505 warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
5506 fSplitCodeToDataContentAtom->setCantEncode();
5507 }
5508 }
5509
5510 template <>
5511 void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
5512 {
5513 switch ( (arm::ReferenceKinds)ref->getKind() ) {
5514 case arm::kPointerDiff:
5515 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
5516 break;
5517 case arm::kNoFixUp:
5518 case arm::kGroupSubordinate:
5519 case arm::kPointer:
5520 case arm::kPointerWeakImport:
5521 case arm::kReadOnlyPointer:
5522 // ignore
5523 break;
5524 default:
5525 warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
5526 fSplitCodeToDataContentAtom->setCantEncode();
5527 }
5528 }
5529
5530 template <typename A>
5531 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
5532 {
5533 switch ( to.getDefinitionKind() ) {
5534 case ObjectFile::Atom::kExternalDefinition:
5535 case ObjectFile::Atom::kExternalWeakDefinition:
5536 case ObjectFile::Atom::kAbsoluteSymbol:
5537 return false;
5538 case ObjectFile::Atom::kRegularDefinition:
5539 case ObjectFile::Atom::kWeakDefinition:
5540 case ObjectFile::Atom::kTentativeDefinition:
5541 // segments with same permissions slide together
5542 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
5543 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
5544 }
5545 throw "ld64 internal error";
5546 }
5547
5548
5549 template <>
5550 void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
5551 {
5552 uint32_t ppcNop;
5553 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5554 for (uint32_t p=from; p < to; p += 4)
5555 ::pwrite(fd, &ppcNop, 4, p);
5556 }
5557
5558 template <>
5559 void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5560 {
5561 uint32_t ppcNop;
5562 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
5563 for (uint32_t p=from; p < to; p += 4)
5564 ::pwrite(fd, &ppcNop, 4, p);
5565 }
5566
5567 template <>
5568 void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
5569 {
5570 uint8_t x86Nop = 0x90;
5571 for (uint32_t p=from; p < to; ++p)
5572 ::pwrite(fd, &x86Nop, 1, p);
5573 }
5574
5575 template <>
5576 void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
5577 {
5578 uint8_t x86Nop = 0x90;
5579 for (uint32_t p=from; p < to; ++p)
5580 ::pwrite(fd, &x86Nop, 1, p);
5581 }
5582
5583 template <>
5584 void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
5585 {
5586 // FIXME: need thumb nop?
5587 uint32_t armNop;
5588 OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
5589 for (uint32_t p=from; p < to; p += 4)
5590 ::pwrite(fd, &armNop, 4, p);
5591 }
5592
5593 template <>
5594 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
5595 {
5596 for (uint8_t* p=from; p < to; p += 4)
5597 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5598 }
5599
5600 template <>
5601 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
5602 {
5603 for (uint8_t* p=from; p < to; p += 4)
5604 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
5605 }
5606
5607 template <>
5608 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
5609 {
5610 for (uint8_t* p=from; p < to; ++p)
5611 *p = 0x90;
5612 }
5613
5614 template <>
5615 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
5616 {
5617 for (uint8_t* p=from; p < to; ++p)
5618 *p = 0x90;
5619 }
5620
5621 template <>
5622 void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
5623 {
5624 // fixme: need thumb nop?
5625 for (uint8_t* p=from; p < to; p += 4)
5626 OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
5627 }
5628
5629 static const char* stringName(const char* str)
5630 {
5631 if ( strncmp(str, "cstring=", 8) == 0) {
5632 static char buffer[1024];
5633 char* t = buffer;
5634 *t++ = '\"';
5635 for(const char*s = &str[8]; *s != '\0'; ++s) {
5636 switch(*s) {
5637 case '\n':
5638 *t++ = '\\';
5639 *t++ = 'n';
5640 break;
5641 case '\t':
5642 *t++ = '\\';
5643 *t++ = 't';
5644 break;
5645 default:
5646 *t++ = *s;
5647 break;
5648 }
5649 if ( t > &buffer[1020] ) {
5650 *t++= '\"';
5651 *t++= '.';
5652 *t++= '.';
5653 *t++= '.';
5654 *t++= '\0';
5655 return buffer;
5656 }
5657 }
5658 *t++= '\"';
5659 *t++= '\0';
5660 return buffer;
5661 }
5662 else {
5663 return str;
5664 }
5665 }
5666
5667
5668 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
5669 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
5670 template <> const char* Writer<x86>::getArchString() { return "i386"; }
5671 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
5672 template <> const char* Writer<arm>::getArchString() { return "arm"; }
5673
5674 template <typename A>
5675 void Writer<A>::writeMap()
5676 {
5677 if ( fOptions.generatedMapPath() != NULL ) {
5678 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
5679 if ( mapFile != NULL ) {
5680 // write output path
5681 fprintf(mapFile, "# Path: %s\n", fFilePath);
5682 // write output architecure
5683 fprintf(mapFile, "# Arch: %s\n", getArchString());
5684 // write UUID
5685 if ( fUUIDAtom != NULL ) {
5686 const uint8_t* uuid = fUUIDAtom->getUUID();
5687 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
5688 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
5689 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
5690 }
5691 // write table of object files
5692 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
5693 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
5694 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
5695 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5696 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5697 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5698 if ( ! (*secit)->fVirtualSection ) {
5699 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5700 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5701 ObjectFile::Reader* reader = (*ait)->getFile();
5702 uint32_t readerOrdinal = (*ait)->getOrdinal();
5703 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
5704 if ( pos == readerToOrdinal.end() ) {
5705 readerToOrdinal[reader] = readerOrdinal;
5706 ordinalToReader[readerOrdinal] = reader;
5707 }
5708 }
5709 }
5710 }
5711 }
5712 fprintf(mapFile, "# Object files:\n");
5713 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
5714 uint32_t fileIndex = 0;
5715 readerToFileOrdinal[this] = fileIndex++;
5716 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
5717 if ( it->first != 0 ) {
5718 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
5719 readerToFileOrdinal[it->second] = fileIndex++;
5720 }
5721 }
5722 // write table of sections
5723 fprintf(mapFile, "# Sections:\n");
5724 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
5725 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5726 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5727 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5728 if ( ! (*secit)->fVirtualSection ) {
5729 SectionInfo* sect = *secit;
5730 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
5731 (*segit)->fName, sect->fSectionName);
5732 }
5733 }
5734 }
5735 // write table of symbols
5736 fprintf(mapFile, "# Symbols:\n");
5737 fprintf(mapFile, "# Address\tSize \tFile Name\n");
5738 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5739 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
5740 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5741 if ( ! (*secit)->fVirtualSection ) {
5742 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
5743 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
5744 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5745 ObjectFile::Atom* atom = *ait;
5746 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
5747 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
5748 }
5749 }
5750 }
5751 }
5752 fclose(mapFile);
5753 }
5754 else {
5755 warning("could not write map file: %s\n", fOptions.generatedMapPath());
5756 }
5757 }
5758 }
5759
5760 static const char* sCleanupFile = NULL;
5761 static void cleanup(int sig)
5762 {
5763 ::signal(sig, SIG_DFL);
5764 if ( sCleanupFile != NULL ) {
5765 ::unlink(sCleanupFile);
5766 }
5767 if ( sig == SIGINT )
5768 ::exit(1);
5769 }
5770
5771
5772 template <typename A>
5773 uint64_t Writer<A>::writeAtoms()
5774 {
5775 // for UNIX conformance, error if file exists and is not writable
5776 if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
5777 throwf("can't write output file: %s", fFilePath);
5778
5779 int permissions = 0777;
5780 if ( fOptions.outputKind() == Options::kObjectFile )
5781 permissions = 0666;
5782 // Calling unlink first assures the file is gone so that open creates it with correct permissions
5783 // It also handles the case where fFilePath file is not writable but its directory is
5784 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
5785 (void)unlink(fFilePath);
5786
5787 // try to allocate buffer for entire output file content
5788 int fd = -1;
5789 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
5790 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
5791 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
5792 uint8_t* atomBuffer = NULL;
5793 bool streaming = false;
5794 if ( wholeBuffer == NULL ) {
5795 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
5796 if ( fd == -1 )
5797 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
5798 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
5799 streaming = true;
5800 // install signal handlers to delete output file if program is killed
5801 sCleanupFile = fFilePath;
5802 ::signal(SIGINT, cleanup);
5803 ::signal(SIGBUS, cleanup);
5804 ::signal(SIGSEGV, cleanup);
5805 }
5806 uint32_t size = 0;
5807 uint32_t end = 0;
5808 try {
5809 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5810 SegmentInfo* curSegment = *segit;
5811 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5812 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
5813 SectionInfo* curSection = *secit;
5814 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
5815 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
5816 //fprintf(stderr, "writing %lu atoms for section %p %s at file offset 0x%08llX\n", sectionAtoms.size(), curSection, curSection->fSectionName, curSection->fFileOffset);
5817 if ( ! curSection->fAllZeroFill ) {
5818 bool needsNops = ((strcmp(curSection->fSegmentName, "__TEXT") == 0) && (strncmp(curSection->fSectionName, "__text", 6) == 0));
5819 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
5820 ObjectFile::Atom* atom = *ait;
5821 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
5822 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
5823 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
5824 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
5825 if ( fileOffset != end ) {
5826 //fprintf(stderr, "writing %d pad bytes, needsNops=%d\n", fileOffset-end, needsNops);
5827 if ( needsNops ) {
5828 // fill gaps with no-ops
5829 if ( streaming )
5830 writeNoOps(fd, end, fileOffset);
5831 else
5832 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
5833 }
5834 else if ( streaming ) {
5835 // zero fill gaps
5836 if ( (fileOffset-end) == 4 ) {
5837 uint32_t zero = 0;
5838 ::pwrite(fd, &zero, 4, end);
5839 }
5840 else {
5841 uint8_t zero = 0x00;
5842 for (uint32_t p=end; p < fileOffset; ++p)
5843 ::pwrite(fd, &zero, 1, p);
5844 }
5845 }
5846 }
5847 uint64_t atomSize = atom->getSize();
5848 if ( streaming ) {
5849 if ( atomSize > fLargestAtomSize )
5850 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
5851 atom->getDisplayName(), atomSize, fLargestAtomSize);
5852 }
5853 else {
5854 if ( fileOffset > fileBufferSize )
5855 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
5856 atom->getDisplayName(), fileOffset, fileBufferSize);
5857 }
5858 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
5859 end = fileOffset+atomSize;
5860 // copy raw bytes
5861 atom->copyRawContent(buffer);
5862 // apply any fix-ups
5863 try {
5864 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5865 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
5866 ObjectFile::Reference* ref = *it;
5867 if ( fOptions.outputKind() == Options::kObjectFile ) {
5868 // doing ld -r
5869 // skip fix-ups for undefined targets
5870 if ( &(ref->getTarget()) != NULL )
5871 this->fixUpReferenceRelocatable(ref, atom, buffer);
5872 }
5873 else {
5874 // producing final linked image
5875 this->fixUpReferenceFinal(ref, atom, buffer);
5876 }
5877 }
5878 }
5879 catch (const char* msg) {
5880 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
5881 }
5882 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %p %s from %s\n",
5883 // fileOffset, end, atom->getAddress(), atom->getSize(), atom, atom->getDisplayName(), atom->getFile()->getPath());
5884 if ( streaming ) {
5885 // write out
5886 ::pwrite(fd, buffer, atomSize, fileOffset);
5887 }
5888 else {
5889 if ( (fileOffset + atomSize) > size )
5890 size = fileOffset + atomSize;
5891 }
5892 }
5893 }
5894 }
5895 }
5896 }
5897
5898 // update content based UUID
5899 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
5900 uint8_t digest[CC_MD5_DIGEST_LENGTH];
5901 if ( streaming ) {
5902 // if output file file did not fit in memory, re-read file to generate md5 hash
5903 uint32_t kMD5BufferSize = 16*1024;
5904 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
5905 if ( md5Buffer != NULL ) {
5906 CC_MD5_CTX md5State;
5907 CC_MD5_Init(&md5State);
5908 ::lseek(fd, 0, SEEK_SET);
5909 ssize_t len;
5910 while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 )
5911 CC_MD5_Update(&md5State, md5Buffer, len);
5912 CC_MD5_Final(digest, &md5State);
5913 ::free(md5Buffer);
5914 }
5915 else {
5916 // if malloc fails, fall back to random uuid
5917 ::uuid_generate_random(digest);
5918 }
5919 fUUIDAtom->setContent(digest);
5920 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
5921 fUUIDAtom->copyRawContent(atomBuffer);
5922 ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
5923 }
5924 else {
5925 // if output file fit in memory, just genrate an md5 hash in memory
5926 #if 1
5927 // temp hack for building on Tiger
5928 CC_MD5_CTX md5State;
5929 CC_MD5_Init(&md5State);
5930 CC_MD5_Update(&md5State, wholeBuffer, size);
5931 CC_MD5_Final(digest, &md5State);
5932 #else
5933 CC_MD5(wholeBuffer, size, digest);
5934 #endif
5935 fUUIDAtom->setContent(digest);
5936 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
5937 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
5938 }
5939 }
5940 }
5941 catch (...) {
5942 if ( sCleanupFile != NULL )
5943 ::unlink(sCleanupFile);
5944 throw;
5945 }
5946
5947 // finish up
5948 if ( streaming ) {
5949 delete [] atomBuffer;
5950 close(fd);
5951 // restore default signal handlers
5952 sCleanupFile = NULL;
5953 ::signal(SIGINT, SIG_DFL);
5954 ::signal(SIGBUS, SIG_DFL);
5955 ::signal(SIGSEGV, SIG_DFL);
5956 }
5957 else {
5958 // write whole output file in one chunk
5959 fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
5960 if ( fd == -1 )
5961 throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
5962 ::pwrite(fd, wholeBuffer, size, 0);
5963 close(fd);
5964 delete [] wholeBuffer;
5965 }
5966
5967 return end;
5968 }
5969
5970 template <>
5971 void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
5972 {
5973 int64_t displacement;
5974 int64_t baseAddr;
5975 uint32_t instruction;
5976 uint32_t newInstruction;
5977 uint64_t targetAddr = 0;
5978 uint32_t firstDisp;
5979 uint32_t nextDisp;
5980 uint32_t opcode = 0;
5981 bool relocateableExternal = false;
5982 bool is_bl;
5983 bool is_blx;
5984 bool targetIsThumb;
5985
5986 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
5987 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
5988 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
5989 }
5990
5991 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
5992 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
5993 case arm::kNoFixUp:
5994 case arm::kFollowOn:
5995 case arm::kGroupSubordinate:
5996 // do nothing
5997 break;
5998 case arm::kPointerWeakImport:
5999 case arm::kPointer:
6000 // If this is the lazy pointers section, then set all lazy pointers to
6001 // point to the dyld stub binding helper.
6002 if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers
6003 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
6004 switch (ref->getTarget().getDefinitionKind()) {
6005 case ObjectFile::Atom::kExternalDefinition:
6006 case ObjectFile::Atom::kExternalWeakDefinition:
6007 // prebound lazy pointer to another dylib ==> pointer contains zero
6008 LittleEndian::set32(*fixUp, 0);
6009 break;
6010 case ObjectFile::Atom::kTentativeDefinition:
6011 case ObjectFile::Atom::kRegularDefinition:
6012 case ObjectFile::Atom::kWeakDefinition:
6013 case ObjectFile::Atom::kAbsoluteSymbol:
6014 // prebound lazy pointer to withing this dylib ==> pointer contains address
6015 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6016 targetAddr |= 1;
6017 LittleEndian::set32(*fixUp, targetAddr);
6018 break;
6019 }
6020 }
6021 else if ( relocateableExternal ) {
6022 if ( fOptions.prebind() ) {
6023 switch (ref->getTarget().getDefinitionKind()) {
6024 case ObjectFile::Atom::kExternalDefinition:
6025 case ObjectFile::Atom::kExternalWeakDefinition:
6026 // prebound external relocation ==> pointer contains addend
6027 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6028 break;
6029 case ObjectFile::Atom::kTentativeDefinition:
6030 case ObjectFile::Atom::kRegularDefinition:
6031 case ObjectFile::Atom::kWeakDefinition:
6032 // prebound external relocation to internal atom ==> pointer contains target address + addend
6033 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
6034 targetAddr |= 1;
6035 LittleEndian::set32(*fixUp, targetAddr);
6036 break;
6037 case ObjectFile::Atom::kAbsoluteSymbol:
6038 break;
6039 }
6040 }
6041 else {
6042 // external relocation ==> pointer contains addend
6043 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6044 }
6045 }
6046 else {
6047 // pointer contains target address
6048 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6049 targetAddr |= 1;
6050 LittleEndian::set32(*fixUp, targetAddr);
6051 }
6052 break;
6053 case arm::kPointerDiff:
6054 LittleEndian::set32(*fixUp,
6055 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6056 break;
6057 case arm::kReadOnlyPointer:
6058 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6059 targetAddr |= 1;
6060 switch ( ref->getTarget().getDefinitionKind() ) {
6061 case ObjectFile::Atom::kRegularDefinition:
6062 case ObjectFile::Atom::kWeakDefinition:
6063 case ObjectFile::Atom::kTentativeDefinition:
6064 // pointer contains target address
6065 LittleEndian::set32(*fixUp, targetAddr);
6066 break;
6067 case ObjectFile::Atom::kExternalDefinition:
6068 case ObjectFile::Atom::kExternalWeakDefinition:
6069 // external relocation ==> pointer contains addend
6070 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6071 break;
6072 case ObjectFile::Atom::kAbsoluteSymbol:
6073 // pointer contains target address
6074 LittleEndian::set32(*fixUp, targetAddr);
6075 break;
6076 }
6077 break;
6078 case arm::kBranch24WeakImport:
6079 case arm::kBranch24:
6080 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6081 // The pc added will be +8 from the pc
6082 displacement -= 8;
6083 // fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6084 // max positive displacement is 0x007FFFFF << 2
6085 // max negative displacement is 0xFF800000 << 2
6086 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6087 throwf("b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6088 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6089 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6090 }
6091 instruction = LittleEndian::get32(*fixUp);
6092 // Make sure we are calling arm with bl, thumb with blx
6093 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6094 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6095 if ( is_bl && ref->getTarget().isThumb() ) {
6096 uint32_t opcode = 0xFA000000;
6097 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6098 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6099 newInstruction = opcode | h_bit | disp;
6100 }
6101 else if ( is_blx && !ref->getTarget().isThumb() ) {
6102 uint32_t opcode = 0xEB000000;
6103 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6104 newInstruction = opcode | disp;
6105 }
6106 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6107 throwf("don't know how to convert instruction %x referencing %s to thumb",
6108 instruction, ref->getTarget().getDisplayName());
6109 }
6110 else {
6111 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6112 }
6113 LittleEndian::set32(*fixUp, newInstruction);
6114 break;
6115 case arm::kThumbBranch22WeakImport:
6116 case arm::kThumbBranch22:
6117 instruction = LittleEndian::get32(*fixUp);
6118 is_bl = ((instruction & 0xD000F800) == 0xD000F000);
6119 is_blx = ((instruction & 0xD000F800) == 0xC000F000);
6120 targetIsThumb = ref->getTarget().isThumb();
6121
6122 // The pc added will be +4 from the pc
6123 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6124 // If the target is not thumb, we will be generating a blx instruction
6125 // Since blx cannot have the low bit set, set bit[1] of the target to
6126 // bit[1] of the base address, so that the difference is a multiple of
6127 // 4 bytes.
6128 if ( !targetIsThumb ) {
6129 targetAddr &= -3ULL;
6130 targetAddr |= (baseAddr & 2LL);
6131 }
6132 displacement = targetAddr - baseAddr;
6133
6134 // max positive displacement is 0x003FFFFE
6135 // max negative displacement is 0xFFC00000
6136 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6137 // armv7 supports a larger displacement
6138 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6139 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6140 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6141 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6142 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6143 }
6144 else {
6145 // The instruction is really two instructions:
6146 // The lower 16 bits are the first instruction, which contains the high
6147 // 11 bits of the displacement.
6148 // The upper 16 bits are the second instruction, which contains the low
6149 // 11 bits of the displacement, as well as differentiating bl and blx.
6150 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6151 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6152 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6153 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6154 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6155 uint32_t j1 = (i1 == s);
6156 uint32_t j2 = (i2 == s);
6157 if ( is_bl ) {
6158 if ( targetIsThumb )
6159 opcode = 0xD000F000; // keep bl
6160 else
6161 opcode = 0xC000F000; // change to blx
6162 }
6163 else if ( is_blx ) {
6164 if ( targetIsThumb )
6165 opcode = 0xD000F000; // change to bl
6166 else
6167 opcode = 0xC000F000; // keep blx
6168 }
6169 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6170 throwf("don't know how to convert instruction %x referencing %s to arm",
6171 instruction, ref->getTarget().getDisplayName());
6172 }
6173 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6174 firstDisp = (s << 10) | imm10;
6175 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6176 //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",
6177 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6178 LittleEndian::set32(*fixUp, newInstruction);
6179 }
6180 }
6181 else {
6182 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6183 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6184 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6185 }
6186 }
6187 else {
6188 // The instruction is really two instructions:
6189 // The lower 16 bits are the first instruction, which contains the high
6190 // 11 bits of the displacement.
6191 // The upper 16 bits are the second instruction, which contains the low
6192 // 11 bits of the displacement, as well as differentiating bl and blx.
6193 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6194 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6195 if ( is_bl && !targetIsThumb ) {
6196 opcode = 0xE800F000;
6197 }
6198 else if ( is_blx && targetIsThumb ) {
6199 opcode = 0xF800F000;
6200 }
6201 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6202 throwf("don't know how to convert instruction %x referencing %s to arm",
6203 instruction, ref->getTarget().getDisplayName());
6204 }
6205 else {
6206 opcode = instruction & 0xF800F800;
6207 }
6208 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6209 LittleEndian::set32(*fixUp, newInstruction);
6210 }
6211 break;
6212 case arm::kDtraceProbeSite:
6213 if ( inAtom->isThumb() ) {
6214 // change 32-bit blx call site to two thumb NOPs
6215 LittleEndian::set32(*fixUp, 0x46C046C0);
6216 }
6217 else {
6218 // change call site to a NOP
6219 LittleEndian::set32(*fixUp, 0xE1A00000);
6220 }
6221 break;
6222 case arm::kDtraceIsEnabledSite:
6223 if ( inAtom->isThumb() ) {
6224 // change 32-bit blx call site to 'nop', 'eor r0, r0'
6225 LittleEndian::set32(*fixUp, 0x46C04040);
6226 }
6227 else {
6228 // change call site to 'eor r0, r0, r0'
6229 LittleEndian::set32(*fixUp, 0xE0200000);
6230 }
6231 break;
6232 case arm::kDtraceTypeReference:
6233 case arm::kDtraceProbe:
6234 // nothing to fix up
6235 break;
6236 default:
6237 throw "boom shaka laka";
6238 }
6239 }
6240
6241 template <>
6242 void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6243 {
6244 int64_t displacement;
6245 uint32_t instruction;
6246 uint32_t newInstruction;
6247 uint64_t targetAddr = 0;
6248 int64_t baseAddr;
6249 uint32_t firstDisp;
6250 uint32_t nextDisp;
6251 uint32_t opcode = 0;
6252 bool relocateableExternal = false;
6253 bool is_bl;
6254 bool is_blx;
6255 bool targetIsThumb;
6256
6257 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
6258 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
6259 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
6260 }
6261
6262 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6263 switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
6264 case arm::kNoFixUp:
6265 case arm::kFollowOn:
6266 case arm::kGroupSubordinate:
6267 // do nothing
6268 break;
6269 case arm::kPointer:
6270 case arm::kReadOnlyPointer:
6271 case arm::kPointerWeakImport:
6272 {
6273 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6274 // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
6275 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6276 LittleEndian::set32(*fixUp, targetAddr);
6277 else
6278 LittleEndian::set32(*fixUp, 0);
6279 }
6280 else if ( relocateableExternal ) {
6281 if ( fOptions.prebind() ) {
6282 switch (ref->getTarget().getDefinitionKind()) {
6283 case ObjectFile::Atom::kExternalDefinition:
6284 case ObjectFile::Atom::kExternalWeakDefinition:
6285 // prebound external relocation ==> pointer contains addend
6286 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6287 break;
6288 case ObjectFile::Atom::kTentativeDefinition:
6289 case ObjectFile::Atom::kRegularDefinition:
6290 case ObjectFile::Atom::kWeakDefinition:
6291 // prebound external relocation to internal atom ==> pointer contains target address + addend
6292 LittleEndian::set32(*fixUp, targetAddr);
6293 break;
6294 case ObjectFile::Atom::kAbsoluteSymbol:
6295 break;
6296 }
6297 }
6298 }
6299 else {
6300 // internal relocation
6301 if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6302 // pointer contains target address
6303 if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
6304 targetAddr |= 1;
6305 LittleEndian::set32(*fixUp, targetAddr);
6306 }
6307 else {
6308 // pointer contains addend
6309 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6310 }
6311 }
6312 }
6313 break;
6314 case arm::kPointerDiff:
6315 LittleEndian::set32(*fixUp,
6316 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6317 break;
6318 case arm::kDtraceProbeSite:
6319 case arm::kDtraceIsEnabledSite:
6320 case arm::kBranch24WeakImport:
6321 case arm::kBranch24:
6322 displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
6323 // The pc added will be +8 from the pc
6324 displacement -= 8;
6325 // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
6326 if ( relocateableExternal ) {
6327 // doing "ld -r" to an external symbol
6328 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6329 displacement -= ref->getTarget().getAddress();
6330 }
6331 else {
6332 // max positive displacement is 0x007FFFFF << 2
6333 // max negative displacement is 0xFF800000 << 2
6334 if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
6335 throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
6336 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6337 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6338 }
6339 }
6340 instruction = LittleEndian::get32(*fixUp);
6341 // Make sure we are calling arm with bl, thumb with blx
6342 is_bl = ((instruction & 0xFF000000) == 0xEB000000);
6343 is_blx = ((instruction & 0xFE000000) == 0xFA000000);
6344 if ( is_bl && ref->getTarget().isThumb() ) {
6345 uint32_t opcode = 0xFA000000;
6346 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6347 uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
6348 newInstruction = opcode | h_bit | disp;
6349 }
6350 else if ( is_blx && !ref->getTarget().isThumb() ) {
6351 uint32_t opcode = 0xEB000000;
6352 uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
6353 newInstruction = opcode | disp;
6354 }
6355 else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
6356 throwf("don't know how to convert instruction %x referencing %s to thumb",
6357 instruction, ref->getTarget().getDisplayName());
6358 }
6359 else {
6360 newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
6361 }
6362 LittleEndian::set32(*fixUp, newInstruction);
6363 break;
6364 case arm::kThumbBranch22WeakImport:
6365 case arm::kThumbBranch22:
6366 instruction = LittleEndian::get32(*fixUp);
6367 is_bl = ((instruction & 0xF8000000) == 0xF8000000);
6368 is_blx = ((instruction & 0xF8000000) == 0xE8000000);
6369 targetIsThumb = ref->getTarget().isThumb();
6370
6371 // The pc added will be +4 from the pc
6372 baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
6373 // If the target is not thumb, we will be generating a blx instruction
6374 // Since blx cannot have the low bit set, set bit[1] of the target to
6375 // bit[1] of the base address, so that the difference is a multiple of
6376 // 4 bytes.
6377 if (!targetIsThumb) {
6378 targetAddr &= -3ULL;
6379 targetAddr |= (baseAddr & 2LL);
6380 }
6381 displacement = targetAddr - baseAddr;
6382
6383 //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);
6384 if ( relocateableExternal ) {
6385 // doing "ld -r" to an external symbol
6386 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
6387 displacement -= ref->getTarget().getAddress();
6388 }
6389
6390 if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
6391 // armv7 supports a larger displacement
6392 if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
6393 if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
6394 throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
6395 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6396 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6397 }
6398 else {
6399 // The instruction is really two instructions:
6400 // The lower 16 bits are the first instruction, which contains the high
6401 // 11 bits of the displacement.
6402 // The upper 16 bits are the second instruction, which contains the low
6403 // 11 bits of the displacement, as well as differentiating bl and blx.
6404 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
6405 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
6406 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
6407 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
6408 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
6409 uint32_t j1 = (i1 == s);
6410 uint32_t j2 = (i2 == s);
6411 if ( is_bl ) {
6412 if ( targetIsThumb )
6413 opcode = 0xD000F000; // keep bl
6414 else
6415 opcode = 0xC000F000; // change to blx
6416 }
6417 else if ( is_blx ) {
6418 if ( targetIsThumb )
6419 opcode = 0xD000F000; // change to bl
6420 else
6421 opcode = 0xC000F000; // keep blx
6422 }
6423 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6424 throwf("don't know how to convert instruction %x referencing %s to arm",
6425 instruction, ref->getTarget().getDisplayName());
6426 }
6427 nextDisp = (j1 << 13) | (j2 << 11) | imm11;
6428 firstDisp = (s << 10) | imm10;
6429 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6430 //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",
6431 // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
6432 LittleEndian::set32(*fixUp, newInstruction);
6433 break;
6434 }
6435 }
6436 else {
6437 throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
6438 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
6439 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6440 }
6441 }
6442 // The instruction is really two instructions:
6443 // The lower 16 bits are the first instruction, which contains the first
6444 // 11 bits of the displacement.
6445 // The upper 16 bits are the second instruction, which contains the next
6446 // 11 bits of the displacement, as well as differentiating bl and blx.
6447 firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
6448 nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
6449 if ( is_bl && !targetIsThumb ) {
6450 opcode = 0xE800F000;
6451 }
6452 else if ( is_blx && targetIsThumb ) {
6453 opcode = 0xF800F000;
6454 }
6455 else if ( !is_bl && !is_blx && !targetIsThumb ) {
6456 throwf("don't know how to convert instruction %x referencing %s to arm",
6457 instruction, ref->getTarget().getDisplayName());
6458 }
6459 else {
6460 opcode = instruction & 0xF800F800;
6461 }
6462 newInstruction = opcode | (nextDisp << 16) | firstDisp;
6463 LittleEndian::set32(*fixUp, newInstruction);
6464 break;
6465 case arm::kDtraceProbe:
6466 case arm::kDtraceTypeReference:
6467 // nothing to fix up
6468 break;
6469 }
6470 }
6471
6472 template <>
6473 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6474 {
6475 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6476 uint8_t* dtraceProbeSite;
6477 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6478 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6479 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6480 const int64_t kOneTwentyEightLimit = 0x7F;
6481 int64_t displacement;
6482 uint32_t temp;
6483 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6484 switch ( kind ) {
6485 case x86::kNoFixUp:
6486 case x86::kFollowOn:
6487 case x86::kGroupSubordinate:
6488 // do nothing
6489 break;
6490 case x86::kPointerWeakImport:
6491 case x86::kPointer:
6492 {
6493 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6494 if ( fOptions.prebind() ) {
6495 switch (ref->getTarget().getDefinitionKind()) {
6496 case ObjectFile::Atom::kExternalDefinition:
6497 case ObjectFile::Atom::kExternalWeakDefinition:
6498 // prebound external relocation ==> pointer contains addend
6499 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6500 break;
6501 case ObjectFile::Atom::kTentativeDefinition:
6502 case ObjectFile::Atom::kRegularDefinition:
6503 case ObjectFile::Atom::kWeakDefinition:
6504 // prebound external relocation to internal atom ==> pointer contains target address + addend
6505 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6506 break;
6507 case ObjectFile::Atom::kAbsoluteSymbol:
6508 break;
6509 }
6510 }
6511 else if ( fOptions.makeCompressedDyldInfo()
6512 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6513 // lazy pointer is initially set to point directly to weak definition
6514 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6515 }
6516 else {
6517 // external relocation ==> pointer contains addend
6518 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6519 }
6520 }
6521 else {
6522 // pointer contains target address
6523 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6524 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6525 }
6526 }
6527 break;
6528 case x86::kPointerDiff:
6529 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6530 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6531 break;
6532 case x86::kPointerDiff16:
6533 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6534 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6535 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6536 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6537 break;
6538 case x86::kPointerDiff24:
6539 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6540 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6541 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6542 temp = LittleEndian::get32(*fixUp);
6543 temp &= 0xFF000000;
6544 temp |= (displacement & 0x00FFFFFF);
6545 LittleEndian::set32(*fixUp, temp);
6546 break;
6547 case x86::kDtraceProbeSite:
6548 // change call site to a NOP
6549 dtraceProbeSite = (uint8_t*)fixUp;
6550 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6551 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6552 dtraceProbeSite[1] = 0x1F;
6553 dtraceProbeSite[2] = 0x40;
6554 dtraceProbeSite[3] = 0x00;
6555 break;
6556 case x86::kDtraceIsEnabledSite:
6557 // change call site to a clear eax
6558 dtraceProbeSite = (uint8_t*)fixUp;
6559 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
6560 dtraceProbeSite[0] = 0xC0;
6561 dtraceProbeSite[1] = 0x90; // 1-byte nop
6562 dtraceProbeSite[2] = 0x90; // 1-byte nop
6563 dtraceProbeSite[3] = 0x90; // 1-byte nop
6564 break;
6565 case x86::kPCRel32WeakImport:
6566 case x86::kPCRel32:
6567 case x86::kPCRel16:
6568 case x86::kPCRel8:
6569 displacement = 0;
6570 switch ( ref->getTarget().getDefinitionKind() ) {
6571 case ObjectFile::Atom::kRegularDefinition:
6572 case ObjectFile::Atom::kWeakDefinition:
6573 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6574 break;
6575 case ObjectFile::Atom::kExternalDefinition:
6576 case ObjectFile::Atom::kExternalWeakDefinition:
6577 throw "codegen problem, can't use rel32 to external symbol";
6578 case ObjectFile::Atom::kTentativeDefinition:
6579 displacement = 0;
6580 break;
6581 case ObjectFile::Atom::kAbsoluteSymbol:
6582 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6583 break;
6584 }
6585 if ( kind == x86::kPCRel8 ) {
6586 displacement += 3;
6587 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6588 //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());
6589 throwf("rel8 out of range in %s", inAtom->getDisplayName());
6590 }
6591 *(int8_t*)fixUp = (int8_t)displacement;
6592 }
6593 else if ( kind == x86::kPCRel16 ) {
6594 displacement += 2;
6595 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6596 //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());
6597 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6598 }
6599 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6600 }
6601 else {
6602 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6603 //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());
6604 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6605 }
6606 LittleEndian::set32(*fixUp, (int32_t)displacement);
6607 }
6608 break;
6609 case x86::kAbsolute32:
6610 switch ( ref->getTarget().getDefinitionKind() ) {
6611 case ObjectFile::Atom::kRegularDefinition:
6612 case ObjectFile::Atom::kWeakDefinition:
6613 case ObjectFile::Atom::kTentativeDefinition:
6614 // pointer contains target address
6615 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6616 break;
6617 case ObjectFile::Atom::kExternalDefinition:
6618 case ObjectFile::Atom::kExternalWeakDefinition:
6619 // external relocation ==> pointer contains addend
6620 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6621 break;
6622 case ObjectFile::Atom::kAbsoluteSymbol:
6623 // pointer contains target address
6624 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
6625 break;
6626 }
6627 break;
6628 case x86::kImageOffset32:
6629 // offset of target atom from mach_header
6630 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6631 LittleEndian::set32(*fixUp, (int32_t)displacement);
6632 break;
6633 case x86::kDtraceTypeReference:
6634 case x86::kDtraceProbe:
6635 // nothing to fix up
6636 break;
6637 }
6638 }
6639
6640
6641
6642 template <>
6643 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6644 {
6645 const int64_t kTwoGigLimit = 0x7FFFFFFF;
6646 const int64_t kSixtyFourKiloLimit = 0x7FFF;
6647 const int64_t kOneTwentyEightLimit = 0x7F;
6648 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
6649 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
6650 int64_t displacement;
6651 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
6652 switch ( kind ) {
6653 case x86::kNoFixUp:
6654 case x86::kFollowOn:
6655 case x86::kGroupSubordinate:
6656 // do nothing
6657 break;
6658 case x86::kPointer:
6659 case x86::kPointerWeakImport:
6660 case x86::kAbsolute32:
6661 {
6662 if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
6663 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
6664 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
6665 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6666 else
6667 LittleEndian::set32(*fixUp, 0);
6668 }
6669 else if ( isExtern ) {
6670 // external relocation ==> pointer contains addend
6671 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6672 }
6673 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
6674 // internal relocation => pointer contains target address
6675 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6676 }
6677 else {
6678 // internal relocation to tentative ==> pointer contains addend
6679 LittleEndian::set32(*fixUp, ref->getTargetOffset());
6680 }
6681 }
6682 break;
6683 case x86::kPointerDiff:
6684 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6685 LittleEndian::set32(*fixUp, (uint32_t)displacement);
6686 break;
6687 case x86::kPointerDiff16:
6688 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6689 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
6690 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
6691 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
6692 break;
6693 case x86::kPCRel8:
6694 case x86::kPCRel16:
6695 case x86::kPCRel32:
6696 case x86::kPCRel32WeakImport:
6697 case x86::kDtraceProbeSite:
6698 case x86::kDtraceIsEnabledSite:
6699 {
6700 if ( isExtern )
6701 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6702 else
6703 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6704 if ( kind == x86::kPCRel8 ) {
6705 displacement += 3;
6706 if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
6707 //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());
6708 throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
6709 }
6710 int8_t byte = (int8_t)displacement;
6711 *((int8_t*)fixUp) = byte;
6712 }
6713 else if ( kind == x86::kPCRel16 ) {
6714 displacement += 2;
6715 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
6716 //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());
6717 throwf("rel16 out of range in %s", inAtom->getDisplayName());
6718 }
6719 int16_t word = (int16_t)displacement;
6720 LittleEndian::set16(*((uint16_t*)fixUp), word);
6721 }
6722 else {
6723 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
6724 //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement,
6725 // inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
6726 throwf("rel32 out of range in %s", inAtom->getDisplayName());
6727 }
6728 LittleEndian::set32(*fixUp, (int32_t)displacement);
6729 }
6730 }
6731 break;
6732 case x86::kPointerDiff24:
6733 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
6734 case x86::kImageOffset32:
6735 throw "internal linker error, kImageOffset32 can't be encoded into object files";
6736 case x86::kDtraceProbe:
6737 case x86::kDtraceTypeReference:
6738 // nothing to fix up
6739 break;
6740 }
6741 }
6742
6743 template <>
6744 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6745 {
6746 const int64_t twoGigLimit = 0x7FFFFFFF;
6747 const int64_t kSixteenMegLimit = 0x00FFFFFF;
6748 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
6749 uint8_t* dtraceProbeSite;
6750 int64_t displacement = 0;
6751 uint32_t temp;
6752 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
6753 case x86_64::kNoFixUp:
6754 case x86_64::kGOTNoFixUp:
6755 case x86_64::kFollowOn:
6756 case x86_64::kGroupSubordinate:
6757 // do nothing
6758 break;
6759 case x86_64::kPointerWeakImport:
6760 case x86_64::kPointer:
6761 {
6762 if ( &ref->getTarget() != NULL ) {
6763 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
6764 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal) {
6765 if ( fOptions.makeCompressedDyldInfo()
6766 && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
6767 // lazy pointer is initially set to point directly to weak definition
6768 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6769 }
6770 else {
6771 // external relocation ==> pointer contains addend
6772 LittleEndian::set64(*fixUp, ref->getTargetOffset());
6773 }
6774 }
6775 else {
6776 // internal relocation
6777 // pointer contains target address
6778 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6779 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6780 }
6781 }
6782 }
6783 break;
6784 case x86_64::kPointer32:
6785 {
6786 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
6787 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
6788 // external relocation
6789 throwf("32-bit pointer to dylib or weak symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
6790 }
6791 else {
6792 // internal relocation
6793 // pointer contains target address
6794 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
6795 displacement = ref->getTarget().getAddress() + ref->getTargetOffset();
6796 switch ( fOptions.outputKind() ) {
6797 case Options::kObjectFile:
6798 case Options::kPreload:
6799 case Options::kDyld:
6800 case Options::kDynamicLibrary:
6801 case Options::kDynamicBundle:
6802 case Options::kKextBundle:
6803 throwf("32-bit pointer to symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
6804 case Options::kDynamicExecutable:
6805 // <rdar://problem/5855588> allow x86_64 main executables to use 32-bit pointers if program loads in load 2GB
6806 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
6807 throw "32-bit pointer out of range";
6808 break;
6809 case Options::kStaticExecutable:
6810 // <rdar://problem/5855588> allow x86_64 mach_kernel to truncate pointers
6811 break;
6812 }
6813 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
6814 }
6815 }
6816 break;
6817 case x86_64::kPointerDiff32:
6818 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6819 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
6820 throw "32-bit pointer difference out of range";
6821 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
6822 break;
6823 case x86_64::kPointerDiff:
6824 LittleEndian::set64(*fixUp,
6825 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
6826 break;
6827 case x86_64::kPointerDiff24:
6828 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
6829 if ( (displacement > kSixteenMegLimit) || (displacement < 0) )
6830 throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
6831 temp = LittleEndian::get32(*((uint32_t*)fixUp));
6832 temp &= 0xFF000000;
6833 temp |= (displacement & 0x00FFFFFF);
6834 LittleEndian::set32(*((uint32_t*)fixUp), temp);
6835 break;
6836 case x86_64::kPCRel32GOTLoad:
6837 case x86_64::kPCRel32GOTLoadWeakImport:
6838 // if GOT entry was optimized away, change movq instruction to a leaq
6839 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
6840 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
6841 uint8_t* opcodes = (uint8_t*)fixUp;
6842 if ( opcodes[-2] != 0x8B )
6843 throw "GOT load reloc does not point to a movq instruction";
6844 opcodes[-2] = 0x8D;
6845 }
6846 // fall into general rel32 case
6847 case x86_64::kBranchPCRel32WeakImport:
6848 case x86_64::kBranchPCRel32:
6849 case x86_64::kBranchPCRel8:
6850 case x86_64::kPCRel32:
6851 case x86_64::kPCRel32_1:
6852 case x86_64::kPCRel32_2:
6853 case x86_64::kPCRel32_4:
6854 case x86_64::kPCRel32GOT:
6855 case x86_64::kPCRel32GOTWeakImport:
6856 switch ( ref->getTarget().getDefinitionKind() ) {
6857 case ObjectFile::Atom::kRegularDefinition:
6858 case ObjectFile::Atom::kWeakDefinition:
6859 case ObjectFile::Atom::kTentativeDefinition:
6860 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6861 break;
6862 case ObjectFile::Atom::kAbsoluteSymbol:
6863 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
6864 break;
6865 case ObjectFile::Atom::kExternalDefinition:
6866 case ObjectFile::Atom::kExternalWeakDefinition:
6867 if ( fOptions.outputKind() == Options::kKextBundle )
6868 displacement = 0;
6869 else
6870 throwf("codegen problem, can't use rel32 to external symbol %s", ref->getTarget().getDisplayName());
6871 break;
6872 }
6873 switch ( ref->getKind() ) {
6874 case x86_64::kPCRel32_1:
6875 displacement -= 1;
6876 break;
6877 case x86_64::kPCRel32_2:
6878 displacement -= 2;
6879 break;
6880 case x86_64::kPCRel32_4:
6881 displacement -= 4;
6882 break;
6883 case x86_64::kBranchPCRel8:
6884 displacement += 3;
6885 break;
6886 }
6887 if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
6888 if ( (displacement > 127) || (displacement < (-128)) ) {
6889 fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n",
6890 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
6891 throw "rel8 out of range";
6892 }
6893 *((int8_t*)fixUp) = (int8_t)displacement;
6894 }
6895 else {
6896 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
6897 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
6898 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
6899 throw "rel32 out of range";
6900 }
6901 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
6902 }
6903 break;
6904 case x86_64::kImageOffset32:
6905 // offset of target atom from mach_header
6906 displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
6907 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
6908 break;
6909 case x86_64::kDtraceProbeSite:
6910 // change call site to a NOP
6911 dtraceProbeSite = (uint8_t*)fixUp;
6912 dtraceProbeSite[-1] = 0x90; // 1-byte nop
6913 dtraceProbeSite[0] = 0x0F; // 4-byte nop
6914 dtraceProbeSite[1] = 0x1F;
6915 dtraceProbeSite[2] = 0x40;
6916 dtraceProbeSite[3] = 0x00;
6917 break;
6918 case x86_64::kDtraceIsEnabledSite:
6919 // change call site to a clear eax
6920 dtraceProbeSite = (uint8_t*)fixUp;
6921 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
6922 dtraceProbeSite[0] = 0x33;
6923 dtraceProbeSite[1] = 0xC0;
6924 dtraceProbeSite[2] = 0x90; // 1-byte nop
6925 dtraceProbeSite[3] = 0x90; // 1-byte nop
6926 break;
6927 case x86_64::kDtraceTypeReference:
6928 case x86_64::kDtraceProbe:
6929 // nothing to fix up
6930 break;
6931 }
6932 }
6933
6934 template <>
6935 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
6936 {
6937 const int64_t twoGigLimit = 0x7FFFFFFF;
6938 bool external = this->makesExternalRelocatableReference(ref->getTarget());
6939 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
6940 int64_t displacement = 0;
6941 int32_t temp32;
6942 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
6943 case x86_64::kNoFixUp:
6944 case x86_64::kGOTNoFixUp:
6945 case x86_64::kFollowOn:
6946 case x86_64::kGroupSubordinate:
6947 // do nothing
6948 break;
6949 case x86_64::kPointer:
6950 case x86_64::kPointerWeakImport:
6951 {
6952 if ( external ) {
6953 // external relocation ==> pointer contains addend
6954 LittleEndian::set64(*fixUp, ref->getTargetOffset());
6955 }
6956 else {
6957 // internal relocation ==> pointer contains target address
6958 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
6959 }
6960 }
6961 break;
6962 case x86_64::kPointer32:
6963 {
6964 if ( external ) {
6965 // external relocation ==> pointer contains addend
6966 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset());
6967 }
6968 else {
6969 // internal relocation ==> pointer contains target address
6970 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTarget().getAddress() + ref->getTargetOffset());
6971 }
6972 }
6973 break;
6974 case x86_64::kPointerDiff32:
6975 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
6976 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
6977 displacement += ref->getTarget().getAddress();
6978 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
6979 displacement -= ref->getFromTarget().getAddress();
6980 LittleEndian::set32(*((uint32_t*)fixUp), displacement);
6981 break;
6982 case x86_64::kPointerDiff:
6983 displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
6984 if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
6985 displacement += ref->getTarget().getAddress();
6986 if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
6987 displacement -= ref->getFromTarget().getAddress();
6988 LittleEndian::set64(*fixUp, displacement);
6989 break;
6990 case x86_64::kBranchPCRel32:
6991 case x86_64::kBranchPCRel32WeakImport:
6992 case x86_64::kDtraceProbeSite:
6993 case x86_64::kDtraceIsEnabledSite:
6994 case x86_64::kPCRel32:
6995 case x86_64::kPCRel32_1:
6996 case x86_64::kPCRel32_2:
6997 case x86_64::kPCRel32_4:
6998 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
6999 temp32 = ref->getTargetOffset();
7000 if ( external ) {
7001 // extern relocation contains addend
7002 displacement = temp32;
7003 }
7004 else {
7005 // internal relocations contain delta to target address
7006 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
7007 }
7008 switch ( ref->getKind() ) {
7009 case x86_64::kPCRel32_1:
7010 displacement -= 1;
7011 break;
7012 case x86_64::kPCRel32_2:
7013 displacement -= 2;
7014 break;
7015 case x86_64::kPCRel32_4:
7016 displacement -= 4;
7017 break;
7018 }
7019 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
7020 //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());
7021 throw "rel32 out of range";
7022 }
7023 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
7024 break;
7025 case x86_64::kBranchPCRel8:
7026 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
7027 temp32 = ref->getTargetOffset();
7028 if ( external ) {
7029 // extern relocation contains addend
7030 displacement = temp32;
7031 }
7032 else {
7033 // internal relocations contain delta to target address
7034 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
7035 }
7036 if ( (displacement > 127) || (displacement < (-128)) ) {
7037 //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());
7038 throw "rel8 out of range";
7039 }
7040 *((int8_t*)fixUp) = (int8_t)displacement;
7041 break;
7042 case x86_64::kPCRel32GOT:
7043 case x86_64::kPCRel32GOTLoad:
7044 case x86_64::kPCRel32GOTWeakImport:
7045 case x86_64::kPCRel32GOTLoadWeakImport:
7046 // contains addend (usually zero)
7047 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
7048 break;
7049 case x86_64::kPointerDiff24:
7050 throw "internal linker error, kPointerDiff24 can't be encoded into object files";
7051 case x86_64::kImageOffset32:
7052 throw "internal linker error, kImageOffset32 can't be encoded into object files";
7053 case x86_64::kDtraceTypeReference:
7054 case x86_64::kDtraceProbe:
7055 // nothing to fix up
7056 break;
7057 }
7058 }
7059
7060 template <>
7061 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7062 {
7063 fixUpReference_powerpc(ref, inAtom, buffer, true);
7064 }
7065
7066 template <>
7067 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7068 {
7069 fixUpReference_powerpc(ref, inAtom, buffer, true);
7070 }
7071
7072 template <>
7073 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7074 {
7075 fixUpReference_powerpc(ref, inAtom, buffer, false);
7076 }
7077
7078 template <>
7079 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
7080 {
7081 fixUpReference_powerpc(ref, inAtom, buffer, false);
7082 }
7083
7084 //
7085 // ppc and ppc64 are mostly the same, so they share a template specialzation
7086 //
7087 template <typename A>
7088 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
7089 {
7090 uint32_t instruction;
7091 uint32_t newInstruction;
7092 int64_t displacement;
7093 uint64_t targetAddr = 0;
7094 uint64_t picBaseAddr;
7095 uint16_t instructionLowHalf;
7096 uint16_t instructionHighHalf;
7097 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
7098 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
7099 bool relocateableExternal = false;
7100 const int64_t picbase_twoGigLimit = 0x80000000;
7101
7102 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
7103 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
7104 if ( finalLinkedImage )
7105 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
7106 else
7107 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
7108 }
7109
7110 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
7111 case A::kNoFixUp:
7112 case A::kFollowOn:
7113 case A::kGroupSubordinate:
7114 // do nothing
7115 break;
7116 case A::kPointerWeakImport:
7117 case A::kPointer:
7118 {
7119 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
7120 if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers
7121 || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
7122 switch (ref->getTarget().getDefinitionKind()) {
7123 case ObjectFile::Atom::kExternalDefinition:
7124 case ObjectFile::Atom::kExternalWeakDefinition:
7125 // prebound lazy pointer to another dylib ==> pointer contains zero
7126 P::setP(*fixUpPointer, 0);
7127 break;
7128 case ObjectFile::Atom::kTentativeDefinition:
7129 case ObjectFile::Atom::kRegularDefinition:
7130 case ObjectFile::Atom::kWeakDefinition:
7131 case ObjectFile::Atom::kAbsoluteSymbol:
7132 // prebound lazy pointer to withing this dylib ==> pointer contains address
7133 P::setP(*fixUpPointer, targetAddr);
7134 break;
7135 }
7136 }
7137 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
7138 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
7139 if ( this->indirectSymbolInRelocatableIsLocal(ref) )
7140 P::setP(*fixUpPointer, targetAddr);
7141 else
7142 P::setP(*fixUpPointer, 0);
7143 }
7144 else if ( relocateableExternal ) {
7145 if ( fOptions.prebind() ) {
7146 switch (ref->getTarget().getDefinitionKind()) {
7147 case ObjectFile::Atom::kExternalDefinition:
7148 case ObjectFile::Atom::kExternalWeakDefinition:
7149 // prebound external relocation ==> pointer contains addend
7150 P::setP(*fixUpPointer, ref->getTargetOffset());
7151 break;
7152 case ObjectFile::Atom::kTentativeDefinition:
7153 case ObjectFile::Atom::kRegularDefinition:
7154 case ObjectFile::Atom::kWeakDefinition:
7155 // prebound external relocation to internal atom ==> pointer contains target address + addend
7156 P::setP(*fixUpPointer, targetAddr);
7157 break;
7158 case ObjectFile::Atom::kAbsoluteSymbol:
7159 break;
7160 }
7161 }
7162 else {
7163 // external relocation ==> pointer contains addend
7164 P::setP(*fixUpPointer, ref->getTargetOffset());
7165 }
7166 }
7167 else {
7168 // internal relocation
7169 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
7170 // pointer contains target address
7171 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
7172 P::setP(*fixUpPointer, targetAddr);
7173 }
7174 else {
7175 // pointer contains addend
7176 P::setP(*fixUpPointer, ref->getTargetOffset());
7177 }
7178 }
7179 }
7180 break;
7181 case A::kPointerDiff64:
7182 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7183 break;
7184 case A::kPointerDiff32:
7185 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7186 break;
7187 case A::kPointerDiff16:
7188 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
7189 break;
7190 case A::kDtraceProbeSite:
7191 if ( finalLinkedImage ) {
7192 // change call site to a NOP
7193 BigEndian::set32(*fixUp, 0x60000000);
7194 }
7195 else {
7196 // set bl instuction to branch to address zero in .o file
7197 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7198 instruction = BigEndian::get32(*fixUp);
7199 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7200 BigEndian::set32(*fixUp, newInstruction);
7201 }
7202 break;
7203 case A::kDtraceIsEnabledSite:
7204 if ( finalLinkedImage ) {
7205 // change call site to a li r3,0
7206 BigEndian::set32(*fixUp, 0x38600000);
7207 }
7208 else {
7209 // set bl instuction to branch to address zero in .o file
7210 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
7211 instruction = BigEndian::get32(*fixUp);
7212 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7213 BigEndian::set32(*fixUp, newInstruction);
7214 }
7215 break;
7216 case A::kBranch24WeakImport:
7217 case A::kBranch24:
7218 {
7219 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
7220 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7221 if ( relocateableExternal ) {
7222 // doing "ld -r" to an external symbol
7223 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7224 displacement -= ref->getTarget().getAddress();
7225 }
7226 else {
7227 const int64_t bl_eightMegLimit = 0x00FFFFFF;
7228 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
7229 //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());
7230 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",
7231 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
7232 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
7233 }
7234 }
7235 instruction = BigEndian::get32(*fixUp);
7236 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
7237 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7238 BigEndian::set32(*fixUp, newInstruction);
7239 }
7240 break;
7241 case A::kBranch14:
7242 {
7243 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
7244 if ( relocateableExternal ) {
7245 // doing "ld -r" to an external symbol
7246 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
7247 displacement -= ref->getTarget().getAddress();
7248 }
7249 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
7250 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
7251 //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());
7252 throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
7253 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
7254 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
7255 }
7256
7257 //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
7258 instruction = BigEndian::get32(*fixUp);
7259 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
7260 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
7261 BigEndian::set32(*fixUp, newInstruction);
7262 }
7263 break;
7264 case A::kPICBaseLow16:
7265 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7266 displacement = targetAddr - picBaseAddr;
7267 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7268 throw "32-bit pic-base out of range";
7269 instructionLowHalf = (displacement & 0xFFFF);
7270 instruction = BigEndian::get32(*fixUp);
7271 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7272 BigEndian::set32(*fixUp, newInstruction);
7273 break;
7274 case A::kPICBaseLow14:
7275 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7276 displacement = targetAddr - picBaseAddr;
7277 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7278 throw "32-bit pic-base out of range";
7279 if ( (displacement & 0x3) != 0 )
7280 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
7281 instructionLowHalf = (displacement & 0xFFFC);
7282 instruction = BigEndian::get32(*fixUp);
7283 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7284 BigEndian::set32(*fixUp, newInstruction);
7285 break;
7286 case A::kPICBaseHigh16:
7287 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
7288 displacement = targetAddr - picBaseAddr;
7289 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
7290 throw "32-bit pic-base out of range";
7291 instructionLowHalf = displacement >> 16;
7292 if ( (displacement & 0x00008000) != 0 )
7293 ++instructionLowHalf;
7294 instruction = BigEndian::get32(*fixUp);
7295 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7296 BigEndian::set32(*fixUp, newInstruction);
7297 break;
7298 case A::kAbsLow16:
7299 if ( relocateableExternal && !finalLinkedImage )
7300 targetAddr -= ref->getTarget().getAddress();
7301 instructionLowHalf = (targetAddr & 0xFFFF);
7302 instruction = BigEndian::get32(*fixUp);
7303 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
7304 BigEndian::set32(*fixUp, newInstruction);
7305 break;
7306 case A::kAbsLow14:
7307 if ( relocateableExternal && !finalLinkedImage )
7308 targetAddr -= ref->getTarget().getAddress();
7309 if ( (targetAddr & 0x3) != 0 )
7310 throw "bad address for absolute lo14 instruction fix-up";
7311 instructionLowHalf = (targetAddr & 0xFFFF);
7312 instruction = BigEndian::get32(*fixUp);
7313 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
7314 BigEndian::set32(*fixUp, newInstruction);
7315 break;
7316 case A::kAbsHigh16:
7317 if ( relocateableExternal ) {
7318 if ( finalLinkedImage ) {
7319 switch (ref->getTarget().getDefinitionKind()) {
7320 case ObjectFile::Atom::kExternalDefinition:
7321 case ObjectFile::Atom::kExternalWeakDefinition:
7322 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7323 break;
7324 case ObjectFile::Atom::kTentativeDefinition:
7325 case ObjectFile::Atom::kRegularDefinition:
7326 case ObjectFile::Atom::kWeakDefinition:
7327 // use target address
7328 break;
7329 case ObjectFile::Atom::kAbsoluteSymbol:
7330 targetAddr = ref->getTarget().getSectionOffset();
7331 break;
7332 }
7333 }
7334 else {
7335 targetAddr -= ref->getTarget().getAddress();
7336 }
7337 }
7338 instructionHighHalf = (targetAddr >> 16);
7339 instruction = BigEndian::get32(*fixUp);
7340 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
7341 BigEndian::set32(*fixUp, newInstruction);
7342 break;
7343 case A::kAbsHigh16AddLow:
7344 if ( relocateableExternal ) {
7345 if ( finalLinkedImage ) {
7346 switch (ref->getTarget().getDefinitionKind()) {
7347 case ObjectFile::Atom::kExternalDefinition:
7348 case ObjectFile::Atom::kExternalWeakDefinition:
7349 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
7350 break;
7351 case ObjectFile::Atom::kTentativeDefinition:
7352 case ObjectFile::Atom::kRegularDefinition:
7353 case ObjectFile::Atom::kWeakDefinition:
7354 // use target address
7355 break;
7356 case ObjectFile::Atom::kAbsoluteSymbol:
7357 targetAddr = ref->getTarget().getSectionOffset();
7358 break;
7359 }
7360 }
7361 else {
7362 targetAddr -= ref->getTarget().getAddress();
7363 }
7364 }
7365 if ( targetAddr & 0x00008000 )
7366 targetAddr += 0x00010000;
7367 instruction = BigEndian::get32(*fixUp);
7368 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
7369 BigEndian::set32(*fixUp, newInstruction);
7370 break;
7371 case A::kDtraceTypeReference:
7372 case A::kDtraceProbe:
7373 // nothing to fix up
7374 break;
7375 }
7376 }
7377
7378 template <>
7379 bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7380 {
7381 uint8_t kind = ref->getKind();
7382 switch ( (ppc::ReferenceKinds)kind ) {
7383 case ppc::kNoFixUp:
7384 case ppc::kFollowOn:
7385 case ppc::kGroupSubordinate:
7386 case ppc::kPointer:
7387 case ppc::kPointerWeakImport:
7388 case ppc::kPointerDiff16:
7389 case ppc::kPointerDiff32:
7390 case ppc::kPointerDiff64:
7391 case ppc::kDtraceProbe:
7392 case ppc::kDtraceProbeSite:
7393 case ppc::kDtraceIsEnabledSite:
7394 case ppc::kDtraceTypeReference:
7395 // these are never used to call external functions
7396 return false;
7397 case ppc::kBranch24:
7398 case ppc::kBranch24WeakImport:
7399 case ppc::kBranch14:
7400 // these are used to call external functions
7401 return true;
7402 case ppc::kPICBaseLow16:
7403 case ppc::kPICBaseLow14:
7404 case ppc::kPICBaseHigh16:
7405 case ppc::kAbsLow16:
7406 case ppc::kAbsLow14:
7407 case ppc::kAbsHigh16:
7408 case ppc::kAbsHigh16AddLow:
7409 // these are only used to call external functions
7410 // in -mlong-branch stubs
7411 switch ( ref->getTarget().getDefinitionKind() ) {
7412 case ObjectFile::Atom::kExternalDefinition:
7413 case ObjectFile::Atom::kExternalWeakDefinition:
7414 // if the .o file this atom came from has long-branch stubs,
7415 // then assume these instructions in a stub.
7416 // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
7417 return ( inAtom->getFile()->hasLongBranchStubs() );
7418 case ObjectFile::Atom::kTentativeDefinition:
7419 case ObjectFile::Atom::kRegularDefinition:
7420 case ObjectFile::Atom::kWeakDefinition:
7421 case ObjectFile::Atom::kAbsoluteSymbol:
7422 return false;
7423 }
7424 break;
7425 }
7426 return false;
7427 }
7428
7429 template <>
7430 bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7431 {
7432 uint8_t kind = ref->getKind();
7433 switch ( (arm::ReferenceKinds)kind ) {
7434 case arm::kBranch24:
7435 case arm::kBranch24WeakImport:
7436 case arm::kThumbBranch22:
7437 case arm::kThumbBranch22WeakImport:
7438 return true;
7439 case arm::kNoFixUp:
7440 case arm::kFollowOn:
7441 case arm::kGroupSubordinate:
7442 case arm::kPointer:
7443 case arm::kReadOnlyPointer:
7444 case arm::kPointerWeakImport:
7445 case arm::kPointerDiff:
7446 case arm::kDtraceProbe:
7447 case arm::kDtraceProbeSite:
7448 case arm::kDtraceIsEnabledSite:
7449 case arm::kDtraceTypeReference:
7450 return false;
7451 }
7452 return false;
7453 }
7454
7455 template <>
7456 bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7457 {
7458 uint8_t kind = ref->getKind();
7459 switch ( (ppc64::ReferenceKinds)kind ) {
7460 case ppc::kNoFixUp:
7461 case ppc::kFollowOn:
7462 case ppc::kGroupSubordinate:
7463 case ppc::kPointer:
7464 case ppc::kPointerWeakImport:
7465 case ppc::kPointerDiff16:
7466 case ppc::kPointerDiff32:
7467 case ppc::kPointerDiff64:
7468 case ppc::kPICBaseLow16:
7469 case ppc::kPICBaseLow14:
7470 case ppc::kPICBaseHigh16:
7471 case ppc::kAbsLow16:
7472 case ppc::kAbsLow14:
7473 case ppc::kAbsHigh16:
7474 case ppc::kAbsHigh16AddLow:
7475 case ppc::kDtraceProbe:
7476 case ppc::kDtraceProbeSite:
7477 case ppc::kDtraceIsEnabledSite:
7478 case ppc::kDtraceTypeReference:
7479 // these are never used to call external functions
7480 return false;
7481 case ppc::kBranch24:
7482 case ppc::kBranch24WeakImport:
7483 case ppc::kBranch14:
7484 // these are used to call external functions
7485 return true;
7486 }
7487 return false;
7488 }
7489
7490 template <>
7491 bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7492 {
7493 uint8_t kind = ref->getKind();
7494 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
7495 }
7496
7497 template <>
7498 bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
7499 {
7500 uint8_t kind = ref->getKind();
7501 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
7502 }
7503
7504
7505 template <>
7506 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
7507 {
7508 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
7509 }
7510
7511 template <>
7512 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
7513 {
7514 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
7515 }
7516
7517 template <>
7518 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
7519 {
7520 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
7521 }
7522
7523 template <>
7524 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
7525 {
7526 switch ( kind ) {
7527 case x86_64::kPointerWeakImport:
7528 case x86_64::kBranchPCRel32WeakImport:
7529 case x86_64::kPCRel32GOTWeakImport:
7530 case x86_64::kPCRel32GOTLoadWeakImport:
7531 return true;
7532 }
7533 return false;
7534 }
7535
7536 template <>
7537 bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
7538 {
7539 return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
7540 kind == arm::kPointerWeakImport);
7541 }
7542
7543 template <>
7544 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
7545 {
7546 return false;
7547 }
7548
7549 template <>
7550 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
7551 {
7552 return false;
7553 }
7554
7555 template <>
7556 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
7557 {
7558 return false;
7559 }
7560
7561 template <>
7562 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
7563 {
7564 switch ( kind ) {
7565 case x86_64::kPCRel32GOT:
7566 case x86_64::kPCRel32GOTWeakImport:
7567 case x86_64::kPCRel32GOTLoad:
7568 case x86_64::kPCRel32GOTLoadWeakImport:
7569 case x86_64::kGOTNoFixUp:
7570 return true;
7571 }
7572 return false;
7573 }
7574
7575 template <>
7576 bool Writer<arm>::GOTReferenceKind(uint8_t kind)
7577 {
7578 return false;
7579 }
7580
7581 template <>
7582 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
7583 {
7584 return false;
7585 }
7586
7587 template <>
7588 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
7589 {
7590 return false;
7591 }
7592
7593 template <>
7594 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
7595 {
7596 return false;
7597 }
7598
7599 template <>
7600 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
7601 {
7602 switch ( kind ) {
7603 case x86_64::kPCRel32GOTLoad:
7604 case x86_64::kPCRel32GOTLoadWeakImport:
7605 return true;
7606 }
7607 return false;
7608 }
7609
7610 template <>
7611 bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
7612 {
7613 return false;
7614 }
7615
7616 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
7617 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
7618 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
7619 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
7620
7621
7622 template <typename A>
7623 void Writer<A>::optimizeDylibReferences()
7624 {
7625 //fprintf(stderr, "original ordinals table:\n");
7626 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7627 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7628 //}
7629 // find unused dylibs that can be removed
7630 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
7631 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
7632 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7633 ObjectFile::Reader* reader = it->first;
7634 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
7635 if ( aliasPos != fLibraryAliases.end() ) {
7636 // already noticed that this reader has same install name as another reader
7637 readerAliases[reader] = aliasPos->second;
7638 }
7639 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || reader->deadStrippable() || fOptions.deadStripDylibs()) ) {
7640 // this reader can be optimized away
7641 it->second = 0xFFFFFFFF;
7642 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
7643 if ( pos != fLibraryToLoadCommand.end() )
7644 pos->second->optimizeAway();
7645 }
7646 else {
7647 // mark this reader as using it ordinal
7648 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
7649 if ( pos == ordinalToReader.end() )
7650 ordinalToReader[it->second] = reader;
7651 else
7652 readerAliases[reader] = pos->second;
7653 }
7654 }
7655 // renumber ordinals (depends on iterator walking in ordinal order)
7656 // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
7657 uint32_t newOrdinal = 0;
7658 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7659 if ( it->first <= fLibraryToOrdinal.size() ) {
7660 if ( ! it->second->isLazyLoadedDylib() )
7661 fLibraryToOrdinal[it->second] = ++newOrdinal;
7662 }
7663 }
7664 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
7665 if ( it->first <= fLibraryToOrdinal.size() ) {
7666 if ( it->second->isLazyLoadedDylib() ) {
7667 fLibraryToOrdinal[it->second] = ++newOrdinal;
7668 }
7669 }
7670 }
7671
7672 // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
7673 if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
7674 throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
7675
7676 // add aliases (e.g. -lm points to libSystem.dylib)
7677 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
7678 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
7679 }
7680
7681 //fprintf(stderr, "new ordinals table:\n");
7682 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
7683 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
7684 //}
7685 }
7686
7687
7688 template <>
7689 void Writer<arm>::scanForAbsoluteReferences()
7690 {
7691 // arm codegen never has absolute references. FIXME: Is this correct?
7692 }
7693
7694 template <>
7695 void Writer<x86_64>::scanForAbsoluteReferences()
7696 {
7697 // x86_64 codegen never has absolute references
7698 }
7699
7700 template <>
7701 void Writer<x86>::scanForAbsoluteReferences()
7702 {
7703 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
7704 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
7705 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7706 ObjectFile::Atom* atom = *it;
7707 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7708 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7709 ObjectFile::Reference* ref = *rit;
7710 switch (ref->getKind()) {
7711 case x86::kAbsolute32:
7712 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
7713 return;
7714 }
7715 }
7716 }
7717 }
7718 }
7719
7720 template <>
7721 void Writer<ppc>::scanForAbsoluteReferences()
7722 {
7723 // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
7724 if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
7725 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7726 ObjectFile::Atom* atom = *it;
7727 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7728 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7729 ObjectFile::Reference* ref = *rit;
7730 switch (ref->getKind()) {
7731 case ppc::kAbsLow16:
7732 case ppc::kAbsLow14:
7733 case ppc::kAbsHigh16:
7734 case ppc::kAbsHigh16AddLow:
7735 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
7736 return;
7737 }
7738 }
7739 }
7740 }
7741 }
7742
7743
7744 // for ppc64 look for any -mdynamic-no-pic codegen
7745 template <>
7746 void Writer<ppc64>::scanForAbsoluteReferences()
7747 {
7748 // only do this for main executable
7749 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
7750 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7751 ObjectFile::Atom* atom = *it;
7752 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7753 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7754 ObjectFile::Reference* ref = *rit;
7755 switch (ref->getKind()) {
7756 case ppc64::kAbsLow16:
7757 case ppc64::kAbsLow14:
7758 case ppc64::kAbsHigh16:
7759 case ppc64::kAbsHigh16AddLow:
7760 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
7761 // shrink page-zero and add pad segment to compensate
7762 fPadSegmentInfo = new SegmentInfo(4096);
7763 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
7764 fPageZeroAtom->setSize(0x1000);
7765 return;
7766 }
7767 }
7768 }
7769 }
7770 }
7771
7772
7773 template <typename A>
7774 void Writer<A>::insertDummyStubs()
7775 {
7776 // only needed for x86
7777 }
7778
7779 template <>
7780 void Writer<x86>::insertDummyStubs()
7781 {
7782 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
7783 std::vector<class StubAtom<x86>*> betterStubs;
7784 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
7785 switch (betterStubs.size() % 64 ) {
7786 case 12:// stub would occupy 0x3C->0x41
7787 case 25:// stub would occupy 0x7D->0x82
7788 case 38:// stub would occupy 0xBE->0xC3
7789 case 51:// stub would occupy 0xFF->0x04
7790 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
7791 break;
7792 }
7793 betterStubs.push_back(*it);
7794 }
7795 // replace
7796 fAllSynthesizedStubs.clear();
7797 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
7798 }
7799
7800
7801 template <typename A>
7802 void Writer<A>::synthesizeKextGOT()
7803 {
7804 // walk every atom and reference
7805 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7806 ObjectFile::Atom* atom = *it;
7807 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7808 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7809 ObjectFile::Reference* ref = *rit;
7810 switch ( ref->getTargetBinding()) {
7811 case ObjectFile::Reference::kUnboundByName:
7812 case ObjectFile::Reference::kDontBind:
7813 break;
7814 case ObjectFile::Reference::kBoundByName:
7815 case ObjectFile::Reference::kBoundDirectly:
7816 ObjectFile::Atom& target = ref->getTarget();
7817 // create GOT slots (non-lazy pointers) as needed
7818 if ( this->GOTReferenceKind(ref->getKind()) ) {
7819 bool useGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
7820 // if this GOT usage cannot be optimized away then make a GOT enry
7821 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
7822 useGOT = true;
7823 if ( useGOT ) {
7824 ObjectFile::Atom* nlp = NULL;
7825 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
7826 if ( pos == fGOTMap.end() ) {
7827 nlp = new NonLazyPointerAtom<A>(*this, target);
7828 fGOTMap[&target] = nlp;
7829 }
7830 else {
7831 nlp = pos->second;
7832 }
7833 // alter reference to use non lazy pointer instead
7834 ref->setTarget(*nlp, ref->getTargetOffset());
7835 }
7836 }
7837 // build map of which symbols need weak importing
7838 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
7839 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
7840 if ( this->weakImportReferenceKind(ref->getKind()) ) {
7841 fWeakImportMap[&target] = true;
7842 }
7843 }
7844 break;
7845 }
7846 }
7847 }
7848
7849 // add non-lazy pointers to fAllAtoms
7850 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
7851 ObjectFile::Section* curSection = NULL;
7852 ObjectFile::Atom* prevAtom = NULL;
7853 bool inserted = false;
7854 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7855 ObjectFile::Atom* atom = *it;
7856 ObjectFile::Section* nextSection = atom->getSection();
7857 if ( nextSection != curSection ) {
7858 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__data") == 0) ) {
7859 // found end of __data section, insert lazy pointers here
7860 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
7861 inserted = true;
7862 break;
7863 }
7864 curSection = nextSection;
7865 }
7866 prevAtom = atom;
7867 }
7868 if ( !inserted ) {
7869 throw "can't insert non-lazy pointers, __data section not found";
7870 }
7871 }
7872
7873 }
7874
7875
7876 template <typename A>
7877 void Writer<A>::synthesizeStubs()
7878 {
7879 switch ( fOptions.outputKind() ) {
7880 case Options::kObjectFile:
7881 case Options::kPreload:
7882 // these output kinds never have stubs
7883 return;
7884 case Options::kKextBundle:
7885 // new kext need a synthesized GOT only
7886 synthesizeKextGOT();
7887 return;
7888 case Options::kStaticExecutable:
7889 case Options::kDyld:
7890 case Options::kDynamicLibrary:
7891 case Options::kDynamicBundle:
7892 case Options::kDynamicExecutable:
7893 // try to synthesize stubs for these
7894 break;
7895 }
7896
7897 // walk every atom and reference
7898 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
7899 ObjectFile::Atom* atom = *it;
7900 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
7901 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
7902 ObjectFile::Reference* ref = *rit;
7903 switch ( ref->getTargetBinding()) {
7904 case ObjectFile::Reference::kUnboundByName:
7905 case ObjectFile::Reference::kDontBind:
7906 break;
7907 case ObjectFile::Reference::kBoundByName:
7908 case ObjectFile::Reference::kBoundDirectly:
7909 ObjectFile::Atom& target = ref->getTarget();
7910 // build map of which symbols need weak importing
7911 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
7912 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
7913 bool weakImport = this->weakImportReferenceKind(ref->getKind());
7914 // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
7915 // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
7916 // in dylibs that are weakly linked.
7917 if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
7918 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
7919 pos = fLibraryToLoadCommand.find(target.getFile());
7920 if ( pos != fLibraryToLoadCommand.end() ) {
7921 if ( pos->second->linkedWeak() )
7922 weakImport = true;
7923 }
7924 }
7925 // <rdar://problem/6186838> -weak_library no longer forces uses to be weak_import
7926 if ( fForcedWeakImportReaders.count(target.getFile()) != 0 ) {
7927 fWeakImportMap[&target] = true;
7928 weakImport = true;
7929 }
7930
7931 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
7932 if ( pos == fWeakImportMap.end() ) {
7933 // target not in fWeakImportMap, so add
7934 fWeakImportMap[&target] = weakImport;
7935 }
7936 else {
7937 // target in fWeakImportMap, check for weakness mismatch
7938 if ( pos->second != weakImport ) {
7939 // found mismatch
7940 switch ( fOptions.weakReferenceMismatchTreatment() ) {
7941 case Options::kWeakReferenceMismatchError:
7942 throwf("mismatching weak references for symbol: %s", target.getName());
7943 case Options::kWeakReferenceMismatchWeak:
7944 pos->second = true;
7945 break;
7946 case Options::kWeakReferenceMismatchNonWeak:
7947 pos->second = false;
7948 break;
7949 }
7950 }
7951 }
7952 // update if we use a weak_import or a strong import from this dylib
7953 if ( fWeakImportMap[&target] )
7954 fDylibReadersWithWeakImports.insert(target.getFile());
7955 else
7956 fDylibReadersWithNonWeakImports.insert(target.getFile());
7957 }
7958 // create stubs as needed
7959 if ( this->stubableReference(atom, ref)
7960 && (ref->getTargetOffset() == 0)
7961 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
7962 ObjectFile::Atom* stub = NULL;
7963 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
7964 if ( pos == fStubsMap.end() ) {
7965 bool forLazyDylib = false;
7966 switch ( target.getDefinitionKind() ) {
7967 case ObjectFile::Atom::kRegularDefinition:
7968 case ObjectFile::Atom::kWeakDefinition:
7969 case ObjectFile::Atom::kAbsoluteSymbol:
7970 case ObjectFile::Atom::kTentativeDefinition:
7971 break;
7972 case ObjectFile::Atom::kExternalDefinition:
7973 case ObjectFile::Atom::kExternalWeakDefinition:
7974 if ( target.getFile()->isLazyLoadedDylib() )
7975 forLazyDylib = true;
7976 break;
7977 }
7978 // just-in-time, create GOT slot to dyld_stub_binder
7979 if ( fOptions.makeCompressedDyldInfo() && (fFastStubGOTAtom == NULL) ) {
7980 if ( fDyldCompressedHelperAtom == NULL )
7981 throw "missing symbol dyld_stub_binder";
7982 fFastStubGOTAtom = new NonLazyPointerAtom<A>(*this, *fDyldCompressedHelperAtom);
7983 }
7984 stub = new StubAtom<A>(*this, target, forLazyDylib);
7985 fStubsMap[&target] = stub;
7986 }
7987 else {
7988 stub = pos->second;
7989 }
7990 // alter reference to use stub instead
7991 ref->setTarget(*stub, 0);
7992 }
7993 else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
7994 throwf("illegal reference to %s in lazy loaded dylib from %s in %s",
7995 target.getDisplayName(), atom->getDisplayName(),
7996 atom->getFile()->getPath());
7997 }
7998 // create GOT slots (non-lazy pointers) as needed
7999 else if ( this->GOTReferenceKind(ref->getKind()) ) {
8000 //
8001 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
8002 bool useGOT;
8003 if ( fBiggerThanTwoGigs ) {
8004 // in big images use GOT for all zero fill atoms
8005 // this is just a heuristic and may need to be re-examined
8006 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
8007 }
8008 else {
8009 // < 2GB image so remove all GOT entries that we can
8010 useGOT = mustUseGOT;
8011 }
8012 // if this GOT usage cannot be optimized away then make a GOT enry
8013 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
8014 useGOT = true;
8015 if ( useGOT ) {
8016 ObjectFile::Atom* nlp = NULL;
8017 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
8018 if ( pos == fGOTMap.end() ) {
8019 nlp = new NonLazyPointerAtom<A>(*this, target);
8020 fGOTMap[&target] = nlp;
8021 }
8022 else {
8023 nlp = pos->second;
8024 }
8025 // alter reference to use non lazy pointer instead
8026 ref->setTarget(*nlp, ref->getTargetOffset());
8027 }
8028 }
8029 }
8030 }
8031 }
8032
8033 // sort stubs
8034 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
8035 std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter());
8036
8037 // add dummy self-modifying stubs (x86 only)
8038 if ( ! fOptions.makeCompressedDyldInfo() )
8039 this->insertDummyStubs();
8040
8041 // sort lazy pointers
8042 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
8043 std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
8044
8045
8046 // add stubs to fAllAtoms
8047 if ( fAllSynthesizedStubs.size() != 0 ) {
8048 std::vector<ObjectFile::Atom*> textStubs;
8049 std::vector<ObjectFile::Atom*> importStubs;
8050 for (typename std::vector<class StubAtom<A>*>::iterator sit=fAllSynthesizedStubs.begin(); sit != fAllSynthesizedStubs.end(); ++sit) {
8051 ObjectFile::Atom* stubAtom = *sit;
8052 if ( strcmp(stubAtom->getSegment().getName(), "__TEXT") == 0 )
8053 textStubs.push_back(stubAtom);
8054 else
8055 importStubs.push_back(stubAtom);
8056 }
8057 // any helper stubs go right after regular stubs
8058 if ( fAllSynthesizedStubHelpers.size() != 0 )
8059 textStubs.insert(textStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
8060 // insert text stubs right after __text section
8061 ObjectFile::Section* curSection = NULL;
8062 ObjectFile::Atom* prevAtom = NULL;
8063 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8064 ObjectFile::Atom* atom = *it;
8065 ObjectFile::Section* nextSection = atom->getSection();
8066 if ( nextSection != curSection ) {
8067 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
8068 // found end of __text section, insert stubs here
8069 fAllAtoms->insert(it, textStubs.begin(), textStubs.end());
8070 break;
8071 }
8072 curSection = nextSection;
8073 }
8074 prevAtom = atom;
8075 }
8076 if ( importStubs.size() != 0 ) {
8077 // insert __IMPORTS stubs right before __LINKEDIT
8078 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8079 ObjectFile::Atom* atom = *it;
8080 ObjectFile::Section* nextSection = atom->getSection();
8081 if ( nextSection != curSection ) {
8082 // for i386 where stubs are not in __TEXT segment
8083 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
8084 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
8085 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
8086 fAllAtoms->insert(it, importStubs.begin(), importStubs.end());
8087 break;
8088 }
8089 curSection = nextSection;
8090 }
8091 prevAtom = atom;
8092 }
8093 }
8094 }
8095
8096
8097 // add non-lazy pointers to fAllAtoms
8098 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
8099 ObjectFile::Section* curSection = NULL;
8100 ObjectFile::Atom* prevAtom = NULL;
8101 bool inserted = false;
8102 // first try to insert at end of __nl_symbol_ptr
8103 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8104 ObjectFile::Atom* atom = *it;
8105 ObjectFile::Section* nextSection = atom->getSection();
8106 if ( nextSection != curSection ) {
8107 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) {
8108 // found end of __nl_symbol_ptr section, insert non-lazy pointers at end of it
8109 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8110 inserted = true;
8111 break;
8112 }
8113 curSection = nextSection;
8114 }
8115 prevAtom = atom;
8116 }
8117 if ( !inserted ) {
8118 // next try to insert after __dyld section
8119 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8120 ObjectFile::Atom* atom = *it;
8121 ObjectFile::Section* nextSection = atom->getSection();
8122 if ( nextSection != curSection ) {
8123 if ( strcmp(atom->getSegment().getName(), "__DATA") == 0 ) {
8124 const char* prevSectionName = (prevAtom != NULL) ? prevAtom->getSectionName() : "";
8125 if ( (strcmp(prevSectionName, "__dyld") != 0)
8126 && (strcmp(prevSectionName, "__program_vars") != 0)
8127 && (strcmp(prevSectionName, "__mod_init_func") != 0) ) {
8128 // found end of __dyld section, insert non-lazy pointers here
8129 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8130 inserted = true;
8131 break;
8132 }
8133 }
8134 }
8135 prevAtom = atom;
8136 }
8137 if ( !inserted ) {
8138 // might not be any __DATA sections, insert after end of __TEXT
8139 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8140 ObjectFile::Atom* atom = *it;
8141 ObjectFile::Section* nextSection = atom->getSection();
8142 if ( nextSection != curSection ) {
8143 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__TEXT") == 0) && (strcmp(atom->getSegment().getName(), "__TEXT") != 0)) {
8144 // found end of __TEXT segment, insert non-lazy pointers at end of it
8145 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
8146 inserted = true;
8147 break;
8148 }
8149 curSection = nextSection;
8150 }
8151 prevAtom = atom;
8152 }
8153 }
8154 if ( !inserted )
8155 throw "can't insert non-lazy pointers, __dyld section not found";
8156 }
8157 }
8158
8159 // add lazy dylib pointers to fAllAtoms
8160 if ( fAllSynthesizedLazyDylibPointers.size() != 0 ) {
8161 ObjectFile::Section* curSection = NULL;
8162 ObjectFile::Atom* prevAtom = NULL;
8163 bool inserted = false;
8164 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8165 ObjectFile::Atom* atom = *it;
8166 ObjectFile::Section* nextSection = atom->getSection();
8167 if ( nextSection != curSection ) {
8168 if ( (prevAtom != NULL) &&
8169 ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0)
8170 || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0)
8171 || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) {
8172 // found end of __dyld section, insert lazy pointers here
8173 fAllAtoms->insert(it, fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
8174 inserted = true;
8175 break;
8176 }
8177 curSection = nextSection;
8178 }
8179 prevAtom = atom;
8180 }
8181 if ( !inserted ) {
8182 throw "can't insert lazy pointers, __dyld section not found";
8183 }
8184 }
8185
8186 // add lazy pointers to fAllAtoms
8187 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
8188 ObjectFile::Section* curSection = NULL;
8189 ObjectFile::Atom* prevAtom = NULL;
8190 bool inserted = false;
8191 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8192 ObjectFile::Atom* atom = *it;
8193 ObjectFile::Section* nextSection = atom->getSection();
8194 if ( nextSection != curSection ) {
8195 if ( (prevAtom != NULL) &&
8196 ( (strcmp(prevAtom->getSectionName(), "__dyld") == 0)
8197 || (strcmp(prevAtom->getSectionName(), "__program_vars") == 0)
8198 || (strcmp(prevAtom->getSectionName(), "__nl_symbol_ptr") == 0) ) ) {
8199 // found end of __dyld section, insert lazy pointers here
8200 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
8201 inserted = true;
8202 break;
8203 }
8204 curSection = nextSection;
8205 }
8206 prevAtom = atom;
8207 }
8208 if ( !inserted ) {
8209 throw "can't insert lazy pointers, __dyld section not found";
8210 }
8211 }
8212
8213
8214 }
8215
8216 template <typename A>
8217 void Writer<A>::createSplitSegContent()
8218 {
8219 // build LC_SEGMENT_SPLIT_INFO once all atoms exist
8220 if ( fSplitCodeToDataContentAtom != NULL ) {
8221 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8222 ObjectFile::Atom* atom = *it;
8223 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8224 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8225 ObjectFile::Reference* ref = *rit;
8226 switch ( ref->getTargetBinding()) {
8227 case ObjectFile::Reference::kUnboundByName:
8228 case ObjectFile::Reference::kDontBind:
8229 break;
8230 case ObjectFile::Reference::kBoundByName:
8231 case ObjectFile::Reference::kBoundDirectly:
8232 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
8233 this->addCrossSegmentRef(atom, ref);
8234 }
8235 break;
8236 }
8237 }
8238 }
8239 // bad codegen may cause LC_SEGMENT_SPLIT_INFO to be removed
8240 adjustLoadCommandsAndPadding();
8241 }
8242
8243 }
8244
8245
8246 template <typename A>
8247 void Writer<A>::synthesizeUnwindInfoTable()
8248 {
8249 if ( fUnwindInfoAtom != NULL ) {
8250 // walk every atom and gets its unwind info
8251 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8252 ObjectFile::Atom* atom = *it;
8253 if ( atom->beginUnwind() == atom->endUnwind() ) {
8254 // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
8255 if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
8256 fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL);
8257 }
8258 else {
8259 // atom has unwind
8260 for ( ObjectFile::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
8261 fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getLSDA(), atom->getPersonalityPointer());
8262 }
8263 }
8264 }
8265 }
8266 }
8267
8268
8269
8270 template <typename A>
8271 void Writer<A>::partitionIntoSections()
8272 {
8273 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
8274
8275 // for every atom, set its sectionInfo object and section offset
8276 // build up fSegmentInfos along the way
8277 ObjectFile::Section* curSection = (ObjectFile::Section*)(-1);
8278 SectionInfo* currentSectionInfo = NULL;
8279 SegmentInfo* currentSegmentInfo = NULL;
8280 SectionInfo* cstringSectionInfo = NULL;
8281 unsigned int sectionIndex = 1;
8282 fSegmentInfos.reserve(8);
8283 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
8284 ObjectFile::Atom* atom = (*fAllAtoms)[i];
8285 if ( ((atom->getSection() != curSection) || (curSection==NULL))
8286 && ((currentSectionInfo == NULL)
8287 || (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)
8288 || (strcmp(atom->getSegment().getName(),currentSectionInfo->fSegmentName) != 0)) ) {
8289 if ( oneSegmentCommand ) {
8290 if ( currentSegmentInfo == NULL ) {
8291 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8292 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8293 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8294 this->fSegmentInfos.push_back(currentSegmentInfo);
8295 }
8296 currentSectionInfo = new SectionInfo();
8297 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8298 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8299 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8300 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8301 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
8302 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8303 currentSectionInfo->setIndex(sectionIndex++);
8304 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8305 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
8306 cstringSectionInfo = currentSectionInfo;
8307 }
8308 else {
8309 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
8310 currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
8311 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
8312 uint32_t initprot = 0;
8313 if ( atom->getSegment().isContentReadable() )
8314 initprot |= VM_PROT_READ;
8315 if ( atom->getSegment().isContentWritable() )
8316 initprot |= VM_PROT_WRITE;
8317 if ( atom->getSegment().isContentExecutable() )
8318 initprot |= VM_PROT_EXECUTE;
8319 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
8320 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
8321 currentSegmentInfo->fInitProtection = initprot;
8322 if ( initprot == 0 )
8323 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
8324 else if ( fOptions.architecture() == CPU_TYPE_ARM )
8325 currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init
8326 else
8327 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
8328 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
8329 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
8330 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
8331 currentSegmentInfo->fInitProtection = it->init;
8332 currentSegmentInfo->fMaxProtection = it->max;
8333 }
8334 }
8335 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
8336 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
8337 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
8338 currentSegmentInfo->fIndependentAddress = true;
8339 if ( (fOptions.outputKind() == Options::kPreload) && (strcmp(currentSegmentInfo->fName, "__LINKEDIT")==0) )
8340 currentSegmentInfo->fHasLoadCommand = false;
8341 if ( strcmp(currentSegmentInfo->fName, "__HEADER")==0 )
8342 currentSegmentInfo->fHasLoadCommand = false;
8343 this->fSegmentInfos.push_back(currentSegmentInfo);
8344 }
8345 currentSectionInfo = new SectionInfo();
8346 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
8347 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
8348 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
8349 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
8350 // check for -sectalign override
8351 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
8352 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
8353 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
8354 currentSectionInfo->fAlignment = it->alignment;
8355 }
8356 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
8357 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
8358 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
8359 currentSectionInfo->setIndex(sectionIndex++);
8360 currentSegmentInfo->fSections.push_back(currentSectionInfo);
8361 }
8362 //fprintf(stderr, "new section %s for atom %s\n", atom->getSectionName(), atom->getDisplayName());
8363 if ( strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0 ) {
8364 fLoadCommandsSection = currentSectionInfo;
8365 fLoadCommandsSegment = currentSegmentInfo;
8366 }
8367 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
8368 currentSectionInfo->fAllLazyPointers = true;
8369 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
8370 currentSectionInfo->fAllLazyPointers = true;
8371 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__ld_symbol_ptr") == 0) )
8372 currentSectionInfo->fAllLazyDylibPointers = true;
8373 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
8374 currentSectionInfo->fAllNonLazyPointers = true;
8375 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
8376 currentSectionInfo->fAllNonLazyPointers = true;
8377 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
8378 currentSectionInfo->fAllNonLazyPointers = true;
8379 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
8380 currentSectionInfo->fAllStubs = true;
8381 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
8382 currentSectionInfo->fAllStubs = true;
8383 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
8384 currentSectionInfo->fAllStubs = true;
8385 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
8386 currentSectionInfo->fAllStubs = true;
8387 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub4") == 0) )
8388 currentSectionInfo->fAllStubs = true;
8389 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub4") == 0) )
8390 currentSectionInfo->fAllStubs = true;
8391 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
8392 currentSectionInfo->fAllSelfModifyingStubs = true;
8393 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
8394 }
8395 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__stub_helper") == 0) )
8396 currentSectionInfo->fAllStubHelpers = true;
8397 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__eh_frame") == 0) )
8398 currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
8399 curSection = atom->getSection();
8400 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers || currentSectionInfo->fAllLazyDylibPointers
8401 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllSelfModifyingStubs ) {
8402 fSymbolTableCommands->needDynamicTable();
8403 }
8404 }
8405 // any non-zero fill atoms make whole section marked not-zero-fill
8406 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
8407 currentSectionInfo->fAllZeroFill = false;
8408 // change section object to be Writer's SectionInfo object
8409 atom->setSection(currentSectionInfo);
8410 // section alignment is that of a contained atom with the greatest alignment
8411 uint8_t atomAlign = atom->getAlignment().powerOf2;
8412 if ( currentSectionInfo->fAlignment < atomAlign )
8413 currentSectionInfo->fAlignment = atomAlign;
8414 // calculate section offset for this atom
8415 uint64_t offset = currentSectionInfo->fSize;
8416 uint64_t alignment = 1 << atomAlign;
8417 uint64_t currentModulus = (offset % alignment);
8418 uint64_t requiredModulus = atom->getAlignment().modulus;
8419 if ( currentModulus != requiredModulus ) {
8420 if ( requiredModulus > currentModulus )
8421 offset += requiredModulus-currentModulus;
8422 else
8423 offset += requiredModulus+alignment-currentModulus;
8424 }
8425 atom->setSectionOffset(offset);
8426 uint64_t curAtomSize = atom->getSize();
8427 currentSectionInfo->fSize = offset + curAtomSize;
8428 // add atom to section vector
8429 currentSectionInfo->fAtoms.push_back(atom);
8430 //fprintf(stderr, " adding atom %p %s size=0x%0llX to section %p %s from %s\n", atom, atom->getDisplayName(), atom->getSize(),
8431 // currentSectionInfo, currentSectionInfo->fSectionName, atom->getFile()->getPath());
8432 // update largest size
8433 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
8434 fLargestAtomSize = curAtomSize;
8435 }
8436 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
8437 // when merging cstring sections in .o files, all strings need to use the max alignment
8438 uint64_t offset = 0;
8439 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
8440 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
8441 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
8442 ObjectFile::Atom* atom = *it;
8443 atom->setSectionOffset(offset);
8444 offset += atom->getSize();
8445 }
8446 cstringSectionInfo->fSize = offset;
8447 }
8448 }
8449
8450
8451 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
8452 class TargetAndOffsetComparor
8453 {
8454 public:
8455 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
8456 {
8457 if ( left.atom != right.atom )
8458 return ( left.atom < right.atom );
8459 return ( left.offset < right.offset );
8460 }
8461 };
8462
8463 template <>
8464 bool Writer<ppc>::addBranchIslands()
8465 {
8466 return this->addPPCBranchIslands();
8467 }
8468
8469 template <>
8470 bool Writer<ppc64>::addBranchIslands()
8471 {
8472 return this->addPPCBranchIslands();
8473 }
8474
8475 template <>
8476 bool Writer<x86>::addBranchIslands()
8477 {
8478 // x86 branches can reach entire 4G address space, so no need for branch islands
8479 return false;
8480 }
8481
8482 template <>
8483 bool Writer<x86_64>::addBranchIslands()
8484 {
8485 // x86 branches can reach entire 4G size of largest image
8486 return false;
8487 }
8488
8489 template <>
8490 bool Writer<arm>::addBranchIslands()
8491 {
8492 // arm branch islands not (yet) supported
8493 // you can instead compile with -mlong-call
8494 return false;
8495 }
8496
8497 template <>
8498 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
8499 {
8500 switch (kind) {
8501 case ppc::kBranch24:
8502 case ppc::kBranch24WeakImport:
8503 return true;
8504 }
8505 return false;
8506 }
8507
8508 template <>
8509 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
8510 {
8511 switch (kind) {
8512 case ppc64::kBranch24:
8513 case ppc64::kBranch24WeakImport:
8514 return true;
8515 }
8516 return false;
8517 }
8518
8519 //
8520 // PowerPC can do PC relative branches as far as +/-16MB.
8521 // If a branch target is >16MB then we insert one or more
8522 // "branch islands" between the branch and its target that
8523 // allows island hoping to the target.
8524 //
8525 // Branch Island Algorithm
8526 //
8527 // If the __TEXT segment < 16MB, then no branch islands needed
8528 // Otherwise, every 14MB into the __TEXT segment a region is
8529 // added which can contain branch islands. Every out of range
8530 // bl instruction is checked. If it crosses a region, an island
8531 // is added to that region with the same target and the bl is
8532 // adjusted to target the island instead.
8533 //
8534 // In theory, if too many islands are added to one region, it
8535 // could grow the __TEXT enough that other previously in-range
8536 // bl branches could be pushed out of range. We reduce the
8537 // probability this could happen by placing the ranges every
8538 // 15MB which means the region would have to be 1MB (256K islands)
8539 // before any branches could be pushed out of range.
8540 //
8541 template <typename A>
8542 bool Writer<A>::addPPCBranchIslands()
8543 {
8544 bool log = false;
8545 bool result = false;
8546 // Can only possibly need branch islands if __TEXT segment > 16M
8547 if ( fLoadCommandsSegment->fSize > 16000000 ) {
8548 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
8549 const uint32_t kBetweenRegions = 14*1024*1024; // place regions of islands every 14MB in __text section
8550 SectionInfo* textSection = NULL;
8551 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
8552 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
8553 textSection = *it;
8554 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
8555 break;
8556 }
8557 }
8558 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
8559 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
8560 AtomToIsland regionsMap[kIslandRegionsCount];
8561 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
8562 unsigned int islandCount = 0;
8563 if ( log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
8564
8565 // create islands for branch references that are out of range
8566 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
8567 ObjectFile::Atom* atom = *it;
8568 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
8569 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
8570 ObjectFile::Reference* ref = *rit;
8571 if ( this->isBranch24Reference(ref->getKind()) ) {
8572 ObjectFile::Atom& target = ref->getTarget();
8573 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
8574 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
8575 int64_t displacement = dstAddr - srcAddr;
8576 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
8577 const int64_t kFifteenMegLimit = kBetweenRegions;
8578 if ( displacement > kFifteenMegLimit ) {
8579 // create forward branch chain
8580 ObjectFile::Atom* nextTarget = &target;
8581 uint64_t nextTargetOffset = ref->getTargetOffset();
8582 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
8583 AtomToIsland* region = &regionsMap[i];
8584 int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
8585 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
8586 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8587 if ( pos == region->end() ) {
8588 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
8589 island->setSection(textSection);
8590 (*region)[finalTargetAndOffset] = island;
8591 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8592 regionsIslands[i].push_back(island);
8593 ++islandCount;
8594 nextTarget = island;
8595 nextTargetOffset = 0;
8596 }
8597 else {
8598 nextTarget = pos->second;
8599 nextTargetOffset = 0;
8600 }
8601 }
8602 }
8603 if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
8604 ref->setTarget(*nextTarget, nextTargetOffset);
8605 }
8606 else if ( displacement < (-kFifteenMegLimit) ) {
8607 // create back branching chain
8608 ObjectFile::Atom* prevTarget = &target;
8609 uint64_t prevTargetOffset = ref->getTargetOffset();
8610 for (int i=0; i < kIslandRegionsCount ; ++i) {
8611 AtomToIsland* region = &regionsMap[i];
8612 int64_t islandRegionAddr = kBetweenRegions * (i+1);
8613 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
8614 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
8615 if ( pos == region->end() ) {
8616 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
8617 island->setSection(textSection);
8618 (*region)[finalTargetAndOffset] = island;
8619 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
8620 regionsIslands[i].push_back(island);
8621 ++islandCount;
8622 prevTarget = island;
8623 prevTargetOffset = 0;
8624 }
8625 else {
8626 prevTarget = pos->second;
8627 prevTargetOffset = 0;
8628 }
8629 }
8630 }
8631 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
8632 ref->setTarget(*prevTarget, prevTargetOffset);
8633 }
8634 }
8635 }
8636 }
8637
8638 // insert islands into __text section and adjust section offsets
8639 if ( islandCount > 0 ) {
8640 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
8641 std::vector<ObjectFile::Atom*> newAtomList;
8642 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
8643 uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
8644 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
8645 int regionIndex = 0;
8646 uint64_t atomSlide = 0;
8647 uint64_t sectionOffset = 0;
8648 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
8649 ObjectFile::Atom* atom = *it;
8650 if ( (atom->getAddress()+atom->getSize()) > islandRegionAddr ) {
8651 uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
8652 sectionOffset = islandStartOffset;
8653 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
8654 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8655 ObjectFile::Atom* islandAtom = *rit;
8656 newAtomList.push_back(islandAtom);
8657 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8658 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8659 islandAtom->setSectionOffset(sectionOffset);
8660 sectionOffset += islandAtom->getSize();
8661 }
8662 ++regionIndex;
8663 islandRegionAddr += kBetweenRegions;
8664 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
8665 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
8666 }
8667 newAtomList.push_back(atom);
8668 if ( atomSlide != 0 )
8669 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
8670 }
8671 sectionOffset = textSection->fSize+atomSlide;
8672 // put any remaining islands at end of __text section
8673 if ( regionIndex < kIslandRegionsCount ) {
8674 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
8675 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
8676 ObjectFile::Atom* islandAtom = *rit;
8677 newAtomList.push_back(islandAtom);
8678 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
8679 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
8680 islandAtom->setSectionOffset(sectionOffset);
8681 sectionOffset += islandAtom->getSize();
8682 }
8683 }
8684
8685 textSection->fAtoms = newAtomList;
8686 textSection->fSize = sectionOffset;
8687 result = true;
8688 }
8689
8690 }
8691 return result;
8692 }
8693
8694
8695 template <typename A>
8696 void Writer<A>::adjustLoadCommandsAndPadding()
8697 {
8698 fSegmentCommands->computeSize();
8699
8700 // recompute load command section offsets
8701 uint64_t offset = 0;
8702 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
8703 const unsigned int atomCount = loadCommandAtoms.size();
8704 for (unsigned int i=0; i < atomCount; ++i) {
8705 ObjectFile::Atom* atom = loadCommandAtoms[i];
8706 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
8707 offset = ( (offset+alignment-1) & (-alignment) );
8708 atom->setSectionOffset(offset);
8709 uint32_t atomSize = atom->getSize();
8710 if ( atomSize > fLargestAtomSize )
8711 fLargestAtomSize = atomSize;
8712 offset += atomSize;
8713 fLoadCommandsSection->fSize = offset;
8714 }
8715
8716 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
8717 const int sectionCount = sectionInfos.size();
8718 uint32_t totalSizeOfTEXTLessHeaderAndLoadCommands = 0;
8719 for(int j=0; j < sectionCount; ++j) {
8720 SectionInfo* curSection = sectionInfos[j];
8721 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8722 break;
8723 totalSizeOfTEXTLessHeaderAndLoadCommands += curSection->fSize;
8724 }
8725 uint64_t paddingSize = 0;
8726 if ( fOptions.outputKind() == Options::kDyld ) {
8727 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
8728 paddingSize = 4096 - (totalSizeOfTEXTLessHeaderAndLoadCommands % 4096);
8729 }
8730 else if ( fOptions.outputKind() == Options::kObjectFile ) {
8731 // mach-o .o files need no padding between load commands and first section
8732 // but leave enough room that the object file could be signed
8733 paddingSize = 32;
8734 }
8735 else if ( fOptions.outputKind() == Options::kPreload ) {
8736 // mach-o MH_PRELOAD files need no padding between load commands and first section
8737 paddingSize = 0;
8738 }
8739 else if ( fOptions.makeEncryptable() ) {
8740 // want load commands to end on a page boundary, so __text starts on page boundary
8741 paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
8742 fEncryptionLoadCommand->setStartEncryptionOffset(totalSizeOfTEXTLessHeaderAndLoadCommands+paddingSize);
8743 }
8744 else {
8745 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
8746 uint64_t addr = 0;
8747 for(int j=sectionCount-1; j >=0; --j) {
8748 SectionInfo* curSection = sectionInfos[j];
8749 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
8750 addr -= (fLoadCommandsSection->fSize+fMachHeaderAtom->getSize());
8751 paddingSize = addr % fOptions.segmentAlignment();
8752 break;
8753 }
8754 addr -= curSection->fSize;
8755 addr = addr & (0 - (1 << curSection->fAlignment));
8756 }
8757
8758 // if command line requires more padding than this
8759 uint32_t minPad = fOptions.minimumHeaderPad();
8760 if ( fOptions.maxMminimumHeaderPad() ) {
8761 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
8762 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
8763 if ( fOptions.outputKind() == Options::kDynamicLibrary )
8764 altMin += MAXPATHLEN;
8765 if ( altMin > minPad )
8766 minPad = altMin;
8767 }
8768 if ( paddingSize < minPad ) {
8769 int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment();
8770 paddingSize += extraPages * fOptions.segmentAlignment();
8771 }
8772 }
8773
8774 // adjust atom size and update section size
8775 fHeaderPadding->setSize(paddingSize);
8776 for(int j=0; j < sectionCount; ++j) {
8777 SectionInfo* curSection = sectionInfos[j];
8778 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
8779 curSection->fSize = paddingSize;
8780 }
8781 }
8782
8783 static uint64_t segmentAlign(uint64_t addr, uint64_t alignment)
8784 {
8785 return ((addr+alignment-1) & (-alignment));
8786 }
8787
8788 // assign file offsets and logical address to all segments
8789 template <typename A>
8790 void Writer<A>::assignFileOffsets()
8791 {
8792 const bool virtualSectionOccupyAddressSpace = ((fOptions.outputKind() != Options::kObjectFile)
8793 && (fOptions.outputKind() != Options::kPreload));
8794 bool haveFixedSegments = false;
8795 uint64_t fileOffset = 0;
8796 uint64_t nextContiguousAddress = fOptions.baseAddress();
8797 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
8798 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
8799
8800 // process segments with fixed addresses (-segaddr)
8801 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
8802 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8803 SegmentInfo* curSegment = *segit;
8804 if ( strcmp(curSegment->fName, it->name) == 0 ) {
8805 curSegment->fBaseAddress = it->address;
8806 curSegment->fFixedAddress = true;
8807 break;
8808 }
8809 }
8810 }
8811
8812 // process segments with fixed addresses (-seg_page_size)
8813 for (std::vector<Options::SegmentSize>::iterator it = fOptions.customSegmentSizes().begin(); it != fOptions.customSegmentSizes().end(); ++it) {
8814 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8815 SegmentInfo* curSegment = *segit;
8816 if ( strcmp(curSegment->fName, it->name) == 0 ) {
8817 curSegment->fPageSize = it->size;
8818 break;
8819 }
8820 }
8821 }
8822
8823 // Run through the segments and each segment's sections to assign addresses
8824 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8825 SegmentInfo* curSegment = *segit;
8826
8827 if ( fOptions.splitSeg() ) {
8828 if ( curSegment->fInitProtection & VM_PROT_WRITE )
8829 nextContiguousAddress = nextWritableAddress;
8830 else
8831 nextContiguousAddress = nextReadOnlyAddress;
8832 }
8833
8834 if ( fOptions.outputKind() == Options::kPreload ) {
8835 if ( strcmp(curSegment->fName, "__HEADER") == 0 )
8836 nextContiguousAddress = 0;
8837 else if ( strcmp(curSegment->fName, "__TEXT") == 0 )
8838 nextContiguousAddress = fOptions.baseAddress();
8839 }
8840
8841 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
8842 curSegment->fFileOffset = fileOffset;
8843
8844 // Set the segment base address
8845 if ( curSegment->fFixedAddress )
8846 haveFixedSegments = true;
8847 else
8848 curSegment->fBaseAddress = segmentAlign(nextContiguousAddress, curSegment->fPageSize);
8849
8850 // We've set the segment address, now run through each section.
8851 uint64_t address = curSegment->fBaseAddress;
8852 SectionInfo* firstZeroFillSection = NULL;
8853 SectionInfo* prevSection = NULL;
8854
8855 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
8856
8857 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
8858 SectionInfo* curSection = *it;
8859
8860 // adjust section address based on alignment
8861 uint64_t alignment = 1 << curSection->fAlignment;
8862 if ( curSection->fAtoms.size() == 1 ) {
8863 // if there is only one atom in section, use modulus for even better layout
8864 ObjectFile::Alignment atomAlign = curSection->fAtoms[0]->getAlignment();
8865 uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
8866 uint64_t currentModulus = (address % atomAlignP2);
8867 if ( currentModulus != atomAlign.modulus ) {
8868 if ( atomAlign.modulus > currentModulus )
8869 address += atomAlign.modulus-currentModulus;
8870 else
8871 address += atomAlign.modulus+atomAlignP2-currentModulus;
8872 }
8873 }
8874 else {
8875 address = ( (address+alignment-1) & (-alignment) );
8876 }
8877
8878 // adjust file offset to match address
8879 if ( prevSection != NULL ) {
8880 if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection )
8881 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
8882 else
8883 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
8884 }
8885
8886 // update section info
8887 curSection->fFileOffset = fileOffset;
8888 curSection->setBaseAddress(address);
8889 //fprintf(stderr, "%s %s addr=0x%llX, fileoffset=0x%llX, size=0x%llX\n", curSegment->fName, curSection->fSectionName, address, fileOffset, curSection->fSize);
8890
8891 // keep track of trailing zero fill sections
8892 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
8893 firstZeroFillSection = curSection;
8894 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && (fOptions.outputKind() != Options::kObjectFile) )
8895 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
8896
8897 // update running pointers
8898 if ( virtualSectionOccupyAddressSpace || !curSection->fVirtualSection )
8899 address += curSection->fSize;
8900 fileOffset += curSection->fSize;
8901
8902 // sanity check size of 32-bit binaries
8903 if ( address > maxAddress() )
8904 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
8905
8906 // update segment info
8907 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
8908 curSegment->fSize = curSegment->fFileSize;
8909 prevSection = curSection;
8910 }
8911
8912 if ( fOptions.outputKind() == Options::kObjectFile ) {
8913 // don't page align .o files
8914 }
8915 else {
8916 // optimize trailing zero-fill sections to not occupy disk space
8917 if ( firstZeroFillSection != NULL ) {
8918 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
8919 fileOffset = firstZeroFillSection->fFileOffset;
8920 }
8921 // page align segment size
8922 curSegment->fFileSize = segmentAlign(curSegment->fFileSize, curSegment->fPageSize);
8923 curSegment->fSize = segmentAlign(curSegment->fSize, curSegment->fPageSize);
8924 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
8925 nextContiguousAddress = segmentAlign(curSegment->fBaseAddress+curSegment->fSize, curSegment->fPageSize);
8926 fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
8927 if ( curSegment->fInitProtection & VM_PROT_WRITE )
8928 nextWritableAddress = nextContiguousAddress;
8929 else
8930 nextReadOnlyAddress = nextContiguousAddress;
8931 }
8932 }
8933 //fprintf(stderr, "end of seg %s, fileoffset=0x%llX, nextContiguousAddress=0x%llX\n", curSegment->fName, fileOffset, nextContiguousAddress);
8934 }
8935
8936 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
8937 if ( haveFixedSegments ) {
8938 int segCount = fSegmentInfos.size();
8939 for(int i=0; i < segCount; ++i) {
8940 SegmentInfo* segment1 = fSegmentInfos[i];
8941
8942 for(int j=0; j < segCount; ++j) {
8943 if ( i != j ) {
8944 SegmentInfo* segment2 = fSegmentInfos[j];
8945
8946 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
8947 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
8948 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
8949 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
8950 }
8951 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
8952 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
8953 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
8954 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
8955 }
8956 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
8957 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
8958 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
8959 }
8960 }
8961 }
8962 }
8963 }
8964
8965 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
8966 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8967 SegmentInfo* curSegment = *segit;
8968 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
8969 if ( fFirstWritableSegment == NULL )
8970 fFirstWritableSegment = curSegment;
8971 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
8972 fWritableSegmentPastFirst4GB = true;
8973 }
8974 }
8975
8976 // record size of encrypted part of __TEXT segment
8977 if ( fOptions.makeEncryptable() ) {
8978 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
8979 SegmentInfo* curSegment = *segit;
8980 if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
8981 fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
8982 break;
8983 }
8984 }
8985 }
8986
8987 }
8988
8989 template <typename A>
8990 void Writer<A>::adjustLinkEditSections()
8991 {
8992 // link edit content is always in last segment
8993 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
8994 unsigned int firstLinkEditSectionIndex = 0;
8995 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
8996 ++firstLinkEditSectionIndex;
8997
8998 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
8999 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
9000 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
9001 if ( fPadSegmentInfo != NULL ) {
9002 // insert __4GBFILL segment into segments vector before LINKEDIT
9003 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
9004 if ( *it == lastSeg ) {
9005 fSegmentInfos.insert(it, fPadSegmentInfo);
9006 break;
9007 }
9008 }
9009 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
9010 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
9011 fPadSegmentInfo->fBaseAddress = address;
9012 // adjust LINKEDIT to start at zeroPageSize
9013 address = fOptions.zeroPageSize();
9014 lastSeg->fBaseAddress = fOptions.zeroPageSize();
9015 }
9016 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
9017 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
9018 // adjust section address based on alignment
9019 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
9020 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
9021 address += pad;
9022 fileOffset += pad; // adjust file offset to match address
9023 lastSeg->fSections[i]->setBaseAddress(address);
9024 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
9025 lastSeg->fSections[i]->setBaseAddress(0);
9026 lastSeg->fSections[i]->fFileOffset = fileOffset;
9027 uint64_t sectionOffset = 0;
9028 for (unsigned int j=0; j < atoms.size(); ++j) {
9029 ObjectFile::Atom* atom = atoms[j];
9030 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
9031 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
9032 atom->setSectionOffset(sectionOffset);
9033 uint64_t size = atom->getSize();
9034 sectionOffset += size;
9035 if ( size > fLargestAtomSize )
9036 fLargestAtomSize = size;
9037 }
9038 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
9039 lastSeg->fSections[i]->fSize = sectionOffset;
9040 fileOffset += sectionOffset;
9041 address += sectionOffset;
9042 }
9043 if ( fOptions.outputKind() == Options::kObjectFile ) {
9044 //lastSeg->fBaseAddress = 0;
9045 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
9046 //lastSeg->fFileOffset = 0;
9047 //lastSeg->fFileSize =
9048 }
9049 else {
9050 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
9051 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
9052 }
9053 }
9054
9055
9056 template <typename A>
9057 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
9058 {
9059 switch ( fWriter.fOptions.outputKind() ) {
9060 case Options::kDynamicExecutable:
9061 case Options::kStaticExecutable:
9062 return ObjectFile::Atom::scopeGlobal;
9063 case Options::kDynamicLibrary:
9064 case Options::kDynamicBundle:
9065 case Options::kDyld:
9066 case Options::kObjectFile:
9067 case Options::kPreload:
9068 case Options::kKextBundle:
9069 return ObjectFile::Atom::scopeLinkageUnit;
9070 }
9071 throw "unknown header type";
9072 }
9073
9074 template <typename A>
9075 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
9076 {
9077 switch ( fWriter.fOptions.outputKind() ) {
9078 case Options::kDynamicExecutable:
9079 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
9080 case Options::kStaticExecutable:
9081 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
9082 case Options::kDynamicLibrary:
9083 case Options::kDynamicBundle:
9084 case Options::kDyld:
9085 return ObjectFile::Atom::kSymbolTableIn;
9086 case Options::kObjectFile:
9087 case Options::kPreload:
9088 case Options::kKextBundle:
9089 return ObjectFile::Atom::kSymbolTableNotIn;
9090 }
9091 throw "unknown header type";
9092 }
9093
9094 template <typename A>
9095 const char* MachHeaderAtom<A>::getName() const
9096 {
9097 switch ( fWriter.fOptions.outputKind() ) {
9098 case Options::kDynamicExecutable:
9099 case Options::kStaticExecutable:
9100 return "__mh_execute_header";
9101 case Options::kDynamicLibrary:
9102 return "__mh_dylib_header";
9103 case Options::kDynamicBundle:
9104 return "__mh_bundle_header";
9105 case Options::kObjectFile:
9106 case Options::kPreload:
9107 case Options::kKextBundle:
9108 return NULL;
9109 case Options::kDyld:
9110 return "__mh_dylinker_header";
9111 }
9112 throw "unknown header type";
9113 }
9114
9115 template <typename A>
9116 const char* MachHeaderAtom<A>::getDisplayName() const
9117 {
9118 switch ( fWriter.fOptions.outputKind() ) {
9119 case Options::kDynamicExecutable:
9120 case Options::kStaticExecutable:
9121 case Options::kDynamicLibrary:
9122 case Options::kDynamicBundle:
9123 case Options::kDyld:
9124 return this->getName();
9125 case Options::kObjectFile:
9126 case Options::kPreload:
9127 case Options::kKextBundle:
9128 return "mach header";
9129 }
9130 throw "unknown header type";
9131 }
9132
9133 template <typename A>
9134 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
9135 {
9136 // get file type
9137 uint32_t fileType = 0;
9138 switch ( fWriter.fOptions.outputKind() ) {
9139 case Options::kDynamicExecutable:
9140 case Options::kStaticExecutable:
9141 fileType = MH_EXECUTE;
9142 break;
9143 case Options::kDynamicLibrary:
9144 fileType = MH_DYLIB;
9145 break;
9146 case Options::kDynamicBundle:
9147 fileType = MH_BUNDLE;
9148 break;
9149 case Options::kObjectFile:
9150 fileType = MH_OBJECT;
9151 break;
9152 case Options::kDyld:
9153 fileType = MH_DYLINKER;
9154 break;
9155 case Options::kPreload:
9156 fileType = MH_PRELOAD;
9157 break;
9158 case Options::kKextBundle:
9159 fileType = MH_KEXT_BUNDLE;
9160 break;
9161 }
9162
9163 // get flags
9164 uint32_t flags = 0;
9165 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
9166 if ( fWriter.fCanScatter )
9167 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
9168 }
9169 else {
9170 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
9171 flags |= MH_NOUNDEFS;
9172 }
9173 else if ( fWriter.fOptions.outputKind() == Options::kPreload ) {
9174 flags |= MH_NOUNDEFS;
9175 if ( fWriter.fOptions.positionIndependentExecutable() )
9176 flags |= MH_PIE;
9177 }
9178 else {
9179 flags = MH_DYLDLINK;
9180 if ( fWriter.fOptions.bindAtLoad() )
9181 flags |= MH_BINDATLOAD;
9182 switch ( fWriter.fOptions.nameSpace() ) {
9183 case Options::kTwoLevelNameSpace:
9184 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
9185 break;
9186 case Options::kFlatNameSpace:
9187 break;
9188 case Options::kForceFlatNameSpace:
9189 flags |= MH_FORCE_FLAT;
9190 break;
9191 }
9192 bool hasWeakDefines = fWriter.fHasWeakExports;
9193 if ( fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->size() != 0 ) {
9194 for(std::set<const ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
9195 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
9196 if ( fWriter.shouldExport(**it) ) {
9197 hasWeakDefines = true;
9198 break;
9199 }
9200 }
9201 }
9202 if ( hasWeakDefines )
9203 flags |= MH_WEAK_DEFINES;
9204 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
9205 flags |= MH_BINDS_TO_WEAK;
9206 if ( fWriter.fOptions.prebind() )
9207 flags |= MH_PREBOUND;
9208 if ( fWriter.fOptions.splitSeg() )
9209 flags |= MH_SPLIT_SEGS;
9210 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
9211 flags |= MH_NO_REEXPORTED_DYLIBS;
9212 if ( fWriter.fOptions.positionIndependentExecutable() )
9213 flags |= MH_PIE;
9214 if ( fWriter.fOptions.markAutoDeadStripDylib() )
9215 flags |= MH_DEAD_STRIPPABLE_DYLIB;
9216 }
9217 if ( fWriter.fOptions.hasExecutableStack() )
9218 flags |= MH_ALLOW_STACK_EXECUTION;
9219 if ( fWriter.fOptions.readerOptions().fRootSafe )
9220 flags |= MH_ROOT_SAFE;
9221 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
9222 flags |= MH_SETUID_SAFE;
9223 }
9224
9225 // get commands info
9226 uint32_t commandsSize = 0;
9227 uint32_t commandsCount = 0;
9228
9229 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
9230 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
9231 ObjectFile::Atom* atom = *it;
9232 commandsSize += atom->getSize();
9233 // segment and symbol table atoms can contain more than one load command
9234 if ( atom == fWriter.fSegmentCommands )
9235 commandsCount += fWriter.fSegmentCommands->commandCount();
9236 else if ( atom == fWriter.fSymbolTableCommands )
9237 commandsCount += fWriter.fSymbolTableCommands->commandCount();
9238 else if ( atom->getSize() != 0 )
9239 ++commandsCount;
9240 }
9241
9242 // fill out mach_header
9243 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
9244 setHeaderInfo(*mh);
9245 mh->set_filetype(fileType);
9246 mh->set_ncmds(commandsCount);
9247 mh->set_sizeofcmds(commandsSize);
9248 mh->set_flags(flags);
9249 }
9250
9251 template <>
9252 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
9253 {
9254 header.set_magic(MH_MAGIC);
9255 header.set_cputype(CPU_TYPE_POWERPC);
9256 header.set_cpusubtype(fWriter.fCpuConstraint);
9257 }
9258
9259 template <>
9260 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
9261 {
9262 header.set_magic(MH_MAGIC_64);
9263 header.set_cputype(CPU_TYPE_POWERPC64);
9264 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9265 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
9266 else
9267 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
9268 header.set_reserved(0);
9269 }
9270
9271 template <>
9272 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
9273 {
9274 header.set_magic(MH_MAGIC);
9275 header.set_cputype(CPU_TYPE_I386);
9276 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
9277 }
9278
9279 template <>
9280 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
9281 {
9282 header.set_magic(MH_MAGIC_64);
9283 header.set_cputype(CPU_TYPE_X86_64);
9284 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9285 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
9286 else
9287 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
9288 header.set_reserved(0);
9289 }
9290
9291 template <>
9292 void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
9293 {
9294 header.set_magic(MH_MAGIC);
9295 header.set_cputype(CPU_TYPE_ARM);
9296 header.set_cpusubtype(fWriter.fCpuConstraint);
9297 }
9298
9299 template <typename A>
9300 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
9301 : WriterAtom<A>(writer, Segment::fgStackSegment)
9302 {
9303 if ( stackGrowsDown() )
9304 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
9305 else
9306 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
9307 }
9308
9309
9310 template <> bool CustomStackAtom<ppc>::stackGrowsDown() { return true; }
9311 template <> bool CustomStackAtom<ppc64>::stackGrowsDown() { return true; }
9312 template <> bool CustomStackAtom<x86>::stackGrowsDown() { return true; }
9313 template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
9314 template <> bool CustomStackAtom<arm>::stackGrowsDown() { return true; }
9315
9316 template <typename A>
9317 void SegmentLoadCommandsAtom<A>::computeSize()
9318 {
9319 uint64_t size = 0;
9320 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9321 int segCount = 0;
9322 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9323 SegmentInfo* seg = *it;
9324 if ( seg->fHasLoadCommand ) {
9325 ++segCount;
9326 size += sizeof(macho_segment_command<P>);
9327 std::vector<SectionInfo*>& sectionInfos = seg->fSections;
9328 const int sectionCount = sectionInfos.size();
9329 for(int j=0; j < sectionCount; ++j) {
9330 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
9331 size += sizeof(macho_section<P>);
9332 }
9333 }
9334 }
9335 fSize = size;
9336 fCommandCount = segCount;
9337 if ( fWriter.fPadSegmentInfo != NULL ) {
9338 ++fCommandCount;
9339 fSize += sizeof(macho_segment_command<P>);
9340 }
9341 }
9342
9343 template <>
9344 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
9345 {
9346 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9347 }
9348
9349 template <>
9350 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
9351 {
9352 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9353 }
9354
9355 template <>
9356 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
9357 {
9358 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9359 }
9360
9361 template <>
9362 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
9363 {
9364 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
9365 }
9366
9367 template <>
9368 uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
9369 {
9370 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
9371 }
9372
9373 template <typename A>
9374 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9375 {
9376 uint64_t size = this->getSize();
9377 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
9378 bzero(buffer, size);
9379 uint8_t* p = buffer;
9380 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
9381 for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
9382 SegmentInfo* segInfo = *it;
9383 if ( ! segInfo->fHasLoadCommand )
9384 continue;
9385 const int sectionCount = segInfo->fSections.size();
9386 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
9387 cmd->set_cmd(macho_segment_command<P>::CMD);
9388 cmd->set_segname(segInfo->fName);
9389 cmd->set_vmaddr(segInfo->fBaseAddress);
9390 cmd->set_vmsize(oneSegment ? 0 : segInfo->fSize);
9391 cmd->set_fileoff(segInfo->fFileOffset);
9392 cmd->set_filesize(oneSegment ? 0 : segInfo->fFileSize);
9393 cmd->set_maxprot(segInfo->fMaxProtection);
9394 cmd->set_initprot(segInfo->fInitProtection);
9395 // add sections array
9396 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
9397 unsigned int sectionsEmitted = 0;
9398 for (int j=0; j < sectionCount; ++j) {
9399 SectionInfo* sectInfo = segInfo->fSections[j];
9400 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
9401 macho_section<P>* sect = &sections[sectionsEmitted++];
9402 if ( oneSegment ) {
9403 // .o file segment does not cover load commands, so recalc at first real section
9404 if ( sectionsEmitted == 1 ) {
9405 cmd->set_vmaddr(sectInfo->getBaseAddress());
9406 cmd->set_fileoff(sectInfo->fFileOffset);
9407 }
9408 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
9409 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
9410 }
9411 sect->set_sectname(sectInfo->fSectionName);
9412 sect->set_segname(sectInfo->fSegmentName);
9413 sect->set_addr(sectInfo->getBaseAddress());
9414 sect->set_size(sectInfo->fSize);
9415 sect->set_offset(sectInfo->fFileOffset);
9416 sect->set_align(sectInfo->fAlignment);
9417 if ( sectInfo->fRelocCount != 0 ) {
9418 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
9419 sect->set_nreloc(sectInfo->fRelocCount);
9420 }
9421 if ( sectInfo->fAllZeroFill ) {
9422 sect->set_flags(S_ZEROFILL);
9423 sect->set_offset(0);
9424 }
9425 else if ( sectInfo->fAllLazyPointers ) {
9426 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
9427 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9428 }
9429 else if ( sectInfo->fAllLazyDylibPointers ) {
9430 sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
9431 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9432 }
9433 else if ( sectInfo->fAllNonLazyPointers ) {
9434 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
9435 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9436 }
9437 else if ( sectInfo->fAllStubs ) {
9438 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9439 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9440 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9441 if ( sectInfo->fHasTextLocalRelocs )
9442 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9443 }
9444 else if ( sectInfo->fAllSelfModifyingStubs ) {
9445 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
9446 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
9447 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
9448 }
9449 else if ( sectInfo->fAllStubHelpers ) {
9450 sect->set_flags(S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9451 if ( sectInfo->fHasTextLocalRelocs )
9452 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9453 }
9454 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCStringType ) {
9455 sect->set_flags(S_CSTRING_LITERALS);
9456 }
9457 else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCFIType ) {
9458 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
9459 }
9460 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9461 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
9462 }
9463 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9464 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
9465 }
9466 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9467 sect->set_flags(S_COALESCED);
9468 }
9469 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9470 sect->set_flags(S_COALESCED);
9471 }
9472 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9473 sect->set_flags(S_INTERPOSING);
9474 }
9475 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9476 sect->set_flags(S_4BYTE_LITERALS);
9477 }
9478 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9479 sect->set_flags(S_8BYTE_LITERALS);
9480 }
9481 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9482 sect->set_flags(S_16BYTE_LITERALS);
9483 }
9484 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9485 sect->set_flags(S_LITERAL_POINTERS);
9486 }
9487 else if ( (strcmp(sectInfo->fSectionName, "__objc_selrefs") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9488 sect->set_flags(S_LITERAL_POINTERS);
9489 }
9490 else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
9491 sect->set_flags(S_LITERAL_POINTERS);
9492 }
9493 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9494 sect->set_flags(S_DTRACE_DOF);
9495 }
9496 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
9497 sect->set_flags(S_DTRACE_DOF);
9498 }
9499 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
9500 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
9501 if ( sectInfo->fHasTextLocalRelocs )
9502 sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
9503 if ( sectInfo->fHasTextExternalRelocs )
9504 sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
9505 }
9506 //fprintf(stderr, "section %s flags=0x%08X\n", sectInfo->fSectionName, sect->flags());
9507 }
9508 }
9509 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
9510 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
9511 cmd->set_nsects(sectionsEmitted);
9512 }
9513 }
9514
9515
9516 template <typename A>
9517 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
9518 : LoadCommandAtom<A>(writer), fNeedsDynamicSymbolTable(false)
9519 {
9520 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
9521 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
9522 switch ( fWriter.fOptions.outputKind() ) {
9523 case Options::kDynamicExecutable:
9524 case Options::kDynamicLibrary:
9525 case Options::kDynamicBundle:
9526 case Options::kDyld:
9527 case Options::kKextBundle:
9528 fNeedsDynamicSymbolTable = true;
9529 break;
9530 case Options::kObjectFile:
9531 case Options::kStaticExecutable:
9532 fNeedsDynamicSymbolTable = false;
9533 case Options::kPreload:
9534 fNeedsDynamicSymbolTable = fWriter.fOptions.positionIndependentExecutable();
9535 break;
9536 }
9537 writer.fSymbolTableCommands = this;
9538 }
9539
9540
9541
9542 template <typename A>
9543 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
9544 {
9545 fNeedsDynamicSymbolTable = true;
9546 }
9547
9548
9549 template <typename A>
9550 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
9551 {
9552 if ( fNeedsDynamicSymbolTable )
9553 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
9554 else
9555 return this->alignedSize(sizeof(macho_symtab_command<P>));
9556 }
9557
9558 template <typename A>
9559 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9560 {
9561 // build LC_SYMTAB command
9562 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
9563 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
9564 symbolTableCmd->set_cmd(LC_SYMTAB);
9565 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
9566 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
9567 symbolTableCmd->set_symoff(fWriter.fSymbolTableCount == 0 ? 0 : fWriter.fSymbolTableAtom->getFileOffset());
9568 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getSize() == 0 ? 0 : fWriter.fStringsAtom->getFileOffset());
9569 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
9570
9571 // build LC_DYSYMTAB command
9572 if ( fNeedsDynamicSymbolTable ) {
9573 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
9574 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
9575 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
9576 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
9577 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
9578 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
9579 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
9580 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
9581 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
9582 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
9583 if ( fWriter.fModuleInfoAtom != NULL ) {
9584 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
9585 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
9586 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
9587 dynamicSymbolTableCmd->set_nmodtab(1);
9588 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
9589 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
9590 }
9591 dynamicSymbolTableCmd->set_indirectsymoff((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->getFileOffset());
9592 dynamicSymbolTableCmd->set_nindirectsyms((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->fTable.size());
9593 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
9594 if ( fWriter.fExternalRelocationsAtom != 0 ) {
9595 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
9596 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
9597 }
9598 if ( fWriter.fLocalRelocationsAtom != 0 ) {
9599 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
9600 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
9601 }
9602 }
9603 }
9604 }
9605
9606
9607 template <typename A>
9608 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
9609 {
9610 return fNeedsDynamicSymbolTable ? 2 : 1;
9611 }
9612
9613 template <typename A>
9614 uint64_t DyldLoadCommandsAtom<A>::getSize() const
9615 {
9616 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
9617 }
9618
9619 template <typename A>
9620 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9621 {
9622 uint64_t size = this->getSize();
9623 bzero(buffer, size);
9624 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
9625 if ( fWriter.fOptions.outputKind() == Options::kDyld )
9626 cmd->set_cmd(LC_ID_DYLINKER);
9627 else
9628 cmd->set_cmd(LC_LOAD_DYLINKER);
9629 cmd->set_cmdsize(this->getSize());
9630 cmd->set_name_offset();
9631 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
9632 }
9633
9634 template <typename A>
9635 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
9636 {
9637 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
9638 }
9639
9640 template <typename A>
9641 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9642 {
9643 uint64_t size = this->getSize();
9644
9645 bzero(buffer, size);
9646 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
9647 cmd->set_cmd(LC_SUB_CLIENT);
9648 cmd->set_cmdsize(size);
9649 cmd->set_client_offset();
9650 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
9651
9652 }
9653
9654 template <typename A>
9655 uint64_t DylibLoadCommandsAtom<A>::getSize() const
9656 {
9657 if ( fOptimizedAway ) {
9658 return 0;
9659 }
9660 else {
9661 const char* path = fInfo.reader->getInstallPath();
9662 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
9663 }
9664 }
9665
9666 template <typename A>
9667 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9668 {
9669 if ( fOptimizedAway )
9670 return;
9671 uint64_t size = this->getSize();
9672 bzero(buffer, size);
9673 const char* path = fInfo.reader->getInstallPath();
9674 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9675 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
9676 bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0)
9677 && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
9678 if ( fInfo.options.fLazyLoad )
9679 cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
9680 else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
9681 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
9682 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
9683 cmd->set_cmd(LC_REEXPORT_DYLIB);
9684 else
9685 cmd->set_cmd(LC_LOAD_DYLIB);
9686 cmd->set_cmdsize(this->getSize());
9687 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
9688 cmd->set_current_version(fInfo.reader->getCurrentVersion());
9689 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
9690 cmd->set_name_offset();
9691 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
9692 }
9693
9694
9695
9696 template <typename A>
9697 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
9698 {
9699 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
9700 }
9701
9702 template <typename A>
9703 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9704 {
9705 uint64_t size = this->getSize();
9706 bzero(buffer, size);
9707 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
9708 cmd->set_cmd(LC_ID_DYLIB);
9709 cmd->set_cmdsize(this->getSize());
9710 cmd->set_name_offset();
9711 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
9712 cmd->set_current_version(fWriter.fOptions.currentVersion());
9713 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
9714 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
9715 }
9716
9717
9718 template <typename A>
9719 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9720 {
9721 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9722 if (fWriter.fEntryPoint->isThumb())
9723 initAddr |= 1ULL;
9724 bzero(buffer, sizeof(macho_routines_command<P>));
9725 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
9726 cmd->set_cmd(macho_routines_command<P>::CMD);
9727 cmd->set_cmdsize(this->getSize());
9728 cmd->set_init_address(initAddr);
9729 }
9730
9731
9732 template <typename A>
9733 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
9734 {
9735 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
9736 }
9737
9738 template <typename A>
9739 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9740 {
9741 uint64_t size = this->getSize();
9742 bzero(buffer, size);
9743 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
9744 cmd->set_cmd(LC_SUB_UMBRELLA);
9745 cmd->set_cmdsize(this->getSize());
9746 cmd->set_sub_umbrella_offset();
9747 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
9748 }
9749
9750 template <typename A>
9751 void UUIDLoadCommandAtom<A>::generate()
9752 {
9753 switch ( fWriter.fOptions.getUUIDMode() ) {
9754 case Options::kUUIDNone:
9755 fEmit = false;
9756 break;
9757 case Options::kUUIDRandom:
9758 ::uuid_generate_random(fUUID);
9759 fEmit = true;
9760 break;
9761 case Options::kUUIDContent:
9762 bzero(fUUID, 16);
9763 fEmit = true;
9764 break;
9765 }
9766 }
9767
9768 template <typename A>
9769 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
9770 {
9771 memcpy(fUUID, uuid, 16);
9772 }
9773
9774 template <typename A>
9775 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
9776 {
9777 if (fEmit) {
9778 uint64_t size = this->getSize();
9779 bzero(buffer, size);
9780 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
9781 cmd->set_cmd(LC_UUID);
9782 cmd->set_cmdsize(this->getSize());
9783 cmd->set_uuid((uint8_t*)fUUID);
9784 }
9785 }
9786
9787
9788 template <typename A>
9789 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
9790 {
9791 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
9792 }
9793
9794 template <typename A>
9795 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9796 {
9797 uint64_t size = this->getSize();
9798 bzero(buffer, size);
9799 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
9800 cmd->set_cmd(LC_SUB_LIBRARY);
9801 cmd->set_cmdsize(this->getSize());
9802 cmd->set_sub_library_offset();
9803 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
9804 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
9805 }
9806
9807 template <typename A>
9808 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
9809 {
9810 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
9811 }
9812
9813 template <typename A>
9814 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9815 {
9816 uint64_t size = this->getSize();
9817 bzero(buffer, size);
9818 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
9819 cmd->set_cmd(LC_SUB_FRAMEWORK);
9820 cmd->set_cmdsize(this->getSize());
9821 cmd->set_umbrella_offset();
9822 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
9823 }
9824
9825 template <>
9826 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
9827 {
9828 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
9829 }
9830
9831 template <>
9832 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
9833 {
9834 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
9835 }
9836
9837 template <>
9838 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
9839 {
9840 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
9841 }
9842
9843 template <>
9844 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
9845 {
9846 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
9847 }
9848
9849 // We should be picking it up from a header
9850 template <>
9851 uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
9852 {
9853 return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
9854 }
9855
9856 template <>
9857 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
9858 {
9859 uint64_t size = this->getSize();
9860 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9861 bzero(buffer, size);
9862 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
9863 cmd->set_cmd(LC_UNIXTHREAD);
9864 cmd->set_cmdsize(size);
9865 cmd->set_flavor(1); // PPC_THREAD_STATE
9866 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
9867 cmd->set_thread_register(0, start);
9868 if ( fWriter.fOptions.hasCustomStack() )
9869 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
9870 }
9871
9872
9873 template <>
9874 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
9875 {
9876 uint64_t size = this->getSize();
9877 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9878 bzero(buffer, size);
9879 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
9880 cmd->set_cmd(LC_UNIXTHREAD);
9881 cmd->set_cmdsize(size);
9882 cmd->set_flavor(5); // PPC_THREAD_STATE64
9883 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
9884 cmd->set_thread_register(0, start);
9885 if ( fWriter.fOptions.hasCustomStack() )
9886 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
9887 }
9888
9889 template <>
9890 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
9891 {
9892 uint64_t size = this->getSize();
9893 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9894 bzero(buffer, size);
9895 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
9896 cmd->set_cmd(LC_UNIXTHREAD);
9897 cmd->set_cmdsize(size);
9898 cmd->set_flavor(1); // i386_THREAD_STATE
9899 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
9900 cmd->set_thread_register(10, start);
9901 if ( fWriter.fOptions.hasCustomStack() )
9902 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
9903 }
9904
9905 template <>
9906 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
9907 {
9908 uint64_t size = this->getSize();
9909 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9910 bzero(buffer, size);
9911 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
9912 cmd->set_cmd(LC_UNIXTHREAD);
9913 cmd->set_cmdsize(size);
9914 cmd->set_flavor(x86_THREAD_STATE64);
9915 cmd->set_count(x86_THREAD_STATE64_COUNT);
9916 cmd->set_thread_register(16, start); // rip
9917 if ( fWriter.fOptions.hasCustomStack() )
9918 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
9919 }
9920
9921 template <>
9922 void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
9923 {
9924 uint64_t size = this->getSize();
9925 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
9926 if ( fWriter.fEntryPoint->isThumb() )
9927 start |= 1ULL;
9928 bzero(buffer, size);
9929 macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
9930 cmd->set_cmd(LC_UNIXTHREAD);
9931 cmd->set_cmdsize(size);
9932 cmd->set_flavor(1);
9933 cmd->set_count(17);
9934 cmd->set_thread_register(15, start); // pc
9935 if ( fWriter.fOptions.hasCustomStack() )
9936 cmd->set_thread_register(13, fWriter.fOptions.customStackAddr()); // FIXME: sp?
9937 }
9938
9939 template <typename A>
9940 uint64_t RPathLoadCommandsAtom<A>::getSize() const
9941 {
9942 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
9943 }
9944
9945 template <typename A>
9946 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9947 {
9948 uint64_t size = this->getSize();
9949 bzero(buffer, size);
9950 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
9951 cmd->set_cmd(LC_RPATH);
9952 cmd->set_cmdsize(this->getSize());
9953 cmd->set_path_offset();
9954 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
9955 }
9956
9957
9958
9959 template <typename A>
9960 void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
9961 {
9962 uint64_t size = this->getSize();
9963 bzero(buffer, size);
9964 macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
9965 cmd->set_cmd(LC_ENCRYPTION_INFO);
9966 cmd->set_cmdsize(this->getSize());
9967 cmd->set_cryptoff(fStartOffset);
9968 cmd->set_cryptsize(fEndOffset-fStartOffset);
9969 cmd->set_cryptid(0);
9970 }
9971
9972
9973
9974 template <typename A>
9975 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
9976 {
9977 bzero(buffer, fSize);
9978 }
9979
9980 template <typename A>
9981 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
9982 {
9983 fSize = newSize;
9984 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
9985 if ( fWriter.fLargestAtomSize < newSize )
9986 fWriter.fLargestAtomSize = newSize;
9987 }
9988
9989 template <typename A>
9990 void UnwindInfoAtom<A>::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding,
9991 ObjectFile::Reference* lsdaRef, ObjectFile::Atom* personalityPointer)
9992 {
9993 Info info;
9994 info.func = func;
9995 if ( lsdaRef != NULL ) {
9996 info.lsda = &lsdaRef->getTarget();
9997 info.lsdaOffset = lsdaRef->getTargetOffset();
9998 }
9999 else {
10000 info.lsda = NULL;
10001 info.lsdaOffset = 0;
10002 }
10003 info.personalityPointer = personalityPointer;
10004 info.encoding = encoding;
10005 fInfos.push_back(info);
10006 //fprintf(stderr, "addUnwindInfo() encoding=0x%08X, lsda=%p, lsdaOffset=%d, person=%p, func=%s\n",
10007 // encoding, info.lsda, info.lsdaOffset, personalityPointer, func->getDisplayName());
10008 }
10009
10010
10011 template <typename A>
10012 void UnwindInfoAtom<A>::compressDuplicates(std::vector<Info>& uniqueInfos)
10013 {
10014 // build new list removing entries where next function has same encoding
10015 uniqueInfos.reserve(fInfos.size());
10016 Info last;
10017 last.func = NULL;
10018 last.lsda = NULL;
10019 last.lsdaOffset = 0;
10020 last.personalityPointer = NULL;
10021 last.encoding = 0xFFFFFFFF;
10022 for(typename std::vector<Info>::iterator it=fInfos.begin(); it != fInfos.end(); ++it) {
10023 Info newInfo = *it;
10024 // remove infos which have same encoding and personalityPointer as last one
10025 if ( (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer)
10026 || (newInfo.lsda != NULL) || (last.lsda != NULL) ) {
10027 uniqueInfos.push_back(newInfo);
10028 }
10029 last = newInfo;
10030 }
10031 //fprintf(stderr, "compressDuplicates() fInfos.size()=%lu, uniqueInfos.size()=%lu\n", fInfos.size(), uniqueInfos.size());
10032 }
10033
10034 template <typename A>
10035 void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings)
10036 {
10037 // scan infos to get frequency counts for each encoding
10038 std::map<uint32_t, unsigned int> encodingsUsed;
10039 unsigned int mostCommonEncodingUsageCount = 0;
10040 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10041 std::map<uint32_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
10042 if ( pos == encodingsUsed.end() ) {
10043 encodingsUsed[it->encoding] = 1;
10044 }
10045 else {
10046 encodingsUsed[it->encoding] += 1;
10047 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
10048 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
10049 }
10050 }
10051 // put the most common encodings into the common table, but at most 127 of them
10052 for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
10053 for (std::map<uint32_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
10054 if ( euit->second == usages ) {
10055 unsigned int size = commonEncodings.size();
10056 if ( size < 127 ) {
10057 commonEncodings[euit->first] = size;
10058 }
10059 }
10060 }
10061 }
10062 }
10063
10064 template <typename A>
10065 void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap)
10066 {
10067 for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10068 lsdaIndexOffsetMap[it->func] = fLSDAIndex.size() * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10069 if ( it->lsda != NULL ) {
10070 LSDAEntry entry;
10071 entry.func = it->func;
10072 entry.lsda = it->lsda;
10073 entry.lsdaOffset = it->lsdaOffset;
10074 fLSDAIndex.push_back(entry);
10075 }
10076 }
10077 }
10078
10079 template <typename A>
10080 void UnwindInfoAtom<A>::makePersonalityIndex(std::vector<Info>& uniqueInfos)
10081 {
10082 for(typename std::vector<Info>::iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
10083 if ( it->personalityPointer != NULL ) {
10084 std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fPersonalityIndexMap.find(it->personalityPointer);
10085 if ( pos == fPersonalityIndexMap.end() ) {
10086 const uint32_t nextIndex = fPersonalityIndexMap.size() + 1;
10087 fPersonalityIndexMap[it->personalityPointer] = nextIndex;
10088 }
10089 uint32_t personalityIndex = fPersonalityIndexMap[it->personalityPointer];
10090 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
10091 }
10092 }
10093 }
10094
10095 template <typename A>
10096 unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize,
10097 unsigned int endIndex, uint8_t*& pageEnd)
10098 {
10099 const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10100 const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
10101 uint8_t* pageStart = pageEnd
10102 - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
10103 - sizeof(unwind_info_regular_second_level_page_header);
10104 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
10105 page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
10106 page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
10107 page->set_entryCount(entriesToAdd);
10108 macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
10109 for (unsigned int i=0; i < entriesToAdd; ++i) {
10110 const Info& info = uniqueInfos[endIndex-entriesToAdd+i];
10111 entryTable[i].set_functionOffset(0);
10112 entryTable[i].set_encoding(info.encoding);
10113 RegFixUp fixup;
10114 fixup.contentPointer = (uint8_t*)(&entryTable[i]);
10115 fixup.func = info.func;
10116 fRegFixUps.push_back(fixup);
10117 }
10118 //fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
10119 pageEnd = pageStart;
10120 return endIndex - entriesToAdd;
10121 }
10122
10123
10124 template <typename A>
10125 unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,
10126 const std::map<uint32_t,unsigned int> commonEncodings,
10127 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
10128 {
10129 const bool log = false;
10130 // first pass calculates how many compressed entries we could fit in this sized page
10131 // keep adding entries to page until:
10132 // 1) encoding table plus entry table plus header exceed page size
10133 // 2) the file offset delta from the first to last function > 24 bits
10134 // 3) custom encoding index reachs 255
10135 // 4) run out of uniqueInfos to encode
10136 std::map<uint32_t, unsigned int> pageSpecificEncodings;
10137 uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
10138 std::vector<uint8_t> encodingIndexes;
10139 int index = endIndex-1;
10140 int entryCount = 0;
10141 uint64_t lastEntryAddress = uniqueInfos[index].func->getAddress();
10142 bool canDo = true;
10143 while ( canDo && (index >= 0) ) {
10144 const Info& info = uniqueInfos[index--];
10145 // compute encoding index
10146 unsigned int encodingIndex;
10147 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10148 if ( pos != commonEncodings.end() ) {
10149 encodingIndex = pos->second;
10150 }
10151 else {
10152 std::map<uint32_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(info.encoding);
10153 if ( ppos != pageSpecificEncodings.end() ) {
10154 encodingIndex = pos->second;
10155 }
10156 else {
10157 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
10158 if ( encodingIndex <= 255 ) {
10159 pageSpecificEncodings[info.encoding] = encodingIndex;
10160 }
10161 else {
10162 canDo = false; // case 3)
10163 if (log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
10164 entryCount, pageSpecificEncodings.size());
10165 }
10166 }
10167 }
10168 if ( canDo )
10169 encodingIndexes.push_back(encodingIndex);
10170 // compute function offset
10171 uint32_t funcOffsetWithInPage = lastEntryAddress - info.func->getAddress();
10172 if ( funcOffsetWithInPage > 0x00FFFF00 ) {
10173 // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
10174 canDo = false; // case 2)
10175 if (log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
10176 }
10177 else {
10178 ++entryCount;
10179 }
10180 // check room for entry
10181 if ( (pageSpecificEncodings.size()+entryCount) > space4 ) {
10182 canDo = false; // case 1)
10183 --entryCount;
10184 if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
10185 }
10186 }
10187
10188 // sanity check that we fit more entries into this page than a regular page would hold
10189 const int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
10190 + pageSpecificEncodings.size()*sizeof(uint32_t)
10191 + entryCount*sizeof(uint32_t);
10192 const int regularEntriesPerPage = (compressPageUsed - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10193 if ( entryCount < regularEntriesPerPage ) {
10194 return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
10195 }
10196
10197 // second pass fills in page
10198 uint8_t* pageStart = pageEnd - compressPageUsed;
10199 macho_unwind_info_compressed_second_level_page_header<P>* page = (macho_unwind_info_compressed_second_level_page_header<P>*)pageStart;
10200 page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
10201 page->set_entryPageOffset(sizeof(macho_unwind_info_compressed_second_level_page_header<P>));
10202 page->set_entryCount(entryCount);
10203 page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
10204 page->set_encodingsCount(pageSpecificEncodings.size());
10205 // fill in entry table
10206 uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
10207 ObjectFile::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
10208 for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
10209 const Info& info = uniqueInfos[i];
10210 uint8_t encodingIndex;
10211 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
10212 if ( pos != commonEncodings.end() )
10213 encodingIndex = pos->second;
10214 else
10215 encodingIndex = pageSpecificEncodings[info.encoding];
10216 uint32_t entryIndex = i - endIndex + entryCount;
10217 A::P::E::set32(entiresArray[entryIndex], encodingIndex << 24);
10218 CompressedFixUp fixup;
10219 fixup.contentPointer = (uint8_t*)(&entiresArray[entryIndex]);
10220 fixup.func = info.func;
10221 fixup.fromFunc = firstFunc;
10222 fCompressedFixUps.push_back(fixup);
10223 }
10224 // fill in encodings table
10225 uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
10226 for(std::map<uint32_t, unsigned int>::iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
10227 A::P::E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
10228 }
10229
10230 if (log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
10231
10232 // update pageEnd;
10233 pageEnd = pageStart;
10234 return endIndex-entryCount; // endIndex for next page
10235 }
10236
10237 template <> void UnwindInfoAtom<ppc>::generate() { }
10238 template <> void UnwindInfoAtom<ppc64>::generate() { }
10239 template <> void UnwindInfoAtom<arm>::generate() { }
10240
10241
10242 template <typename A>
10243 void UnwindInfoAtom<A>::generate()
10244 {
10245 // only generate table if there are functions with unwind info
10246 if ( fInfos.size() > 0 ) {
10247 // find offset of end of __unwind_info section
10248 SectionInfo* unwindSectionInfo = (SectionInfo*)this->getSection();
10249
10250 // build new list that has proper offsetInImage and remove entries where next function has same encoding
10251 std::vector<Info> uniqueInfos;
10252 this->compressDuplicates(uniqueInfos);
10253
10254 // build personality index, update encodings with personality index
10255 this->makePersonalityIndex(uniqueInfos);
10256 if ( fPersonalityIndexMap.size() > 3 )
10257 throw "too many personality routines for compact unwind to encode";
10258
10259 // put the most common encodings into the common table, but at most 127 of them
10260 std::map<uint32_t, unsigned int> commonEncodings;
10261 this->findCommonEncoding(uniqueInfos, commonEncodings);
10262
10263 // build lsda index
10264 std::map<ObjectFile::Atom*, uint32_t> lsdaIndexOffsetMap;
10265 this->makeLsdaIndex(uniqueInfos, lsdaIndexOffsetMap);
10266
10267 // calculate worst case size for all unwind info pages when allocating buffer
10268 const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
10269 const unsigned int pageCount = ((uniqueInfos.size() - 1)/entriesPerRegularPage) + 1;
10270 fPagesContentForDelete = (uint8_t*)calloc(pageCount,4096);
10271 fPagesSize = 0;
10272 if ( fPagesContentForDelete == NULL )
10273 throw "could not allocate space for compact unwind info";
10274 ObjectFile::Atom* secondLevelFirstFuncs[pageCount];
10275 uint8_t* secondLevelPagesStarts[pageCount];
10276
10277 // make last second level page smaller so that all other second level pages can be page aligned
10278 uint32_t maxLastPageSize = unwindSectionInfo->fFileOffset % 4096;
10279 uint32_t tailPad = 0;
10280 if ( maxLastPageSize < 128 ) {
10281 tailPad = maxLastPageSize;
10282 maxLastPageSize = 4096;
10283 }
10284
10285 // fill in pages in reverse order
10286 unsigned int endIndex = uniqueInfos.size();
10287 unsigned int secondLevelPageCount = 0;
10288 uint8_t* pageEnd = &fPagesContentForDelete[pageCount*4096];
10289 uint32_t pageSize = maxLastPageSize;
10290 while ( endIndex > 0 ) {
10291 endIndex = makeCompressedSecondLevelPage(uniqueInfos, commonEncodings, pageSize, endIndex, pageEnd);
10292 secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
10293 secondLevelFirstFuncs[secondLevelPageCount] = uniqueInfos[endIndex].func;
10294 ++secondLevelPageCount;
10295 pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
10296 }
10297 fPagesContent = pageEnd;
10298 fPagesSize = &fPagesContentForDelete[pageCount*4096] - pageEnd;
10299
10300 // calculate section layout
10301 const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
10302 const uint32_t commonEncodingsArrayCount = commonEncodings.size();
10303 const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
10304 const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
10305 const uint32_t personalityArrayCount = fPersonalityIndexMap.size();
10306 const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
10307 const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
10308 const uint32_t indexCount = secondLevelPageCount+1;
10309 const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
10310 const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
10311 const uint32_t lsdaIndexArrayCount = fLSDAIndex.size();
10312 const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
10313 const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
10314
10315
10316 // allocate and fill in section header
10317 fHeaderSize = headerEndSectionOffset;
10318 fHeaderContent = new uint8_t[fHeaderSize];
10319 bzero(fHeaderContent, fHeaderSize);
10320 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)fHeaderContent;
10321 sectionHeader->set_version(UNWIND_SECTION_VERSION);
10322 sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
10323 sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
10324 sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
10325 sectionHeader->set_personalityArrayCount(personalityArrayCount);
10326 sectionHeader->set_indexSectionOffset(indexSectionOffset);
10327 sectionHeader->set_indexCount(indexCount);
10328
10329 // copy common encodings
10330 uint32_t* commonEncodingsTable = (uint32_t*)&fHeaderContent[commonEncodingsArraySectionOffset];
10331 for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
10332 A::P::E::set32(commonEncodingsTable[it->second], it->first);
10333
10334 // make references for personality entries
10335 uint32_t* personalityArray = (uint32_t*)&fHeaderContent[sectionHeader->personalityArraySectionOffset()];
10336 for (std::map<ObjectFile::Atom*, unsigned int>::iterator it=fPersonalityIndexMap.begin(); it != fPersonalityIndexMap.end(); ++it) {
10337 uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - fHeaderContent;
10338 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->first));
10339 }
10340
10341 // build first level index and references
10342 macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&fHeaderContent[indexSectionOffset];
10343 for (unsigned int i=0; i < secondLevelPageCount; ++i) {
10344 unsigned int reverseIndex = secondLevelPageCount - 1 - i;
10345 indexTable[i].set_functionOffset(0);
10346 indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-fPagesContent+headerEndSectionOffset);
10347 indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
10348 uint32_t refOffset = (uint8_t*)&indexTable[i] - fHeaderContent;
10349 fReferences.push_back(new WriterReference<A>(refOffset, A::kImageOffset32, secondLevelFirstFuncs[reverseIndex]));
10350 }
10351 indexTable[secondLevelPageCount].set_functionOffset(0);
10352 indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
10353 indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
10354 fReferences.push_back(new WriterReference<A>((uint8_t*)&indexTable[secondLevelPageCount] - fHeaderContent, A::kImageOffset32,
10355 fInfos.back().func, fInfos.back().func->getSize()+1));
10356
10357 // build lsda references
10358 uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
10359 for (typename std::vector<LSDAEntry>::iterator it = fLSDAIndex.begin(); it != fLSDAIndex.end(); ++it) {
10360 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset, A::kImageOffset32, it->func));
10361 fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset+4, A::kImageOffset32, it->lsda, it->lsdaOffset));
10362 lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
10363 }
10364
10365 // make references for regular second level entries
10366 for (typename std::vector<RegFixUp>::iterator it = fRegFixUps.begin(); it != fRegFixUps.end(); ++it) {
10367 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10368 fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->func));
10369 }
10370 // make references for compressed second level entries
10371 for (typename std::vector<CompressedFixUp>::iterator it = fCompressedFixUps.begin(); it != fCompressedFixUps.end(); ++it) {
10372 uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
10373 fReferences.push_back(new WriterReference<A>(offset, A::kPointerDiff24, it->func, 0, it->fromFunc, 0));
10374 }
10375
10376 // update section record with new size
10377 unwindSectionInfo->fSize = this->getSize();
10378
10379 // alter alignment so this section lays out so second level tables are page aligned
10380 if ( secondLevelPageCount > 2 )
10381 fAlignment = ObjectFile::Alignment(12, (unwindSectionInfo->fFileOffset - this->getSize()) % 4096);
10382 }
10383
10384 }
10385
10386
10387
10388
10389 template <typename A>
10390 void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10391 {
10392 memcpy(buffer, fHeaderContent, fHeaderSize);
10393 memcpy(&buffer[fHeaderSize], fPagesContent, fPagesSize);
10394 }
10395
10396
10397
10398 template <typename A>
10399 uint64_t LinkEditAtom<A>::getFileOffset() const
10400 {
10401 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
10402 }
10403
10404
10405 template <typename A>
10406 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
10407 {
10408 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
10409 }
10410
10411 template <typename A>
10412 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10413 {
10414 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
10415 }
10416
10417
10418 template <typename A>
10419 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
10420 {
10421 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
10422 }
10423
10424 template <typename A>
10425 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10426 {
10427 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
10428 }
10429
10430
10431
10432 template <typename A>
10433 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
10434 {
10435 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
10436 }
10437
10438 template <typename A>
10439 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10440 {
10441 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
10442 }
10443
10444 template <typename A>
10445 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
10446 {
10447 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
10448 }
10449
10450 template <typename A>
10451 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10452 {
10453 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
10454 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
10455 }
10456
10457
10458
10459 template <typename A>
10460 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
10461 {
10462 return fTable.size() * sizeof(uint32_t);
10463 }
10464
10465 template <typename A>
10466 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10467 {
10468 uint64_t size = this->getSize();
10469 bzero(buffer, size);
10470 const uint32_t indirectTableSize = fTable.size();
10471 uint32_t* indirectTable = (uint32_t*)buffer;
10472 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
10473 if ( it->indirectIndex < indirectTableSize )
10474 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
10475 else
10476 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
10477 }
10478 }
10479
10480
10481
10482 template <typename A>
10483 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
10484 {
10485 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
10486 + sizeof(macho_dylib_module<P>)
10487 + this->getReferencesCount()*sizeof(uint32_t);
10488 }
10489
10490 template <typename A>
10491 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
10492 {
10493 return this->getFileOffset();
10494 }
10495
10496 template <typename A>
10497 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
10498 {
10499 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
10500 }
10501
10502 template <typename A>
10503 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
10504 {
10505 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
10506 }
10507
10508 template <typename A>
10509 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
10510 {
10511 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
10512 }
10513
10514 template <typename A>
10515 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10516 {
10517 uint64_t size = this->getSize();
10518 bzero(buffer, size);
10519 // create toc. The symbols are already sorted, they are all in the smae module
10520 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
10521 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
10522 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
10523 p->set_module_index(0);
10524 }
10525 // create module table (one entry)
10526 pint_t objcModuleSectionStart = 0;
10527 pint_t objcModuleSectionSize = 0;
10528 uint16_t numInits = 0;
10529 uint16_t numTerms = 0;
10530 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
10531 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
10532 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
10533 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
10534 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10535 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
10536 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10537 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
10538 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
10539 }
10540 }
10541 else if ( strcmp((*segit)->fName, "__OBJC") == 0 ) {
10542 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
10543 SectionInfo* sectInfo = (*sectit);
10544 if ( strcmp(sectInfo->fSectionName, "__module_info") == 0 ) {
10545 objcModuleSectionStart = sectInfo->getBaseAddress();
10546 objcModuleSectionSize = sectInfo->fSize;
10547 }
10548 }
10549 }
10550 }
10551 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
10552 module->set_module_name(fModuleNameOffset);
10553 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
10554 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
10555 module->set_irefsym(0);
10556 module->set_nrefsym(this->getReferencesCount());
10557 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
10558 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
10559 module->set_iextrel(0);
10560 module->set_nextrel(fWriter.fExternalRelocs.size());
10561 module->set_iinit_iterm(0,0);
10562 module->set_ninit_nterm(numInits,numTerms);
10563 module->set_objc_module_info_addr(objcModuleSectionStart);
10564 module->set_objc_module_info_size(objcModuleSectionSize);
10565 // create reference table
10566 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
10567 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
10568 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
10569 ref->set_flags(REFERENCE_FLAG_DEFINED);
10570 }
10571 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
10572 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
10573 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
10574 if ( pos != fWriter.fStubsMap.end() )
10575 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
10576 else
10577 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
10578 }
10579 }
10580
10581
10582
10583 template <typename A>
10584 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
10585 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
10586 {
10587 fCurrentBuffer = new char[kBufferSize];
10588 // burn first byte of string pool (so zero is never a valid string offset)
10589 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
10590 // make offset 1 always point to an empty string
10591 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
10592 }
10593
10594 template <typename A>
10595 uint64_t StringsLinkEditAtom<A>::getSize() const
10596 {
10597 // align size
10598 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
10599 }
10600
10601 template <typename A>
10602 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
10603 {
10604 uint64_t offset = 0;
10605 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
10606 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
10607 offset += kBufferSize;
10608 }
10609 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
10610 // zero fill end to align
10611 offset += fCurrentBufferUsed;
10612 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
10613 buffer[offset++] = 0;
10614 }
10615
10616 template <typename A>
10617 int32_t StringsLinkEditAtom<A>::add(const char* name)
10618 {
10619 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
10620 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
10621 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
10622 fCurrentBufferUsed += lenNeeded;
10623 }
10624 else {
10625 int copied = kBufferSize-fCurrentBufferUsed-1;
10626 // change trailing '\0' that strlcpy added to real char
10627 fCurrentBuffer[kBufferSize-1] = name[copied];
10628 // alloc next buffer
10629 fFullBuffers.push_back(fCurrentBuffer);
10630 fCurrentBuffer = new char[kBufferSize];
10631 fCurrentBufferUsed = 0;
10632 // append rest of string
10633 this->add(&name[copied+1]);
10634 }
10635 return offset;
10636 }
10637
10638
10639 template <typename A>
10640 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
10641 {
10642 StringToOffset::iterator pos = fUniqueStrings.find(name);
10643 if ( pos != fUniqueStrings.end() ) {
10644 return pos->second;
10645 }
10646 else {
10647 int32_t offset = this->add(name);
10648 fUniqueStrings[name] = offset;
10649 return offset;
10650 }
10651 }
10652
10653
10654 template <typename A>
10655 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
10656 {
10657 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
10658 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
10659 // check for out of bounds
10660 if ( index > maxIndex )
10661 return "";
10662 // check for index in fCurrentBuffer
10663 if ( index > currentBufferStartIndex )
10664 return &fCurrentBuffer[index-currentBufferStartIndex];
10665 // otherwise index is in a full buffer
10666 uint32_t fullBufferIndex = index/kBufferSize;
10667 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
10668 }
10669
10670
10671
10672 template <typename A>
10673 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
10674 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
10675 {
10676 char* buf = new char[strlen(name)+32];
10677 if ( targetOffset == 0 ) {
10678 if ( islandRegion == 0 )
10679 sprintf(buf, "%s$island", name);
10680 else
10681 sprintf(buf, "%s$island_%d", name, islandRegion);
10682 }
10683 else {
10684 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
10685 }
10686 fName = buf;
10687 }
10688
10689
10690 template <>
10691 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
10692 {
10693 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
10694 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10695 OSWriteBigInt32(buffer, 0, branchInstruction);
10696 }
10697
10698 template <>
10699 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
10700 {
10701 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
10702 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
10703 OSWriteBigInt32(buffer, 0, branchInstruction);
10704 }
10705
10706 template <>
10707 uint64_t BranchIslandAtom<ppc>::getSize() const
10708 {
10709 return 4;
10710 }
10711
10712 template <>
10713 uint64_t BranchIslandAtom<ppc64>::getSize() const
10714 {
10715 return 4;
10716 }
10717
10718
10719
10720 template <typename A>
10721 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
10722 {
10723 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
10724 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
10725 else
10726 return 0; // a zero size causes the load command to be suppressed
10727 }
10728
10729 template <typename A>
10730 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10731 {
10732 uint64_t size = this->getSize();
10733 if ( size > 0 ) {
10734 bzero(buffer, size);
10735 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
10736 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
10737 cmd->set_cmdsize(size);
10738 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
10739 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
10740 }
10741 }
10742
10743
10744 template <typename A>
10745 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
10746 {
10747 return fEncodedData.size();
10748 }
10749
10750 template <typename A>
10751 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
10752 {
10753 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
10754 }
10755
10756
10757 template <typename A>
10758 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
10759 {
10760 pint_t addr = fWriter.fOptions.baseAddress();
10761 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
10762 pint_t nextAddr = it->atom->getAddress() + it->offset;
10763 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
10764 uint64_t delta = nextAddr - addr;
10765 if ( delta == 0 )
10766 throw "double split seg info for same address";
10767 // uleb128 encode
10768 uint8_t byte;
10769 do {
10770 byte = delta & 0x7F;
10771 delta &= ~0x7F;
10772 if ( delta != 0 )
10773 byte |= 0x80;
10774 fEncodedData.push_back(byte);
10775 delta = delta >> 7;
10776 }
10777 while( byte >= 0x80 );
10778 addr = nextAddr;
10779 }
10780 }
10781
10782 template <typename A>
10783 void SegmentSplitInfoContentAtom<A>::encode()
10784 {
10785 if ( ! fCantEncode ) {
10786 fEncodedData.reserve(8192);
10787
10788 if ( fKind1Locations.size() != 0 ) {
10789 fEncodedData.push_back(1);
10790 //fprintf(stderr, "type 1:\n");
10791 this->uleb128EncodeAddresses(fKind1Locations);
10792 fEncodedData.push_back(0);
10793 }
10794
10795 if ( fKind2Locations.size() != 0 ) {
10796 fEncodedData.push_back(2);
10797 //fprintf(stderr, "type 2:\n");
10798 this->uleb128EncodeAddresses(fKind2Locations);
10799 fEncodedData.push_back(0);
10800 }
10801
10802 if ( fKind3Locations.size() != 0 ) {
10803 fEncodedData.push_back(3);
10804 //fprintf(stderr, "type 3:\n");
10805 this->uleb128EncodeAddresses(fKind3Locations);
10806 fEncodedData.push_back(0);
10807 }
10808
10809 if ( fKind4Locations.size() != 0 ) {
10810 fEncodedData.push_back(4);
10811 //fprintf(stderr, "type 4:\n");
10812 this->uleb128EncodeAddresses(fKind4Locations);
10813 fEncodedData.push_back(0);
10814 }
10815
10816 // always add zero byte to mark end
10817 fEncodedData.push_back(0);
10818
10819 // add zeros to end to align size
10820 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
10821 fEncodedData.push_back(0);
10822 }
10823 }
10824
10825
10826 template <typename A>
10827 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
10828 : WriterAtom<A>(writer, getInfoSegment())
10829 {
10830 fContent[0] = 0;
10831 uint32_t value = 0;
10832 // struct objc_image_info {
10833 // uint32_t version; // initially 0
10834 // uint32_t flags;
10835 // };
10836 // #define OBJC_IMAGE_SUPPORTS_GC 2
10837 // #define OBJC_IMAGE_GC_ONLY 4
10838 //
10839 if ( objcReplacementClasses )
10840 value = 1;
10841 switch ( objcConstraint ) {
10842 case ObjectFile::Reader::kObjcNone:
10843 case ObjectFile::Reader::kObjcRetainRelease:
10844 break;
10845 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
10846 value |= 2;
10847 break;
10848 case ObjectFile::Reader::kObjcGC:
10849 value |= 6;
10850 break;
10851 }
10852 A::P::E::set32(fContent[1], value);
10853 }
10854
10855 template <typename A>
10856 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
10857 {
10858 memcpy(buffer, &fContent[0], 8);
10859 }
10860
10861
10862 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
10863 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
10864 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
10865 template <> const char* ObjCInfoAtom<arm>::getSectionName() const { return "__objc_imageinfo"; }
10866 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
10867 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
10868
10869 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
10870 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
10871 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
10872 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
10873 template <> Segment& ObjCInfoAtom<arm>::getInfoSegment() const { return Segment::fgDataSegment; }
10874
10875
10876
10877
10878 template <typename A>
10879 void DyldInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
10880 {
10881 // build LC_DYLD_INFO command
10882 macho_dyld_info_command<P>* cmd = (macho_dyld_info_command<P>*)buffer;
10883 bzero(cmd, sizeof(macho_dyld_info_command<P>));
10884
10885 cmd->set_cmd( fWriter.fOptions.makeClassicDyldInfo() ? LC_DYLD_INFO : LC_DYLD_INFO_ONLY);
10886 cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
10887 if ( (fWriter.fCompressedRebaseInfoAtom != NULL) && (fWriter.fCompressedRebaseInfoAtom->getSize() != 0) ) {
10888 cmd->set_rebase_off(fWriter.fCompressedRebaseInfoAtom->getFileOffset());
10889 cmd->set_rebase_size(fWriter.fCompressedRebaseInfoAtom->getSize());
10890 }
10891 if ( (fWriter.fCompressedBindingInfoAtom != NULL) && (fWriter.fCompressedBindingInfoAtom->getSize() != 0) ) {
10892 cmd->set_bind_off(fWriter.fCompressedBindingInfoAtom->getFileOffset());
10893 cmd->set_bind_size(fWriter.fCompressedBindingInfoAtom->getSize());
10894 }
10895 if ( (fWriter.fCompressedWeakBindingInfoAtom != NULL) && (fWriter.fCompressedWeakBindingInfoAtom->getSize() != 0) ) {
10896 cmd->set_weak_bind_off(fWriter.fCompressedWeakBindingInfoAtom->getFileOffset());
10897 cmd->set_weak_bind_size(fWriter.fCompressedWeakBindingInfoAtom->getSize());
10898 }
10899 if ( (fWriter.fCompressedLazyBindingInfoAtom != NULL) && (fWriter.fCompressedLazyBindingInfoAtom->getSize() != 0) ) {
10900 cmd->set_lazy_bind_off(fWriter.fCompressedLazyBindingInfoAtom->getFileOffset());
10901 cmd->set_lazy_bind_size(fWriter.fCompressedLazyBindingInfoAtom->getSize());
10902 }
10903 if ( (fWriter.fCompressedExportInfoAtom != NULL) && (fWriter.fCompressedExportInfoAtom->getSize() != 0) ) {
10904 cmd->set_export_off(fWriter.fCompressedExportInfoAtom->getFileOffset());
10905 cmd->set_export_size(fWriter.fCompressedExportInfoAtom->getSize());
10906 }
10907 }
10908
10909
10910 struct rebase_tmp
10911 {
10912 rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
10913 uint8_t opcode;
10914 uint64_t operand1;
10915 uint64_t operand2;
10916 };
10917
10918
10919 template <typename A>
10920 void CompressedRebaseInfoLinkEditAtom<A>::encode()
10921 {
10922 // sort rebase info by type, then address
10923 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
10924 std::vector<RebaseInfo>& info = fWriter.fRebaseInfo;
10925 std::sort(info.begin(), info.end());
10926
10927 // convert to temp encoding that can be more easily optimized
10928 std::vector<rebase_tmp> mid;
10929 const SegmentInfo* currentSegment = NULL;
10930 unsigned int segIndex = 0;
10931 uint8_t type = 0;
10932 uint64_t address = (uint64_t)(-1);
10933 for (std::vector<RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
10934 if ( type != it->fType ) {
10935 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->fType));
10936 type = it->fType;
10937 }
10938 if ( address != it->fAddress ) {
10939 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
10940 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= it->fAddress) ) {
10941 segIndex = 0;
10942 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
10943 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
10944 currentSegment = *segit;
10945 break;
10946 }
10947 ++segIndex;
10948 }
10949 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
10950 }
10951 else {
10952 mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
10953 }
10954 address = it->fAddress;
10955 }
10956 mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
10957 address += sizeof(pint_t);
10958 }
10959 mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
10960
10961 // optimize phase 1, compress packed runs of pointers
10962 rebase_tmp* dst = &mid[0];
10963 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
10964 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
10965 *dst = *src++;
10966 while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
10967 dst->operand1 += src->operand1;
10968 ++src;
10969 }
10970 --src;
10971 ++dst;
10972 }
10973 else {
10974 *dst++ = *src;
10975 }
10976 }
10977 dst->opcode = REBASE_OPCODE_DONE;
10978
10979 // optimize phase 2, combine rebase/add pairs
10980 dst = &mid[0];
10981 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
10982 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
10983 && (src->operand1 == 1)
10984 && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
10985 dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
10986 dst->operand1 = src[1].operand1;
10987 ++src;
10988 ++dst;
10989 }
10990 else {
10991 *dst++ = *src;
10992 }
10993 }
10994 dst->opcode = REBASE_OPCODE_DONE;
10995
10996 // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
10997 // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
10998 dst = &mid[0];
10999 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
11000 uint64_t delta = src->operand1;
11001 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11002 && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11003 && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11004 && (src[1].operand1 == delta)
11005 && (src[2].operand1 == delta) ) {
11006 // found at least three in a row, this is worth compressing
11007 dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
11008 dst->operand1 = 1;
11009 dst->operand2 = delta;
11010 ++src;
11011 while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
11012 && (src->operand1 == delta) ) {
11013 dst->operand1++;
11014 ++src;
11015 }
11016 --src;
11017 ++dst;
11018 }
11019 else {
11020 *dst++ = *src;
11021 }
11022 }
11023 dst->opcode = REBASE_OPCODE_DONE;
11024
11025 // optimize phase 4, use immediate encodings
11026 for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11027 if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB)
11028 && (p->operand1 < (15*sizeof(pint_t)))
11029 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11030 p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
11031 p->operand1 = p->operand1/sizeof(pint_t);
11032 }
11033 else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
11034 p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
11035 }
11036 }
11037
11038 // convert to compressed encoding
11039 const static bool log = false;
11040 fEncodedData.reserve(info.size()*2);
11041 bool done = false;
11042 for (std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11043 switch ( it->opcode ) {
11044 case REBASE_OPCODE_DONE:
11045 if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
11046 done = true;
11047 break;
11048 case REBASE_OPCODE_SET_TYPE_IMM:
11049 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11050 fEncodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
11051 break;
11052 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11053 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11054 fEncodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11055 fEncodedData.append_uleb128(it->operand2);
11056 break;
11057 case REBASE_OPCODE_ADD_ADDR_ULEB:
11058 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11059 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
11060 fEncodedData.append_uleb128(it->operand1);
11061 break;
11062 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
11063 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11064 fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
11065 break;
11066 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
11067 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
11068 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
11069 break;
11070 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
11071 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
11072 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
11073 fEncodedData.append_uleb128(it->operand1);
11074 break;
11075 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
11076 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11077 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
11078 fEncodedData.append_uleb128(it->operand1);
11079 break;
11080 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
11081 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11082 fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
11083 fEncodedData.append_uleb128(it->operand1);
11084 fEncodedData.append_uleb128(it->operand2);
11085 break;
11086 }
11087 }
11088
11089
11090 // align to pointer size
11091 fEncodedData.pad_to_size(sizeof(pint_t));
11092
11093 if (log) fprintf(stderr, "total rebase info size = %ld\n", fEncodedData.size());
11094 }
11095
11096
11097 struct binding_tmp
11098 {
11099 binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
11100 : opcode(op), operand1(p1), operand2(p2), name(s) {}
11101 uint8_t opcode;
11102 uint64_t operand1;
11103 uint64_t operand2;
11104 const char* name;
11105 };
11106
11107
11108
11109 template <typename A>
11110 void CompressedBindingInfoLinkEditAtom<A>::encode()
11111 {
11112 // sort by library, symbol, type, then address
11113 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11114 std::vector<BindingInfo>& info = fWriter.fBindingInfo;
11115 std::sort(info.begin(), info.end());
11116
11117 // convert to temp encoding that can be more easily optimized
11118 std::vector<binding_tmp> mid;
11119 const SegmentInfo* currentSegment = NULL;
11120 unsigned int segIndex = 0;
11121 int ordinal = 0;
11122 const char* symbolName = NULL;
11123 uint8_t type = 0;
11124 uint64_t address = (uint64_t)(-1);
11125 int64_t addend = 0;
11126 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11127 if ( ordinal != it->fLibraryOrdinal ) {
11128 if ( it->fLibraryOrdinal <= 0 ) {
11129 // special lookups are encoded as negative numbers in BindingInfo
11130 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->fLibraryOrdinal));
11131 }
11132 else {
11133 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->fLibraryOrdinal));
11134 }
11135 ordinal = it->fLibraryOrdinal;
11136 }
11137 if ( symbolName != it->fSymbolName ) {
11138 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11139 symbolName = it->fSymbolName;
11140 }
11141 if ( type != it->fType ) {
11142 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11143 type = it->fType;
11144 }
11145 if ( address != it->fAddress ) {
11146 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11147 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress)
11148 || (it->fAddress < address) ) {
11149 segIndex = 0;
11150 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11151 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11152 currentSegment = *segit;
11153 break;
11154 }
11155 ++segIndex;
11156 }
11157 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11158 }
11159 else {
11160 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11161 }
11162 address = it->fAddress;
11163 }
11164 if ( addend != it->fAddend ) {
11165 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11166 addend = it->fAddend;
11167 }
11168 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11169 address += sizeof(pint_t);
11170 }
11171 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11172
11173
11174 // optimize phase 1, combine bind/add pairs
11175 binding_tmp* dst = &mid[0];
11176 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11177 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11178 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11179 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11180 dst->operand1 = src[1].operand1;
11181 ++src;
11182 ++dst;
11183 }
11184 else {
11185 *dst++ = *src;
11186 }
11187 }
11188 dst->opcode = BIND_OPCODE_DONE;
11189
11190 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11191 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11192 dst = &mid[0];
11193 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11194 uint64_t delta = src->operand1;
11195 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11196 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11197 && (src[1].operand1 == delta) ) {
11198 // found at least two in a row, this is worth compressing
11199 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11200 dst->operand1 = 1;
11201 dst->operand2 = delta;
11202 ++src;
11203 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11204 && (src->operand1 == delta) ) {
11205 dst->operand1++;
11206 ++src;
11207 }
11208 --src;
11209 ++dst;
11210 }
11211 else {
11212 *dst++ = *src;
11213 }
11214 }
11215 dst->opcode = BIND_OPCODE_DONE;
11216
11217 // optimize phase 3, use immediate encodings
11218 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11219 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11220 && (p->operand1 < (15*sizeof(pint_t)))
11221 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11222 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11223 p->operand1 = p->operand1/sizeof(pint_t);
11224 }
11225 }
11226 dst->opcode = BIND_OPCODE_DONE;
11227
11228
11229 // convert to compressed encoding
11230 const static bool log = false;
11231 fEncodedData.reserve(info.size()*2);
11232 bool done = false;
11233 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11234 switch ( it->opcode ) {
11235 case BIND_OPCODE_DONE:
11236 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11237 done = true;
11238 break;
11239 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11240 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11241 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11242 break;
11243 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11244 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11245 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11246 fEncodedData.append_uleb128(it->operand1);
11247 break;
11248 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11249 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11250 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11251 break;
11252 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11253 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11254 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11255 fEncodedData.append_string(it->name);
11256 break;
11257 case BIND_OPCODE_SET_TYPE_IMM:
11258 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11259 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11260 break;
11261 case BIND_OPCODE_SET_ADDEND_SLEB:
11262 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11263 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11264 fEncodedData.append_sleb128(it->operand1);
11265 break;
11266 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11267 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11268 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11269 fEncodedData.append_uleb128(it->operand2);
11270 break;
11271 case BIND_OPCODE_ADD_ADDR_ULEB:
11272 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11273 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11274 fEncodedData.append_uleb128(it->operand1);
11275 break;
11276 case BIND_OPCODE_DO_BIND:
11277 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11278 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11279 break;
11280 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11281 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11282 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11283 fEncodedData.append_uleb128(it->operand1);
11284 break;
11285 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11286 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11287 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11288 break;
11289 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11290 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11291 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11292 fEncodedData.append_uleb128(it->operand1);
11293 fEncodedData.append_uleb128(it->operand2);
11294 break;
11295 }
11296 }
11297
11298 // align to pointer size
11299 fEncodedData.pad_to_size(sizeof(pint_t));
11300
11301 if (log) fprintf(stderr, "total binding info size = %ld\n", fEncodedData.size());
11302
11303 }
11304
11305
11306
11307 struct WeakBindingSorter
11308 {
11309 bool operator()(const BindingInfo& left, const BindingInfo& right)
11310 {
11311 // sort by symbol, type, address
11312 if ( left.fSymbolName != right.fSymbolName )
11313 return ( strcmp(left.fSymbolName, right.fSymbolName) < 0 );
11314 if ( left.fType != right.fType )
11315 return (left.fType < right.fType);
11316 return (left.fAddress < right.fAddress);
11317 }
11318 };
11319
11320
11321
11322 template <typename A>
11323 void CompressedWeakBindingInfoLinkEditAtom<A>::encode()
11324 {
11325 // add regular atoms that override a dylib's weak definitions
11326 for(std::set<const class ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
11327 it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
11328 if ( fWriter.shouldExport(**it) )
11329 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, (*it)->getName(), true, 0, 0));
11330 }
11331
11332 // add all exported weak definitions
11333 for(std::vector<class ObjectFile::Atom*>::iterator it = fWriter.fAllAtoms->begin(); it != fWriter.fAllAtoms->end(); ++it) {
11334 ObjectFile::Atom* atom = *it;
11335 if ( (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) && fWriter.shouldExport(*atom) ) {
11336 fWriter.fWeakBindingInfo.push_back(BindingInfo(0, atom->getName(), false, 0, 0));
11337 }
11338 }
11339
11340 // sort by symbol, type, address
11341 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11342 std::vector<BindingInfo>& info = fWriter.fWeakBindingInfo;
11343 if ( info.size() == 0 )
11344 return;
11345 std::sort(info.begin(), info.end(), WeakBindingSorter());
11346
11347 // convert to temp encoding that can be more easily optimized
11348 std::vector<binding_tmp> mid;
11349 mid.reserve(info.size());
11350 const SegmentInfo* currentSegment = NULL;
11351 unsigned int segIndex = 0;
11352 const char* symbolName = NULL;
11353 uint8_t type = 0;
11354 uint64_t address = (uint64_t)(-1);
11355 int64_t addend = 0;
11356 for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
11357 if ( symbolName != it->fSymbolName ) {
11358 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
11359 symbolName = it->fSymbolName;
11360 }
11361 if ( it->fType != 0 ) {
11362 if ( type != it->fType ) {
11363 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
11364 type = it->fType;
11365 }
11366 if ( address != it->fAddress ) {
11367 // non weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
11368 // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
11369 if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress)
11370 || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress) ) {
11371 segIndex = 0;
11372 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11373 if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11374 currentSegment = *segit;
11375 break;
11376 }
11377 ++segIndex;
11378 }
11379 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
11380 }
11381 else {
11382 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
11383 }
11384 address = it->fAddress;
11385 }
11386 if ( addend != it->fAddend ) {
11387 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
11388 addend = it->fAddend;
11389 }
11390 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
11391 address += sizeof(pint_t);
11392 }
11393 }
11394 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
11395
11396
11397 // optimize phase 1, combine bind/add pairs
11398 binding_tmp* dst = &mid[0];
11399 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11400 if ( (src->opcode == BIND_OPCODE_DO_BIND)
11401 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
11402 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
11403 dst->operand1 = src[1].operand1;
11404 ++src;
11405 ++dst;
11406 }
11407 else {
11408 *dst++ = *src;
11409 }
11410 }
11411 dst->opcode = BIND_OPCODE_DONE;
11412
11413 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
11414 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
11415 dst = &mid[0];
11416 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
11417 uint64_t delta = src->operand1;
11418 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11419 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11420 && (src[1].operand1 == delta) ) {
11421 // found at least two in a row, this is worth compressing
11422 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
11423 dst->operand1 = 1;
11424 dst->operand2 = delta;
11425 ++src;
11426 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11427 && (src->operand1 == delta) ) {
11428 dst->operand1++;
11429 ++src;
11430 }
11431 --src;
11432 ++dst;
11433 }
11434 else {
11435 *dst++ = *src;
11436 }
11437 }
11438 dst->opcode = BIND_OPCODE_DONE;
11439
11440 // optimize phase 3, use immediate encodings
11441 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
11442 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
11443 && (p->operand1 < (15*sizeof(pint_t)))
11444 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
11445 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
11446 p->operand1 = p->operand1/sizeof(pint_t);
11447 }
11448 }
11449 dst->opcode = BIND_OPCODE_DONE;
11450
11451
11452 // convert to compressed encoding
11453 const static bool log = false;
11454 fEncodedData.reserve(info.size()*2);
11455 bool done = false;
11456 for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
11457 switch ( it->opcode ) {
11458 case BIND_OPCODE_DONE:
11459 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
11460 fEncodedData.append_byte(BIND_OPCODE_DONE);
11461 done = true;
11462 break;
11463 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
11464 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
11465 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
11466 break;
11467 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
11468 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
11469 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11470 fEncodedData.append_uleb128(it->operand1);
11471 break;
11472 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
11473 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
11474 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
11475 break;
11476 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
11477 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
11478 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
11479 fEncodedData.append_string(it->name);
11480 break;
11481 case BIND_OPCODE_SET_TYPE_IMM:
11482 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
11483 fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
11484 break;
11485 case BIND_OPCODE_SET_ADDEND_SLEB:
11486 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
11487 fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
11488 fEncodedData.append_sleb128(it->operand1);
11489 break;
11490 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
11491 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
11492 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
11493 fEncodedData.append_uleb128(it->operand2);
11494 break;
11495 case BIND_OPCODE_ADD_ADDR_ULEB:
11496 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11497 fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
11498 fEncodedData.append_uleb128(it->operand1);
11499 break;
11500 case BIND_OPCODE_DO_BIND:
11501 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
11502 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11503 break;
11504 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
11505 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
11506 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
11507 fEncodedData.append_uleb128(it->operand1);
11508 break;
11509 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
11510 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
11511 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
11512 break;
11513 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
11514 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
11515 fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
11516 fEncodedData.append_uleb128(it->operand1);
11517 fEncodedData.append_uleb128(it->operand2);
11518 break;
11519 }
11520 }
11521
11522 // align to pointer size
11523 fEncodedData.pad_to_size(sizeof(pint_t));
11524
11525 if (log) fprintf(stderr, "total weak binding info size = %ld\n", fEncodedData.size());
11526
11527 }
11528
11529 template <typename A>
11530 void CompressedLazyBindingInfoLinkEditAtom<A>::encode()
11531 {
11532 // stream all lazy bindings and record start offsets
11533 const SegmentInfo* currentSegment = NULL;
11534 uint8_t segIndex = 0;
11535 const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
11536 std::vector<class LazyPointerAtom<A>*>& allLazys = fWriter.fAllSynthesizedLazyPointers;
11537 for (typename std::vector<class LazyPointerAtom<A>*>::iterator it = allLazys.begin(); it != allLazys.end(); ++it) {
11538 LazyPointerAtom<A>* lazyPointerAtom = *it;
11539 ObjectFile::Atom* lazyPointerTargetAtom = lazyPointerAtom->getTarget();
11540
11541 // skip lazy pointers that are bound non-lazily because they are coalesced
11542 if ( ! fWriter.targetRequiresWeakBinding(*lazyPointerTargetAtom) ) {
11543 // record start offset for use by stub helper
11544 lazyPointerAtom->setLazyBindingInfoOffset(fEncodedData.size());
11545
11546 // write address to bind
11547 pint_t address = lazyPointerAtom->getAddress();
11548 if ( (currentSegment == NULL) || (address < currentSegment->fBaseAddress)
11549 || ((currentSegment->fBaseAddress+currentSegment->fSize) <= address) ) {
11550 segIndex = 0;
11551 for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
11552 if ( ((*segit)->fBaseAddress <= address) && (address < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
11553 currentSegment = *segit;
11554 break;
11555 }
11556 ++segIndex;
11557 }
11558 }
11559 fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
11560 fEncodedData.append_uleb128(lazyPointerAtom->getAddress() - currentSegment->fBaseAddress);
11561
11562 // write ordinal
11563 int ordinal = fWriter.compressedOrdinalForImortedAtom(lazyPointerTargetAtom);
11564 if ( ordinal <= 0 ) {
11565 // special lookups are encoded as negative numbers in BindingInfo
11566 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (ordinal & BIND_IMMEDIATE_MASK) );
11567 }
11568 else if ( ordinal <= 15 ) {
11569 // small ordinals are encoded in opcode
11570 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
11571 }
11572 else {
11573 fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
11574 fEncodedData.append_uleb128(ordinal);
11575 }
11576 // write symbol name
11577 bool weak_import = fWriter.fWeakImportMap[lazyPointerTargetAtom];
11578 if ( weak_import )
11579 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | BIND_SYMBOL_FLAGS_WEAK_IMPORT);
11580 else
11581 fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
11582 fEncodedData.append_string(lazyPointerTargetAtom->getName());
11583 // write do bind
11584 fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
11585 fEncodedData.append_byte(BIND_OPCODE_DONE);
11586 }
11587 }
11588 // align to pointer size
11589 fEncodedData.pad_to_size(sizeof(pint_t));
11590
11591 //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", fEncodedData.size(), allLazys.size());
11592 }
11593
11594 struct TrieEntriesSorter
11595 {
11596 TrieEntriesSorter(Options& o) : fOptions(o) {}
11597
11598 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
11599 {
11600 unsigned int leftOrder;
11601 unsigned int rightOrder;
11602 fOptions.exportedSymbolOrder(left.name, &leftOrder);
11603 fOptions.exportedSymbolOrder(right.name, &rightOrder);
11604 if ( leftOrder != rightOrder )
11605 return (leftOrder < rightOrder);
11606 else
11607 return (left.address < right.address);
11608 }
11609 private:
11610 Options& fOptions;
11611 };
11612
11613
11614 template <typename A>
11615 void CompressedExportInfoLinkEditAtom<A>::encode()
11616 {
11617 // make vector of mach_o::trie::Entry for all exported symbols
11618 std::vector<class ObjectFile::Atom*>& exports = fWriter.fExportedAtoms;
11619 uint64_t imageBaseAddress = fWriter.fMachHeaderAtom->getAddress();
11620 std::vector<mach_o::trie::Entry> entries;
11621 entries.reserve(exports.size());
11622 for (std::vector<ObjectFile::Atom*>::iterator it = exports.begin(); it != exports.end(); ++it) {
11623 ObjectFile::Atom* atom = *it;
11624 uint64_t flags = 0;
11625 if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
11626 flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
11627 uint64_t address = atom->getAddress() - imageBaseAddress;
11628 if ( atom->isThumb() )
11629 address |= 1;
11630 mach_o::trie::Entry entry;
11631 entry.name = atom->getName();
11632 entry.flags = flags;
11633 entry.address = address;
11634 entries.push_back(entry);
11635 }
11636
11637 // sort vector by -exported_symbols_order, and any others by address
11638 std::sort(entries.begin(), entries.end(), TrieEntriesSorter(fWriter.fOptions));
11639
11640 // create trie
11641 mach_o::trie::makeTrie(entries, fEncodedData.bytes());
11642
11643 // align to pointer size
11644 fEncodedData.pad_to_size(sizeof(pint_t));
11645 }
11646
11647
11648
11649
11650
11651 }; // namespace executable
11652 }; // namespace mach_o
11653
11654
11655 #endif // __EXECUTABLE_MACH_O__