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