]> git.saurik.com Git - apple/ld64.git/blob - src/MachOWriterExecutable.hpp
5b05210cf756704a7bfb0022e44c09e8c311c86f
[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 return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
2387 case ObjectFile::Atom::kExternalDefinition:
2388 case ObjectFile::Atom::kExternalWeakDefinition:
2389 return shouldExport(target);
2390 }
2391 return false;
2392 }
2393
2394 template <typename A>
2395 void Writer<A>::buildFixups()
2396 {
2397 if ( fOptions.outputKind() == Options::kObjectFile ) {
2398 this->buildObjectFileFixups();
2399 }
2400 else {
2401 if ( fOptions.keepRelocations() )
2402 this->buildObjectFileFixups();
2403 this->buildExecutableFixups();
2404 }
2405 }
2406
2407 template <>
2408 uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2409 {
2410 ObjectFile::Atom& target = ref->getTarget();
2411 bool external = this->makesExternalRelocatableReference(target);
2412 uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
2413 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2414 macho_relocation_info<P> reloc1;
2415 macho_relocation_info<P> reloc2;
2416 x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
2417
2418 switch ( kind ) {
2419 case x86_64::kNoFixUp:
2420 case x86_64::kFollowOn:
2421 return 0;
2422
2423 case x86_64::kPointer:
2424 case x86_64::kPointerWeakImport:
2425 reloc1.set_r_address(address);
2426 reloc1.set_r_symbolnum(symbolIndex);
2427 reloc1.set_r_pcrel(false);
2428 reloc1.set_r_length(3);
2429 reloc1.set_r_extern(external);
2430 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2431 fSectionRelocs.push_back(reloc1);
2432 return 1;
2433
2434 case x86_64::kPointerDiff32:
2435 case x86_64::kPointerDiff:
2436 {
2437 ObjectFile::Atom& fromTarget = ref->getFromTarget();
2438 bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
2439 uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
2440 reloc1.set_r_address(address);
2441 reloc1.set_r_symbolnum(symbolIndex);
2442 reloc1.set_r_pcrel(false);
2443 reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2444 reloc1.set_r_extern(external);
2445 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
2446 reloc2.set_r_address(address);
2447 reloc2.set_r_symbolnum(fromSymbolIndex);
2448 reloc2.set_r_pcrel(false);
2449 reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
2450 reloc2.set_r_extern(fromExternal);
2451 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
2452 fSectionRelocs.push_back(reloc1);
2453 fSectionRelocs.push_back(reloc2);
2454 return 2;
2455 }
2456
2457 case x86_64::kBranchPCRel32:
2458 case x86_64::kBranchPCRel32WeakImport:
2459 case x86_64::kDtraceProbeSite:
2460 case x86_64::kDtraceIsEnabledSite:
2461 reloc1.set_r_address(address);
2462 reloc1.set_r_symbolnum(symbolIndex);
2463 reloc1.set_r_pcrel(true);
2464 reloc1.set_r_length(2);
2465 reloc1.set_r_extern(external);
2466 reloc1.set_r_type(X86_64_RELOC_BRANCH);
2467 fSectionRelocs.push_back(reloc1);
2468 return 1;
2469
2470 case x86_64::kPCRel32:
2471 reloc1.set_r_address(address);
2472 reloc1.set_r_symbolnum(symbolIndex);
2473 reloc1.set_r_pcrel(true);
2474 reloc1.set_r_length(2);
2475 reloc1.set_r_extern(external);
2476 reloc1.set_r_type(X86_64_RELOC_SIGNED);
2477 fSectionRelocs.push_back(reloc1);
2478 return 1;
2479
2480 case x86_64::kPCRel32_1:
2481 reloc1.set_r_address(address);
2482 reloc1.set_r_symbolnum(symbolIndex);
2483 reloc1.set_r_pcrel(true);
2484 reloc1.set_r_length(2);
2485 reloc1.set_r_extern(external);
2486 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
2487 fSectionRelocs.push_back(reloc1);
2488 return 1;
2489
2490 case x86_64::kPCRel32_2:
2491 reloc1.set_r_address(address);
2492 reloc1.set_r_symbolnum(symbolIndex);
2493 reloc1.set_r_pcrel(true);
2494 reloc1.set_r_length(2);
2495 reloc1.set_r_extern(external);
2496 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
2497 fSectionRelocs.push_back(reloc1);
2498 return 1;
2499
2500 case x86_64::kPCRel32_4:
2501 reloc1.set_r_address(address);
2502 reloc1.set_r_symbolnum(symbolIndex);
2503 reloc1.set_r_pcrel(true);
2504 reloc1.set_r_length(2);
2505 reloc1.set_r_extern(external);
2506 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
2507 fSectionRelocs.push_back(reloc1);
2508 return 1;
2509
2510 case x86_64::kPCRel32GOT:
2511 case x86_64::kPCRel32GOTWeakImport:
2512 reloc1.set_r_address(address);
2513 reloc1.set_r_symbolnum(symbolIndex);
2514 reloc1.set_r_pcrel(true);
2515 reloc1.set_r_length(2);
2516 reloc1.set_r_extern(external);
2517 reloc1.set_r_type(X86_64_RELOC_GOT);
2518 fSectionRelocs.push_back(reloc1);
2519 return 1;
2520
2521 case x86_64::kPCRel32GOTLoad:
2522 case x86_64::kPCRel32GOTLoadWeakImport:
2523 reloc1.set_r_address(address);
2524 reloc1.set_r_symbolnum(symbolIndex);
2525 reloc1.set_r_pcrel(true);
2526 reloc1.set_r_length(2);
2527 reloc1.set_r_extern(external);
2528 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
2529 fSectionRelocs.push_back(reloc1);
2530 return 1;
2531
2532 case x86_64::kDtraceTypeReference:
2533 case x86_64::kDtraceProbe:
2534 // generates no relocs
2535 return 0;
2536 }
2537 return 0;
2538 }
2539
2540
2541 template <>
2542 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2543 {
2544 ObjectFile::Atom& target = ref->getTarget();
2545 bool isExtern = this->makesExternalRelocatableReference(target);
2546 uint32_t symbolIndex = 0;
2547 if ( isExtern )
2548 symbolIndex = this->symbolIndex(target);
2549 uint32_t sectionNum = target.getSection()->getIndex();
2550 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2551 macho_relocation_info<P> reloc1;
2552 macho_relocation_info<P> reloc2;
2553 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2554 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2555 x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
2556
2557 if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
2558 fprintf(stderr, "ld: warning section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s\n",
2559 target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
2560
2561
2562 switch ( kind ) {
2563 case x86::kNoFixUp:
2564 case x86::kFollowOn:
2565 return 0;
2566
2567 case x86::kPointer:
2568 case x86::kPointerWeakImport:
2569 case x86::kAbsolute32:
2570 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2571 // use scattered reloc is target offset is non-zero
2572 sreloc1->set_r_scattered(true);
2573 sreloc1->set_r_pcrel(false);
2574 sreloc1->set_r_length(2);
2575 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2576 sreloc1->set_r_address(address);
2577 sreloc1->set_r_value(target.getAddress());
2578 }
2579 else {
2580 reloc1.set_r_address(address);
2581 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2582 reloc1.set_r_pcrel(false);
2583 reloc1.set_r_length(2);
2584 reloc1.set_r_extern(isExtern);
2585 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2586 }
2587 fSectionRelocs.push_back(reloc1);
2588 return 1;
2589
2590 case x86::kPointerDiff16:
2591 case x86::kPointerDiff:
2592 {
2593 //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2594 //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
2595 // ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(),
2596 // ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
2597 sreloc1->set_r_scattered(true);
2598 sreloc1->set_r_pcrel(false);
2599 sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2600 if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
2601 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
2602 else
2603 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
2604 sreloc1->set_r_address(address);
2605 sreloc1->set_r_value(target.getAddress());
2606 sreloc2->set_r_scattered(true);
2607 sreloc2->set_r_pcrel(false);
2608 sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
2609 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
2610 sreloc2->set_r_address(0);
2611 //if ( &ref->getFromTarget() == &ref->getTarget() )
2612 sreloc2->set_r_value(ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
2613 //else
2614 // sreloc2->set_r_value(ref->getFromTarget().getAddress());
2615 fSectionRelocs.push_back(reloc2);
2616 fSectionRelocs.push_back(reloc1);
2617 return 2;
2618 }
2619
2620 case x86::kPCRel32WeakImport:
2621 case x86::kPCRel32:
2622 case x86::kPCRel16:
2623 case x86::kDtraceProbeSite:
2624 case x86::kDtraceIsEnabledSite:
2625 if ( !isExtern && (ref->getTargetOffset() != 0) ) {
2626 // use scattered reloc is target offset is non-zero
2627 sreloc1->set_r_scattered(true);
2628 sreloc1->set_r_pcrel(true);
2629 sreloc1->set_r_length( (kind==x86::kPCRel16) ? 1 : 2);
2630 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2631 sreloc1->set_r_address(address);
2632 sreloc1->set_r_value(target.getAddress());
2633 }
2634 else {
2635 reloc1.set_r_address(address);
2636 reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
2637 reloc1.set_r_pcrel(true);
2638 reloc1.set_r_length( (kind==x86::kPCRel16) ? 1 : 2);
2639 reloc1.set_r_extern(isExtern);
2640 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2641 }
2642 fSectionRelocs.push_back(reloc1);
2643 return 1;
2644
2645 case x86::kDtraceTypeReference:
2646 case x86::kDtraceProbe:
2647 // generates no relocs
2648 return 0;
2649
2650 }
2651 return 0;
2652 }
2653
2654
2655
2656
2657 template <> uint64_t Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
2658 template <> uint64_t Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
2659 template <> uint64_t Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
2660 template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
2661
2662
2663 template <>
2664 uint8_t Writer<ppc>::getRelocPointerSize()
2665 {
2666 return 2;
2667 }
2668
2669 template <>
2670 uint8_t Writer<ppc64>::getRelocPointerSize()
2671 {
2672 return 3;
2673 }
2674
2675 template <>
2676 uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2677 {
2678 return addObjectRelocs_powerpc(atom, ref);
2679 }
2680
2681 template <>
2682 uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2683 {
2684 return addObjectRelocs_powerpc(atom, ref);
2685 }
2686
2687 //
2688 // addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
2689 // they use a common addObjectRelocs_powerpc() method.
2690 //
2691 template <typename A>
2692 uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
2693 {
2694 ObjectFile::Atom& target = ref->getTarget();
2695 bool isExtern = this->makesExternalRelocatableReference(target);
2696 uint32_t symbolIndex = 0;
2697 if ( isExtern )
2698 symbolIndex = this->symbolIndex(target);
2699 uint32_t sectionNum = target.getSection()->getIndex();
2700 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
2701 macho_relocation_info<P> reloc1;
2702 macho_relocation_info<P> reloc2;
2703 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
2704 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
2705 typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
2706
2707 switch ( kind ) {
2708 case A::kNoFixUp:
2709 case A::kFollowOn:
2710 return 0;
2711
2712 case A::kPointer:
2713 case A::kPointerWeakImport:
2714 if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
2715 // use scattered reloc is target offset is outside target
2716 sreloc1->set_r_scattered(true);
2717 sreloc1->set_r_pcrel(false);
2718 sreloc1->set_r_length(getRelocPointerSize());
2719 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
2720 sreloc1->set_r_address(address);
2721 sreloc1->set_r_value(target.getAddress());
2722 }
2723 else {
2724 reloc1.set_r_address(address);
2725 if ( isExtern )
2726 reloc1.set_r_symbolnum(symbolIndex);
2727 else
2728 reloc1.set_r_symbolnum(sectionNum);
2729 reloc1.set_r_pcrel(false);
2730 reloc1.set_r_length(getRelocPointerSize());
2731 reloc1.set_r_extern(isExtern);
2732 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
2733 }
2734 fSectionRelocs.push_back(reloc1);
2735 return 1;
2736
2737 case A::kPointerDiff16:
2738 case A::kPointerDiff32:
2739 case A::kPointerDiff64:
2740 {
2741 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2742 pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
2743 sreloc1->set_r_scattered(true);
2744 sreloc1->set_r_pcrel(false);
2745 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
2746 sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
2747 sreloc1->set_r_address(address);
2748 sreloc1->set_r_value(toAddr);
2749 sreloc2->set_r_scattered(true);
2750 sreloc2->set_r_pcrel(false);
2751 sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
2752 sreloc2->set_r_type(PPC_RELOC_PAIR);
2753 sreloc2->set_r_address(0);
2754 sreloc2->set_r_value(fromAddr);
2755 fSectionRelocs.push_back(reloc2);
2756 fSectionRelocs.push_back(reloc1);
2757 return 2;
2758 }
2759
2760 case A::kBranch24WeakImport:
2761 case A::kBranch24:
2762 case A::kDtraceProbeSite:
2763 case A::kDtraceIsEnabledSite:
2764 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2765 reloc1.set_r_address(address);
2766 if ( isExtern )
2767 reloc1.set_r_symbolnum(symbolIndex);
2768 else
2769 reloc1.set_r_symbolnum(sectionNum);
2770 reloc1.set_r_pcrel(true);
2771 reloc1.set_r_length(2);
2772 reloc1.set_r_type(PPC_RELOC_BR24);
2773 reloc1.set_r_extern(isExtern);
2774 }
2775 else {
2776 sreloc1->set_r_scattered(true);
2777 sreloc1->set_r_pcrel(true);
2778 sreloc1->set_r_length(2);
2779 sreloc1->set_r_type(PPC_RELOC_BR24);
2780 sreloc1->set_r_address(address);
2781 sreloc1->set_r_value(target.getAddress());
2782 }
2783 fSectionRelocs.push_back(reloc1);
2784 return 1;
2785
2786 case A::kBranch14:
2787 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2788 reloc1.set_r_address(address);
2789 if ( isExtern )
2790 reloc1.set_r_symbolnum(symbolIndex);
2791 else
2792 reloc1.set_r_symbolnum(sectionNum);
2793 reloc1.set_r_pcrel(true);
2794 reloc1.set_r_length(2);
2795 reloc1.set_r_type(PPC_RELOC_BR14);
2796 reloc1.set_r_extern(isExtern);
2797 }
2798 else {
2799 sreloc1->set_r_scattered(true);
2800 sreloc1->set_r_pcrel(true);
2801 sreloc1->set_r_length(2);
2802 sreloc1->set_r_type(PPC_RELOC_BR14);
2803 sreloc1->set_r_address(address);
2804 sreloc1->set_r_value(target.getAddress());
2805 }
2806 fSectionRelocs.push_back(reloc1);
2807 return 1;
2808
2809 case A::kPICBaseLow16:
2810 case A::kPICBaseLow14:
2811 {
2812 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2813 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2814 sreloc1->set_r_scattered(true);
2815 sreloc1->set_r_pcrel(false);
2816 sreloc1->set_r_length(2);
2817 sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
2818 sreloc1->set_r_address(address);
2819 sreloc1->set_r_value(target.getAddress());
2820 sreloc2->set_r_scattered(true);
2821 sreloc2->set_r_pcrel(false);
2822 sreloc2->set_r_length(2);
2823 sreloc2->set_r_type(PPC_RELOC_PAIR);
2824 sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
2825 sreloc2->set_r_value(fromAddr);
2826 fSectionRelocs.push_back(reloc2);
2827 fSectionRelocs.push_back(reloc1);
2828 return 2;
2829 }
2830
2831 case A::kPICBaseHigh16:
2832 {
2833 pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
2834 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2835 sreloc1->set_r_scattered(true);
2836 sreloc1->set_r_pcrel(false);
2837 sreloc1->set_r_length(2);
2838 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
2839 sreloc1->set_r_address(address);
2840 sreloc1->set_r_value(target.getAddress());
2841 sreloc2->set_r_scattered(true);
2842 sreloc2->set_r_pcrel(false);
2843 sreloc2->set_r_length(2);
2844 sreloc2->set_r_type(PPC_RELOC_PAIR);
2845 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
2846 sreloc2->set_r_value(fromAddr);
2847 fSectionRelocs.push_back(reloc2);
2848 fSectionRelocs.push_back(reloc1);
2849 return 2;
2850 }
2851
2852 case A::kAbsLow14:
2853 case A::kAbsLow16:
2854 {
2855 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2856 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2857 reloc1.set_r_address(address);
2858 if ( isExtern )
2859 reloc1.set_r_symbolnum(symbolIndex);
2860 else
2861 reloc1.set_r_symbolnum(sectionNum);
2862 reloc1.set_r_pcrel(false);
2863 reloc1.set_r_length(2);
2864 reloc1.set_r_extern(isExtern);
2865 reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2866 }
2867 else {
2868 sreloc1->set_r_scattered(true);
2869 sreloc1->set_r_pcrel(false);
2870 sreloc1->set_r_length(2);
2871 sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
2872 sreloc1->set_r_address(address);
2873 sreloc1->set_r_value(target.getAddress());
2874 }
2875 if ( isExtern )
2876 reloc2.set_r_address(ref->getTargetOffset() >> 16);
2877 else
2878 reloc2.set_r_address(toAddr >> 16);
2879 reloc2.set_r_symbolnum(0);
2880 reloc2.set_r_pcrel(false);
2881 reloc2.set_r_length(2);
2882 reloc2.set_r_extern(false);
2883 reloc2.set_r_type(PPC_RELOC_PAIR);
2884 fSectionRelocs.push_back(reloc2);
2885 fSectionRelocs.push_back(reloc1);
2886 return 2;
2887 }
2888
2889 case A::kAbsHigh16:
2890 {
2891 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2892 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2893 reloc1.set_r_address(address);
2894 if ( isExtern )
2895 reloc1.set_r_symbolnum(symbolIndex);
2896 else
2897 reloc1.set_r_symbolnum(sectionNum);
2898 reloc1.set_r_pcrel(false);
2899 reloc1.set_r_length(2);
2900 reloc1.set_r_extern(isExtern);
2901 reloc1.set_r_type(PPC_RELOC_HI16);
2902 }
2903 else {
2904 sreloc1->set_r_scattered(true);
2905 sreloc1->set_r_pcrel(false);
2906 sreloc1->set_r_length(2);
2907 sreloc1->set_r_type(PPC_RELOC_HI16);
2908 sreloc1->set_r_address(address);
2909 sreloc1->set_r_value(target.getAddress());
2910 }
2911 if ( isExtern )
2912 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2913 else
2914 reloc2.set_r_address(toAddr & 0xFFFF);
2915 reloc2.set_r_symbolnum(0);
2916 reloc2.set_r_pcrel(false);
2917 reloc2.set_r_length(2);
2918 reloc2.set_r_extern(false);
2919 reloc2.set_r_type(PPC_RELOC_PAIR);
2920 fSectionRelocs.push_back(reloc2);
2921 fSectionRelocs.push_back(reloc1);
2922 return 2;
2923 }
2924
2925 case A::kAbsHigh16AddLow:
2926 {
2927 pint_t toAddr = target.getAddress() + ref->getTargetOffset();
2928 uint32_t overflow = 0;
2929 if ( (toAddr & 0x00008000) != 0 )
2930 overflow = 0x10000;
2931 if ( (ref->getTargetOffset() == 0) || isExtern ) {
2932 reloc1.set_r_address(address);
2933 if ( isExtern )
2934 reloc1.set_r_symbolnum(symbolIndex);
2935 else
2936 reloc1.set_r_symbolnum(sectionNum);
2937 reloc1.set_r_pcrel(false);
2938 reloc1.set_r_length(2);
2939 reloc1.set_r_extern(isExtern);
2940 reloc1.set_r_type(PPC_RELOC_HA16);
2941 }
2942 else {
2943 sreloc1->set_r_scattered(true);
2944 sreloc1->set_r_pcrel(false);
2945 sreloc1->set_r_length(2);
2946 sreloc1->set_r_type(PPC_RELOC_HA16);
2947 sreloc1->set_r_address(address);
2948 sreloc1->set_r_value(target.getAddress());
2949 }
2950 if ( isExtern )
2951 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
2952 else
2953 reloc2.set_r_address(toAddr & 0xFFFF);
2954 reloc2.set_r_symbolnum(0);
2955 reloc2.set_r_pcrel(false);
2956 reloc2.set_r_length(2);
2957 reloc2.set_r_extern(false);
2958 reloc2.set_r_type(PPC_RELOC_PAIR);
2959 fSectionRelocs.push_back(reloc2);
2960 fSectionRelocs.push_back(reloc1);
2961 return 2;
2962 }
2963
2964 case A::kDtraceTypeReference:
2965 case A::kDtraceProbe:
2966 // generates no relocs
2967 return 0;
2968 }
2969 return 0;
2970 }
2971
2972
2973
2974 //
2975 // There are cases when an entry in the indirect symbol table is the magic value
2976 // INDIRECT_SYMBOL_LOCAL instead of being a symbol index. When that happens
2977 // the content of the corresponding part of the __nl_symbol_pointer section
2978 // must also change.
2979 //
2980 template <typename A>
2981 bool Writer<A>::indirectSymbolIsLocal(const ObjectFile::Reference* ref) const
2982 {
2983 // use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
2984 return ( !this->shouldExport(ref->getTarget()) || (ref->getTargetOffset() != 0) );
2985 }
2986
2987
2988 template <typename A>
2989 void Writer<A>::buildObjectFileFixups()
2990 {
2991 uint32_t relocIndex = 0;
2992 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
2993 const int segCount = segmentInfos.size();
2994 for(int i=0; i < segCount; ++i) {
2995 SegmentInfo* curSegment = segmentInfos[i];
2996 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2997 const int sectionCount = sectionInfos.size();
2998 for(int j=0; j < sectionCount; ++j) {
2999 SectionInfo* curSection = sectionInfos[j];
3000 //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
3001 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3002 if ( ! curSection->fAllZeroFill ) {
3003 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs )
3004 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3005 curSection->fRelocOffset = relocIndex;
3006 const int atomCount = sectionAtoms.size();
3007 for (int k=0; k < atomCount; ++k) {
3008 ObjectFile::Atom* atom = sectionAtoms[k];
3009 //fprintf(stderr, "buildObjectFileFixups(): atom %s\n", atom->getDisplayName());
3010 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3011 const int refCount = refs.size();
3012 for (int l=0; l < refCount; ++l) {
3013 ObjectFile::Reference* ref = refs[l];
3014 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs ) {
3015 uint32_t offsetInSection = atom->getSectionOffset();
3016 uint32_t indexInSection = offsetInSection / atom->getSize();
3017 uint32_t undefinedSymbolIndex;
3018 if ( curSection->fAllStubs ) {
3019 ObjectFile::Atom& stubTarget =ref->getTarget();
3020 ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
3021 undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
3022 //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
3023 }
3024 else if ( curSection->fAllNonLazyPointers) {
3025 // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
3026 if ( this->indirectSymbolIsLocal(ref) )
3027 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3028 else
3029 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
3030 }
3031 else {
3032 // should never get here, fAllLazyPointers not used in generated .o files
3033 undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3034 }
3035 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3036 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3037 //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
3038 fIndirectTableAtom->fTable.push_back(entry);
3039 if ( curSection->fAllLazyPointers ) {
3040 ObjectFile::Atom& target = ref->getTarget();
3041 ObjectFile::Atom& fromTarget = ref->getFromTarget();
3042 if ( &fromTarget == NULL ) {
3043 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
3044 }
3045 else {
3046 bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
3047 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
3048 && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
3049 macho_relocation_info<P> reloc1;
3050 reloc1.set_r_address(atom->getSectionOffset());
3051 reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
3052 reloc1.set_r_pcrel(false);
3053 reloc1.set_r_length();
3054 reloc1.set_r_extern(isExtern);
3055 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
3056 fSectionRelocs.push_back(reloc1);
3057 ++relocIndex;
3058 }
3059 }
3060 else if ( curSection->fAllStubs ) {
3061 relocIndex += this->addObjectRelocs(atom, ref);
3062 }
3063 }
3064 else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
3065 relocIndex += this->addObjectRelocs(atom, ref);
3066 }
3067 }
3068 }
3069 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
3070 }
3071 }
3072 }
3073
3074 // reverse the relocs
3075 std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
3076
3077 // now reverse section reloc offsets
3078 for(int i=0; i < segCount; ++i) {
3079 SegmentInfo* curSegment = segmentInfos[i];
3080 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3081 const int sectionCount = sectionInfos.size();
3082 for(int j=0; j < sectionCount; ++j) {
3083 SectionInfo* curSection = sectionInfos[j];
3084 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
3085 }
3086 }
3087
3088 }
3089
3090 template <>
3091 bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3092 {
3093 switch ( ref.getKind() ) {
3094 case ppc::kAbsLow16:
3095 case ppc::kAbsLow14:
3096 case ppc::kAbsHigh16:
3097 case ppc::kAbsHigh16AddLow:
3098 if ( fSlideable )
3099 return true;
3100 }
3101 return false;
3102 }
3103
3104
3105 template <>
3106 bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3107 {
3108 switch ( ref.getKind() ) {
3109 case ppc::kAbsLow16:
3110 case ppc::kAbsLow14:
3111 case ppc::kAbsHigh16:
3112 case ppc::kAbsHigh16AddLow:
3113 if ( fSlideable )
3114 return true;
3115 }
3116 return false;
3117 }
3118
3119 template <>
3120 bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3121 {
3122 if ( ref.getKind() == x86::kAbsolute32 ) {
3123 switch ( ref.getTarget().getDefinitionKind() ) {
3124 case ObjectFile::Atom::kTentativeDefinition:
3125 case ObjectFile::Atom::kRegularDefinition:
3126 case ObjectFile::Atom::kWeakDefinition:
3127 // illegal in dylibs/bundles, until we support TEXT relocs
3128 return fSlideable;
3129 case ObjectFile::Atom::kExternalDefinition:
3130 case ObjectFile::Atom::kExternalWeakDefinition:
3131 // illegal until we support TEXT relocs
3132 return true;
3133 case ObjectFile::Atom::kAbsoluteSymbol:
3134 // absolute symbbols only allowed in static executables
3135 return ( fOptions.outputKind() != Options::kStaticExecutable);
3136 }
3137 }
3138 return false;
3139 }
3140
3141 template <>
3142 bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
3143 {
3144 return false;
3145 }
3146
3147
3148 template <typename A>
3149 typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
3150 {
3151 switch ( target.getDefinitionKind() ) {
3152 case ObjectFile::Atom::kTentativeDefinition:
3153 case ObjectFile::Atom::kRegularDefinition:
3154 // in main executables, the only way regular symbols are indirected is if -interposable is used
3155 if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
3156 if ( this->shouldExport(target) && fOptions.interposable() )
3157 return kRelocExternal;
3158 else if ( fSlideable )
3159 return kRelocInternal;
3160 else
3161 return kRelocNone;
3162 }
3163 // for flat-namespace or interposable two-level-namespace
3164 // all references to exported symbols get indirected
3165 else if ( this->shouldExport(target) &&
3166 ((fOptions.nameSpace() == Options::kFlatNameSpace)
3167 || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
3168 || fOptions.interposable())
3169 && (target.getName() != NULL)
3170 && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
3171 return kRelocExternal;
3172 else if ( fSlideable )
3173 return kRelocInternal;
3174 else
3175 return kRelocNone;
3176 case ObjectFile::Atom::kWeakDefinition:
3177 // all calls to global weak definitions get indirected
3178 if ( this->shouldExport(target) )
3179 return kRelocExternal;
3180 else if ( fSlideable )
3181 return kRelocInternal;
3182 else
3183 return kRelocNone;
3184 case ObjectFile::Atom::kExternalDefinition:
3185 case ObjectFile::Atom::kExternalWeakDefinition:
3186 return kRelocExternal;
3187 case ObjectFile::Atom::kAbsoluteSymbol:
3188 return kRelocNone;
3189 }
3190 return kRelocNone;
3191 }
3192
3193 template <typename A>
3194 uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3195 {
3196 // for 32-bit architectures, the r_address field in relocs
3197 // for final linked images is the offset from the first segment
3198 uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
3199 // or the offset from the first writable segment if built split-seg
3200 if ( fOptions.splitSeg() )
3201 result = address - fFirstWritableSegment->fBaseAddress;
3202 if ( result > 0x7FFFFFFF ) {
3203 throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
3204 atom->getDisplayName(), atom->getFile()->getPath());
3205 }
3206 return result;
3207 }
3208
3209 template <>
3210 uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3211 {
3212 // for x86_64, the r_address field in relocs for final linked images
3213 // is the offset from the start address of the first writable segment
3214 uint64_t result = address - fFirstWritableSegment->fBaseAddress;
3215 if ( result > 0xFFFFFFFF ) {
3216 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3217 atom->getDisplayName(), atom->getFile()->getPath());
3218 }
3219 return result;
3220 }
3221
3222 template <>
3223 uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
3224 {
3225 // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.
3226 // the 10.5 dyld, iterprets the r_address as:
3227 // 1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
3228 // 2) an offset from the base address of the first writable segment
3229 // For dyld, r_address is always the offset from the base address
3230 uint64_t result;
3231 bool badFor10_4 = false;
3232 if ( fWritableSegmentPastFirst4GB ) {
3233 if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
3234 badFor10_4 = true;
3235 result = address - fFirstWritableSegment->fBaseAddress;
3236 if ( result > 0xFFFFFFFF ) {
3237 throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
3238 atom->getDisplayName(), atom->getFile()->getPath());
3239 }
3240 }
3241 else {
3242 result = address - fSegmentInfos[0]->fBaseAddress;
3243 if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
3244 badFor10_4 = true;
3245 }
3246 if ( badFor10_4 ) {
3247 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",
3248 atom->getDisplayName(), atom->getFile()->getPath());
3249 }
3250 return result;
3251 }
3252
3253
3254 template <> bool Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
3255 template <> bool Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3256 template <> bool Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
3257 template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
3258
3259
3260 template <typename A>
3261 void Writer<A>::buildExecutableFixups()
3262 {
3263 fIndirectTableAtom->fTable.reserve(50); // minimize reallocations
3264 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
3265 const int segCount = segmentInfos.size();
3266 for(int i=0; i < segCount; ++i) {
3267 SegmentInfo* curSegment = segmentInfos[i];
3268 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3269 const int sectionCount = sectionInfos.size();
3270 for(int j=0; j < sectionCount; ++j) {
3271 SectionInfo* curSection = sectionInfos[j];
3272 //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
3273 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3274 if ( ! curSection->fAllZeroFill ) {
3275 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
3276 curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
3277 const int atomCount = sectionAtoms.size();
3278 for (int k=0; k < atomCount; ++k) {
3279 ObjectFile::Atom* atom = sectionAtoms[k];
3280 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
3281 const int refCount = refs.size();
3282 //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
3283 for (int l=0; l < refCount; ++l) {
3284 ObjectFile::Reference* ref = refs[l];
3285 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
3286 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
3287 if ( atom->getSize() != sizeof(pint_t) ) {
3288 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
3289 }
3290 ObjectFile::Atom* pointerTarget = &(ref->getTarget());
3291 if ( curSection->fAllLazyPointers ) {
3292 pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
3293 }
3294 uint32_t offsetInSection = atom->getSectionOffset();
3295 uint32_t indexInSection = offsetInSection / sizeof(pint_t);
3296 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
3297 if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
3298 undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
3299 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3300 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3301 //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
3302 fIndirectTableAtom->fTable.push_back(entry);
3303 if ( curSection->fAllLazyPointers ) {
3304 uint8_t preboundLazyType;
3305 if ( fOptions.prebind() && (fDyldHelper != NULL) && preboundLazyPointerType(&preboundLazyType) ) {
3306 // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
3307 macho_scattered_relocation_info<P> pblaReloc;
3308 pblaReloc.set_r_scattered(true);
3309 pblaReloc.set_r_pcrel(false);
3310 pblaReloc.set_r_length();
3311 pblaReloc.set_r_type(preboundLazyType);
3312 pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3313 pblaReloc.set_r_value(fDyldHelper->getAddress());
3314 fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
3315 }
3316 else if ( fSlideable ) {
3317 // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
3318 macho_relocation_info<P> dyldHelperReloc;
3319 uint32_t sectionNum = 1;
3320 if ( fDyldHelper != NULL )
3321 sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
3322 //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
3323 dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
3324 dyldHelperReloc.set_r_symbolnum(sectionNum);
3325 dyldHelperReloc.set_r_pcrel(false);
3326 dyldHelperReloc.set_r_length();
3327 dyldHelperReloc.set_r_extern(false);
3328 dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
3329 fInternalRelocs.push_back(dyldHelperReloc);
3330 }
3331 }
3332 }
3333 else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
3334 if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
3335 throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
3336 atom->getDisplayName(), atom->getFile()->getPath());
3337 }
3338 switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
3339 case kRelocNone:
3340 // no reloc needed
3341 break;
3342 case kRelocInternal:
3343 {
3344 macho_relocation_info<P> internalReloc;
3345 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
3346 uint32_t sectionNum = sectInfo->getIndex();
3347 // special case _mh_dylib_header and friends which are not in any real section
3348 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
3349 sectionNum = 1;
3350 internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3351 internalReloc.set_r_symbolnum(sectionNum);
3352 internalReloc.set_r_pcrel(false);
3353 internalReloc.set_r_length();
3354 internalReloc.set_r_extern(false);
3355 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3356 fInternalRelocs.push_back(internalReloc);
3357 }
3358 break;
3359 case kRelocExternal:
3360 {
3361 macho_relocation_info<P> externalReloc;
3362 externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
3363 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
3364 externalReloc.set_r_pcrel(false);
3365 externalReloc.set_r_length();
3366 externalReloc.set_r_extern(true);
3367 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
3368 fExternalRelocs.push_back(externalReloc);
3369 }
3370 break;
3371 }
3372 }
3373 else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
3374 throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
3375 }
3376 }
3377 if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
3378 ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
3379 uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
3380 uint32_t offsetInSection = atom->getSectionOffset();
3381 uint32_t indexInSection = offsetInSection / atom->getSize();
3382 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
3383 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
3384 //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
3385 fIndirectTableAtom->fTable.push_back(entry);
3386 }
3387 }
3388 }
3389 }
3390 }
3391 if ( fSplitCodeToDataContentAtom != NULL )
3392 fSplitCodeToDataContentAtom->encode();
3393 }
3394
3395
3396 template <>
3397 void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3398 {
3399 switch ( (ppc::ReferenceKinds)ref->getKind() ) {
3400 case ppc::kPICBaseHigh16:
3401 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
3402 break;
3403 case ppc::kPointerDiff32:
3404 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3405 break;
3406 case ppc::kPointerDiff64:
3407 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3408 break;
3409 case ppc::kNoFixUp:
3410 case ppc::kPointer:
3411 case ppc::kPointerWeakImport:
3412 case ppc::kPICBaseLow16:
3413 case ppc::kPICBaseLow14:
3414 // ignore
3415 break;
3416 default:
3417 fprintf(stderr, "ld: warning codegen with reference kind %d in %s prevents image from loading in dyld shared cache\n", ref->getKind(), atom->getDisplayName());
3418 fSplitCodeToDataContentAtom->setCantEncode();
3419 }
3420 }
3421
3422 template <>
3423 void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3424 {
3425 switch ( (ppc64::ReferenceKinds)ref->getKind() ) {
3426 case ppc64::kPICBaseHigh16:
3427 fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
3428 break;
3429 case ppc64::kPointerDiff32:
3430 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3431 break;
3432 case ppc64::kPointerDiff64:
3433 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3434 break;
3435 case ppc64::kNoFixUp:
3436 case ppc64::kPointer:
3437 case ppc64::kPointerWeakImport:
3438 case ppc64::kPICBaseLow16:
3439 case ppc64::kPICBaseLow14:
3440 // ignore
3441 break;
3442 default:
3443 fprintf(stderr, "ld: warning codegen with reference kind %d in %s prevents image from loading in dyld shared cache\n", ref->getKind(), atom->getDisplayName());
3444 fSplitCodeToDataContentAtom->setCantEncode();
3445 }
3446 }
3447
3448 template <>
3449 void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3450 {
3451 switch ( (x86::ReferenceKinds)ref->getKind() ) {
3452 case x86::kPointerDiff:
3453 if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 )
3454 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
3455 else
3456 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3457 break;
3458 case x86::kNoFixUp:
3459 case x86::kPointer:
3460 case x86::kPointerWeakImport:
3461 // ignore
3462 break;
3463 case x86::kPCRel32:
3464 case x86::kPCRel32WeakImport:
3465 if ( (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
3466 || (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
3467 fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
3468 break;
3469 }
3470 // fall into warning case
3471 default:
3472 fprintf(stderr, "ld: warning codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache\n", atom->getDisplayName(), ref->getFixUpOffset());
3473 fSplitCodeToDataContentAtom->setCantEncode();
3474 }
3475 }
3476
3477 template <>
3478 void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
3479 {
3480 switch ( (x86_64::ReferenceKinds)ref->getKind() ) {
3481 case x86_64::kPCRel32:
3482 case x86_64::kPCRel32_1:
3483 case x86_64::kPCRel32_2:
3484 case x86_64::kPCRel32_4:
3485 case x86_64::kPCRel32GOTLoad:
3486 case x86_64::kPCRel32GOTLoadWeakImport:
3487 case x86_64::kPCRel32GOT:
3488 case x86_64::kPCRel32GOTWeakImport:
3489 case x86_64::kPointerDiff32:
3490 fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
3491 break;
3492 case x86_64::kPointerDiff:
3493 fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
3494 break;
3495 case x86_64::kNoFixUp:
3496 case x86_64::kPointer:
3497 // ignore
3498 break;
3499 default:
3500 fprintf(stderr, "ld: warning codegen in %s with kind %d prevents image from loading in dyld shared cache\n", atom->getDisplayName(), ref->getKind());
3501 fSplitCodeToDataContentAtom->setCantEncode();
3502 }
3503 }
3504
3505
3506 template <typename A>
3507 bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
3508 {
3509 switch ( to.getDefinitionKind() ) {
3510 case ObjectFile::Atom::kExternalDefinition:
3511 case ObjectFile::Atom::kExternalWeakDefinition:
3512 case ObjectFile::Atom::kAbsoluteSymbol:
3513 return false;
3514 case ObjectFile::Atom::kRegularDefinition:
3515 case ObjectFile::Atom::kWeakDefinition:
3516 case ObjectFile::Atom::kTentativeDefinition:
3517 // segments with same permissions slide together
3518 return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
3519 || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
3520 }
3521 throw "ld64 internal error";
3522 }
3523
3524
3525 template <>
3526 void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
3527 {
3528 uint32_t ppcNop;
3529 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
3530 for (uint32_t p=from; p < to; p += 4)
3531 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
3532 }
3533
3534 template <>
3535 void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
3536 {
3537 uint32_t ppcNop;
3538 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
3539 for (uint32_t p=from; p < to; p += 4)
3540 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
3541 }
3542
3543 template <>
3544 void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
3545 {
3546 uint8_t x86Nop = 0x90;
3547 for (uint32_t p=from; p < to; ++p)
3548 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
3549 }
3550
3551 template <>
3552 void Writer<x86_64>::writeNoOps(uint32_t from, uint32_t to)
3553 {
3554 uint8_t x86Nop = 0x90;
3555 for (uint32_t p=from; p < to; ++p)
3556 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
3557 }
3558
3559
3560 template <>
3561 void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
3562 {
3563 for (uint8_t* p=from; p < to; p += 4)
3564 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
3565 }
3566
3567 template <>
3568 void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
3569 {
3570 for (uint8_t* p=from; p < to; p += 4)
3571 OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
3572 }
3573
3574 template <>
3575 void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
3576 {
3577 for (uint8_t* p=from; p < to; ++p)
3578 *p = 0x90;
3579 }
3580
3581 template <>
3582 void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
3583 {
3584 for (uint8_t* p=from; p < to; ++p)
3585 *p = 0x90;
3586 }
3587
3588
3589 static const char* stringName(const char* str)
3590 {
3591 if ( strncmp(str, "cstring=", 8) == 0) {
3592 static char buffer[1024];
3593 char* t = buffer;
3594 *t++ = '\"';
3595 for(const char*s = &str[8]; *s != '\0'; ++s) {
3596 switch(*s) {
3597 case '\n':
3598 *t++ = '\\';
3599 *t++ = 'n';
3600 break;
3601 case '\t':
3602 *t++ = '\\';
3603 *t++ = 't';
3604 break;
3605 default:
3606 *t++ = *s;
3607 break;
3608 }
3609 if ( t > &buffer[1020] ) {
3610 *t++= '\"';
3611 *t++= '.';
3612 *t++= '.';
3613 *t++= '.';
3614 *t++= '\0';
3615 return buffer;
3616 }
3617 }
3618 *t++= '\"';
3619 *t++= '\0';
3620 return buffer;
3621 }
3622 else {
3623 return str;
3624 }
3625 }
3626
3627
3628 template <> const char* Writer<ppc>::getArchString() { return "ppc"; }
3629 template <> const char* Writer<ppc64>::getArchString() { return "ppc64"; }
3630 template <> const char* Writer<x86>::getArchString() { return "i386"; }
3631 template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
3632
3633 template <typename A>
3634 void Writer<A>::writeMap()
3635 {
3636 if ( fOptions.generatedMapPath() != NULL ) {
3637 FILE* mapFile = fopen(fOptions.generatedMapPath(), "w");
3638 if ( mapFile != NULL ) {
3639 // write output path
3640 fprintf(mapFile, "# Path: %s\n", fFilePath);
3641 // write output architecure
3642 fprintf(mapFile, "# Arch: %s\n", getArchString());
3643 // write UUID
3644 if ( fUUIDAtom != NULL ) {
3645 const uint8_t* uuid = fUUIDAtom->getUUID();
3646 fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
3647 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
3648 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
3649 }
3650 // write table of object files
3651 std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
3652 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
3653 std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
3654 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3655 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3656 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3657 if ( ! (*secit)->fVirtualSection ) {
3658 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3659 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3660 ObjectFile::Reader* reader = (*ait)->getFile();
3661 uint32_t readerOrdinal = (*ait)->getOrdinal();
3662 std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
3663 if ( pos == readerToOrdinal.end() ) {
3664 readerToOrdinal[reader] = readerOrdinal;
3665 ordinalToReader[readerOrdinal] = reader;
3666 }
3667 }
3668 }
3669 }
3670 }
3671 fprintf(mapFile, "# Object files:\n");
3672 fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
3673 uint32_t fileIndex = 0;
3674 readerToFileOrdinal[this] = fileIndex++;
3675 for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
3676 if ( it->first != 0 ) {
3677 fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
3678 readerToFileOrdinal[it->second] = fileIndex++;
3679 }
3680 }
3681 // write table of sections
3682 fprintf(mapFile, "# Sections:\n");
3683 fprintf(mapFile, "# Address\tSize \tSegment\tSection\n");
3684 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3685 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3686 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3687 if ( ! (*secit)->fVirtualSection ) {
3688 SectionInfo* sect = *secit;
3689 fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize,
3690 (*segit)->fName, sect->fSectionName);
3691 }
3692 }
3693 }
3694 // write table of symbols
3695 fprintf(mapFile, "# Symbols:\n");
3696 fprintf(mapFile, "# Address\tSize \tFile Name\n");
3697 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3698 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
3699 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3700 if ( ! (*secit)->fVirtualSection ) {
3701 std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
3702 bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
3703 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3704 ObjectFile::Atom* atom = *ait;
3705 fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(),
3706 readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
3707 }
3708 }
3709 }
3710 }
3711 fclose(mapFile);
3712 }
3713 else {
3714 fprintf(stderr, "ld: warning could not write map file: %s\n", fOptions.generatedMapPath());
3715 }
3716 }
3717 }
3718
3719 template <typename A>
3720 uint64_t Writer<A>::writeAtoms()
3721 {
3722 // try to allocate buffer for entire output file content
3723 SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
3724 uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
3725 uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
3726 uint8_t* atomBuffer = NULL;
3727 bool streaming = false;
3728 if ( wholeBuffer == NULL ) {
3729 atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
3730 streaming = true;
3731 }
3732 uint32_t size = 0;
3733 uint32_t end = 0;
3734 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
3735 SegmentInfo* curSegment = *segit;
3736 bool isTextSeg = (strcmp(curSegment->fName, "__TEXT") == 0);
3737 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
3738 for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
3739 SectionInfo* curSection = *secit;
3740 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
3741 //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
3742 //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
3743 if ( ! curSection->fAllZeroFill ) {
3744 end = curSection->fFileOffset;
3745 bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
3746 for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
3747 ObjectFile::Atom* atom = *ait;
3748 if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
3749 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
3750 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
3751 uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
3752 if ( fileOffset != end ) {
3753 if ( needsNops ) {
3754 // fill gaps with no-ops
3755 if ( streaming )
3756 writeNoOps(end, fileOffset);
3757 else
3758 copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
3759 }
3760 else if ( streaming ) {
3761 // zero fill gaps
3762 if ( (fileOffset-end) == 4 ) {
3763 uint32_t zero = 0;
3764 ::pwrite(fFileDescriptor, &zero, 4, end);
3765 }
3766 else {
3767 uint8_t zero = 0x00;
3768 for (uint32_t p=end; p < fileOffset; ++p)
3769 ::pwrite(fFileDescriptor, &zero, 1, p);
3770 }
3771 }
3772 }
3773 uint64_t atomSize = atom->getSize();
3774 if ( streaming ) {
3775 if ( atomSize > fLargestAtomSize )
3776 throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX",
3777 atom->getDisplayName(), atomSize, fLargestAtomSize);
3778 }
3779 else {
3780 if ( fileOffset > fileBufferSize )
3781 throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX",
3782 atom->getDisplayName(), fileOffset, fileBufferSize);
3783 }
3784 uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
3785 end = fileOffset+atomSize;
3786 // copy raw bytes
3787 atom->copyRawContent(buffer);
3788 // apply any fix-ups
3789 try {
3790 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
3791 for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
3792 ObjectFile::Reference* ref = *it;
3793 if ( fOptions.outputKind() == Options::kObjectFile ) {
3794 // doing ld -r
3795 // skip fix-ups for undefined targets
3796 if ( &(ref->getTarget()) != NULL )
3797 this->fixUpReferenceRelocatable(ref, atom, buffer);
3798 }
3799 else {
3800 // producing final linked image
3801 this->fixUpReferenceFinal(ref, atom, buffer);
3802 }
3803 }
3804 }
3805 catch (const char* msg) {
3806 throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
3807 }
3808 //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n",
3809 // fileOffset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
3810 if ( streaming ) {
3811 // write out
3812 ::pwrite(fFileDescriptor, buffer, atomSize, fileOffset);
3813 }
3814 else {
3815 if ( (fileOffset + atomSize) > size )
3816 size = fileOffset + atomSize;
3817 }
3818 }
3819 }
3820 }
3821 }
3822 }
3823
3824 // update content based UUID
3825 if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
3826 uint8_t digest[CC_MD5_DIGEST_LENGTH];
3827 if ( streaming ) {
3828 // if output file file did not fit in memory, re-read file to generate md5 hash
3829 uint32_t kMD5BufferSize = 16*1024;
3830 uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
3831 if ( md5Buffer != NULL ) {
3832 CC_MD5_CTX md5State;
3833 CC_MD5_Init(&md5State);
3834 ::lseek(fFileDescriptor, 0, SEEK_SET);
3835 ssize_t len;
3836 while ( (len = ::read(fFileDescriptor, md5Buffer, kMD5BufferSize)) > 0 )
3837 CC_MD5_Update(&md5State, md5Buffer, len);
3838 CC_MD5_Final(digest, &md5State);
3839 ::free(md5Buffer);
3840 }
3841 else {
3842 // if malloc fails, fall back to random uuid
3843 ::uuid_generate_random(digest);
3844 }
3845 fUUIDAtom->setContent(digest);
3846 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
3847 fUUIDAtom->copyRawContent(atomBuffer);
3848 ::pwrite(fFileDescriptor, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
3849 }
3850 else {
3851 // if output file fit in memory, just genrate an md5 hash in memory
3852 CC_MD5(wholeBuffer, size, digest);
3853 fUUIDAtom->setContent(digest);
3854 uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
3855 fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
3856 }
3857 }
3858
3859 // finish up
3860 if ( streaming ) {
3861 delete [] atomBuffer;
3862 }
3863 else {
3864 // write whole output file in one chunk
3865 ::pwrite(fFileDescriptor, wholeBuffer, size, 0);
3866 delete [] wholeBuffer;
3867 }
3868
3869 close(fFileDescriptor);
3870 return end;
3871 }
3872
3873
3874 template <>
3875 void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
3876 {
3877 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
3878 uint8_t* dtraceProbeSite;
3879 const int64_t kTwoGigLimit = 0x7FFFFFFF;
3880 const int64_t kSixtyFourKiloLimit = 0x7FFF;
3881 int64_t displacement;
3882 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
3883 switch ( kind ) {
3884 case x86::kNoFixUp:
3885 case x86::kFollowOn:
3886 // do nothing
3887 break;
3888 case x86::kPointerWeakImport:
3889 case x86::kPointer:
3890 {
3891 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
3892 if ( fOptions.prebind() ) {
3893 switch (ref->getTarget().getDefinitionKind()) {
3894 case ObjectFile::Atom::kExternalDefinition:
3895 case ObjectFile::Atom::kExternalWeakDefinition:
3896 // prebound external relocation ==> pointer contains addend
3897 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3898 break;
3899 case ObjectFile::Atom::kTentativeDefinition:
3900 case ObjectFile::Atom::kRegularDefinition:
3901 case ObjectFile::Atom::kWeakDefinition:
3902 // prebound external relocation to internal atom ==> pointer contains target address + addend
3903 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3904 break;
3905 case ObjectFile::Atom::kAbsoluteSymbol:
3906 break;
3907 }
3908 }
3909 else {
3910 // external realocation ==> pointer contains addend
3911 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3912 }
3913 }
3914 else {
3915 // pointer contains target address
3916 //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
3917 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3918 }
3919 }
3920 break;
3921 case x86::kPointerDiff:
3922 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
3923 LittleEndian::set32(*fixUp, (uint32_t)displacement);
3924 break;
3925 case x86::kPointerDiff16:
3926 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
3927 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
3928 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
3929 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
3930 break;
3931 case x86::kDtraceProbeSite:
3932 // change call site to a NOP
3933 dtraceProbeSite = (uint8_t*)fixUp;
3934 dtraceProbeSite[-1] = 0x90; // 1-byte nop
3935 dtraceProbeSite[0] = 0x0F; // 4-byte nop
3936 dtraceProbeSite[1] = 0x1F;
3937 dtraceProbeSite[2] = 0x40;
3938 dtraceProbeSite[3] = 0x00;
3939 break;
3940 case x86::kDtraceIsEnabledSite:
3941 // change call site to a clear eax
3942 dtraceProbeSite = (uint8_t*)fixUp;
3943 dtraceProbeSite[-1] = 0x33; // xorl eax,eax
3944 dtraceProbeSite[0] = 0xC0;
3945 dtraceProbeSite[1] = 0x90; // 1-byte nop
3946 dtraceProbeSite[2] = 0x90; // 1-byte nop
3947 dtraceProbeSite[3] = 0x90; // 1-byte nop
3948 break;
3949 case x86::kPCRel32WeakImport:
3950 case x86::kPCRel32:
3951 case x86::kPCRel16:
3952 displacement = 0;
3953 switch ( ref->getTarget().getDefinitionKind() ) {
3954 case ObjectFile::Atom::kRegularDefinition:
3955 case ObjectFile::Atom::kWeakDefinition:
3956 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
3957 break;
3958 case ObjectFile::Atom::kExternalDefinition:
3959 case ObjectFile::Atom::kExternalWeakDefinition:
3960 throw "codegen problem, can't use rel32 to external symbol";
3961 case ObjectFile::Atom::kTentativeDefinition:
3962 displacement = 0;
3963 break;
3964 case ObjectFile::Atom::kAbsoluteSymbol:
3965 displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
3966 break;
3967 }
3968 if ( kind == x86::kPCRel16 ) {
3969 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
3970 //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());
3971 throwf("rel16 out of range in %s", inAtom->getDisplayName());
3972 }
3973 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
3974 }
3975 else {
3976 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
3977 //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());
3978 throwf("rel32 out of range in %s", inAtom->getDisplayName());
3979 }
3980 LittleEndian::set32(*fixUp, (int32_t)displacement);
3981 }
3982 break;
3983 case x86::kAbsolute32:
3984 switch ( ref->getTarget().getDefinitionKind() ) {
3985 case ObjectFile::Atom::kRegularDefinition:
3986 case ObjectFile::Atom::kWeakDefinition:
3987 case ObjectFile::Atom::kTentativeDefinition:
3988 // pointer contains target address
3989 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
3990 break;
3991 case ObjectFile::Atom::kExternalDefinition:
3992 case ObjectFile::Atom::kExternalWeakDefinition:
3993 // external realocation ==> pointer contains addend
3994 LittleEndian::set32(*fixUp, ref->getTargetOffset());
3995 break;
3996 case ObjectFile::Atom::kAbsoluteSymbol:
3997 // pointer contains target address
3998 LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
3999 break;
4000 }
4001 break;
4002 case x86::kDtraceTypeReference:
4003 case x86::kDtraceProbe:
4004 // nothing to fix up
4005 break;
4006 }
4007 }
4008
4009
4010
4011 template <>
4012 void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4013 {
4014 const int64_t kTwoGigLimit = 0x7FFFFFFF;
4015 const int64_t kSixtyFourKiloLimit = 0x7FFF;
4016 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4017 bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());
4018 int64_t displacement;
4019 x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
4020 switch ( kind ) {
4021 case x86::kNoFixUp:
4022 case x86::kFollowOn:
4023 // do nothing
4024 break;
4025 case x86::kPointer:
4026 case x86::kPointerWeakImport:
4027 case x86::kAbsolute32:
4028 {
4029 if ( isExtern ) {
4030 // external realocation ==> pointer contains addend
4031 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4032 }
4033 else if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4034 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
4035 if ( this->indirectSymbolIsLocal(ref) )
4036 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4037 else
4038 LittleEndian::set32(*fixUp, 0);
4039 }
4040 else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
4041 // internal relocation => pointer contains target address
4042 LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4043 }
4044 else {
4045 // internal relocation to tentative ==> pointer contains addend
4046 LittleEndian::set32(*fixUp, ref->getTargetOffset());
4047 }
4048 }
4049 break;
4050 case x86::kPointerDiff:
4051 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4052 LittleEndian::set32(*fixUp, (uint32_t)displacement);
4053 break;
4054 case x86::kPointerDiff16:
4055 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4056 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) )
4057 throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
4058 LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
4059 break;
4060 case x86::kPCRel16:
4061 case x86::kPCRel32:
4062 case x86::kPCRel32WeakImport:
4063 case x86::kDtraceProbeSite:
4064 case x86::kDtraceIsEnabledSite:
4065 {
4066 if ( isExtern )
4067 displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4068 else
4069 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4070 if ( kind == x86::kPCRel16 ) {
4071 displacement += 2;
4072 if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
4073 //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());
4074 throwf("rel16 out of range in %s", inAtom->getDisplayName());
4075 }
4076 int16_t word = (int16_t)displacement;
4077 LittleEndian::set16(*((uint16_t*)fixUp), word);
4078 }
4079 else {
4080 if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
4081 //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());
4082 throwf("rel32 out of range in %s", inAtom->getDisplayName());
4083 }
4084 LittleEndian::set32(*fixUp, (int32_t)displacement);
4085 }
4086 }
4087 break;
4088 case x86::kDtraceProbe:
4089 case x86::kDtraceTypeReference:
4090 // nothing to fix up
4091 break;
4092 }
4093 }
4094
4095 template <>
4096 void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4097 {
4098 const int64_t twoGigLimit = 0x7FFFFFFF;
4099 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
4100 uint8_t* dtraceProbeSite;
4101 int64_t displacement = 0;
4102 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
4103 case x86_64::kNoFixUp:
4104 case x86_64::kFollowOn:
4105 // do nothing
4106 break;
4107 case x86_64::kPointerWeakImport:
4108 case x86_64::kPointer:
4109 {
4110 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
4111 if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
4112 // external realocation ==> pointer contains addend
4113 LittleEndian::set64(*fixUp, ref->getTargetOffset());
4114 }
4115 else {
4116 // internal relocation
4117 // pointer contains target address
4118 //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
4119 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4120 }
4121 }
4122 break;
4123 case x86_64::kPointerDiff32:
4124 displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
4125 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
4126 throw "32-bit pointer difference out of range";
4127 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
4128 break;
4129 case x86_64::kPointerDiff:
4130 LittleEndian::set64(*fixUp,
4131 (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4132 break;
4133 case x86_64::kPCRel32GOTLoad:
4134 case x86_64::kPCRel32GOTLoadWeakImport:
4135 // if GOT entry was optimized away, change movq instruction to a leaq
4136 if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
4137 //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
4138 uint8_t* opcodes = (uint8_t*)fixUp;
4139 if ( opcodes[-2] != 0x8B )
4140 throw "GOT load reloc does not point to a movq instruction";
4141 opcodes[-2] = 0x8D;
4142 }
4143 // fall into general rel32 case
4144 case x86_64::kBranchPCRel32WeakImport:
4145 case x86_64::kBranchPCRel32:
4146 case x86_64::kPCRel32:
4147 case x86_64::kPCRel32_1:
4148 case x86_64::kPCRel32_2:
4149 case x86_64::kPCRel32_4:
4150 case x86_64::kPCRel32GOT:
4151 case x86_64::kPCRel32GOTWeakImport:
4152 switch ( ref->getTarget().getDefinitionKind() ) {
4153 case ObjectFile::Atom::kRegularDefinition:
4154 case ObjectFile::Atom::kWeakDefinition:
4155 case ObjectFile::Atom::kTentativeDefinition:
4156 displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4157 break;
4158 case ObjectFile::Atom::kAbsoluteSymbol:
4159 displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4160 break;
4161 case ObjectFile::Atom::kExternalDefinition:
4162 case ObjectFile::Atom::kExternalWeakDefinition:
4163 throw "codegen problem, can't use rel32 to external symbol";
4164 break;
4165 }
4166 switch ( ref->getKind() ) {
4167 case x86_64::kPCRel32_1:
4168 displacement -= 1;
4169 break;
4170 case x86_64::kPCRel32_2:
4171 displacement -= 2;
4172 break;
4173 case x86_64::kPCRel32_4:
4174 displacement -= 4;
4175 break;
4176 }
4177 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
4178 fprintf(stderr, "call out of range from %s (%llX) in %s to %s (%llX) in %s\n",
4179 inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
4180 throw "rel32 out of range";
4181 }
4182 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
4183 break;
4184 case x86_64::kDtraceProbeSite:
4185 // change call site to a NOP
4186 dtraceProbeSite = (uint8_t*)fixUp;
4187 dtraceProbeSite[-1] = 0x90; // 1-byte nop
4188 dtraceProbeSite[0] = 0x0F; // 4-byte nop
4189 dtraceProbeSite[1] = 0x1F;
4190 dtraceProbeSite[2] = 0x40;
4191 dtraceProbeSite[3] = 0x00;
4192 break;
4193 case x86_64::kDtraceIsEnabledSite:
4194 // change call site to a clear eax
4195 dtraceProbeSite = (uint8_t*)fixUp;
4196 dtraceProbeSite[-1] = 0x48; // xorq eax,eax
4197 dtraceProbeSite[0] = 0x33;
4198 dtraceProbeSite[1] = 0xC0;
4199 dtraceProbeSite[2] = 0x90; // 1-byte nop
4200 dtraceProbeSite[3] = 0x90; // 1-byte nop
4201 break;
4202 case x86_64::kDtraceTypeReference:
4203 case x86_64::kDtraceProbe:
4204 // nothing to fix up
4205 break;
4206 }
4207 }
4208
4209 template <>
4210 void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4211 {
4212 const int64_t twoGigLimit = 0x7FFFFFFF;
4213 bool external = this->makesExternalRelocatableReference(ref->getTarget());
4214 uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
4215 int64_t displacement = 0;
4216 int32_t temp32;
4217 switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
4218 case x86_64::kNoFixUp:
4219 case x86_64::kFollowOn:
4220 // do nothing
4221 break;
4222 case x86_64::kPointer:
4223 case x86_64::kPointerWeakImport:
4224 {
4225 if ( external ) {
4226 // external realocation ==> pointer contains addend
4227 LittleEndian::set64(*fixUp, ref->getTargetOffset());
4228 }
4229 else {
4230 // internal relocation ==> pointer contains target address
4231 LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
4232 }
4233 }
4234 break;
4235 case x86_64::kPointerDiff32:
4236 // addend in content
4237 LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
4238 break;
4239 case x86_64::kPointerDiff:
4240 // addend in content
4241 LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
4242 break;
4243 case x86_64::kBranchPCRel32:
4244 case x86_64::kBranchPCRel32WeakImport:
4245 case x86_64::kDtraceProbeSite:
4246 case x86_64::kDtraceIsEnabledSite:
4247 case x86_64::kPCRel32:
4248 case x86_64::kPCRel32_1:
4249 case x86_64::kPCRel32_2:
4250 case x86_64::kPCRel32_4:
4251 // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
4252 temp32 = ref->getTargetOffset();
4253 if ( external ) {
4254 // extern relocation contains addend
4255 displacement = temp32;
4256 }
4257 else {
4258 // internal relocations contain delta to target address
4259 displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
4260 }
4261 switch ( ref->getKind() ) {
4262 case x86_64::kPCRel32_1:
4263 displacement -= 1;
4264 break;
4265 case x86_64::kPCRel32_2:
4266 displacement -= 2;
4267 break;
4268 case x86_64::kPCRel32_4:
4269 displacement -= 4;
4270 break;
4271 }
4272 if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
4273 //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());
4274 throw "rel32 out of range";
4275 }
4276 LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
4277 break;
4278 case x86_64::kPCRel32GOT:
4279 case x86_64::kPCRel32GOTLoad:
4280 case x86_64::kPCRel32GOTWeakImport:
4281 case x86_64::kPCRel32GOTLoadWeakImport:
4282 // contains addend (usually zero)
4283 LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
4284 break;
4285 case x86_64::kDtraceTypeReference:
4286 case x86_64::kDtraceProbe:
4287 // nothing to fix up
4288 break;
4289 }
4290 }
4291
4292 template <>
4293 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4294 {
4295 fixUpReference_powerpc(ref, inAtom, buffer, true);
4296 }
4297
4298 template <>
4299 void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4300 {
4301 fixUpReference_powerpc(ref, inAtom, buffer, true);
4302 }
4303
4304 template <>
4305 void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4306 {
4307 fixUpReference_powerpc(ref, inAtom, buffer, false);
4308 }
4309
4310 template <>
4311 void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
4312 {
4313 fixUpReference_powerpc(ref, inAtom, buffer, false);
4314 }
4315
4316 //
4317 // ppc and ppc64 are mostly the same, so they share a template specialzation
4318 //
4319 template <typename A>
4320 void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
4321 {
4322 uint32_t instruction;
4323 uint32_t newInstruction;
4324 int64_t displacement;
4325 uint64_t targetAddr = 0;
4326 uint64_t picBaseAddr;
4327 uint16_t instructionLowHalf;
4328 uint16_t instructionHighHalf;
4329 uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
4330 pint_t* fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
4331 bool relocateableExternal = false;
4332 const int64_t picbase_twoGigLimit = 0x80000000;
4333
4334 if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
4335 targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
4336 if ( finalLinkedImage )
4337 relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
4338 else
4339 relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());
4340 }
4341
4342 switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
4343 case A::kNoFixUp:
4344 case A::kFollowOn:
4345 // do nothing
4346 break;
4347 case A::kPointerWeakImport:
4348 case A::kPointer:
4349 {
4350 //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
4351 if ( finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllLazyPointers ) {
4352 if ( fOptions.prebind() ) {
4353 switch (ref->getTarget().getDefinitionKind()) {
4354 case ObjectFile::Atom::kExternalDefinition:
4355 case ObjectFile::Atom::kExternalWeakDefinition:
4356 // prebound lazy pointer to another dylib ==> pointer contains zero
4357 P::setP(*fixUpPointer, 0);
4358 break;
4359 case ObjectFile::Atom::kTentativeDefinition:
4360 case ObjectFile::Atom::kRegularDefinition:
4361 case ObjectFile::Atom::kWeakDefinition:
4362 // prebound lazy pointer to withing this dylib ==> pointer contains address
4363 P::setP(*fixUpPointer, targetAddr);
4364 break;
4365 case ObjectFile::Atom::kAbsoluteSymbol:
4366 break;
4367 }
4368 }
4369 else {
4370 // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
4371 if ( fDyldHelper == NULL )
4372 throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
4373 P::setP(*fixUpPointer, fDyldHelper->getAddress());
4374 }
4375 }
4376 else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
4377 // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
4378 if ( this->indirectSymbolIsLocal(ref) )
4379 P::setP(*fixUpPointer, targetAddr);
4380 else
4381 P::setP(*fixUpPointer, 0);
4382 }
4383 else if ( relocateableExternal ) {
4384 if ( fOptions.prebind() ) {
4385 switch (ref->getTarget().getDefinitionKind()) {
4386 case ObjectFile::Atom::kExternalDefinition:
4387 case ObjectFile::Atom::kExternalWeakDefinition:
4388 // prebound external relocation ==> pointer contains addend
4389 P::setP(*fixUpPointer, ref->getTargetOffset());
4390 break;
4391 case ObjectFile::Atom::kTentativeDefinition:
4392 case ObjectFile::Atom::kRegularDefinition:
4393 case ObjectFile::Atom::kWeakDefinition:
4394 // prebound external relocation to internal atom ==> pointer contains target address + addend
4395 P::setP(*fixUpPointer, targetAddr);
4396 break;
4397 case ObjectFile::Atom::kAbsoluteSymbol:
4398 break;
4399 }
4400 }
4401 else {
4402 // external realocation ==> pointer contains addend
4403 P::setP(*fixUpPointer, ref->getTargetOffset());
4404 }
4405 }
4406 else {
4407 // internal relocation
4408 if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
4409 // pointer contains target address
4410 //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n", ref->getTarget().getDisplayName(), targetAddr);
4411 P::setP(*fixUpPointer, targetAddr);
4412 }
4413 else {
4414 // pointer contains addend
4415 P::setP(*fixUpPointer, ref->getTargetOffset());
4416 }
4417 }
4418 }
4419 break;
4420 case A::kPointerDiff64:
4421 P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4422 break;
4423 case A::kPointerDiff32:
4424 P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4425 break;
4426 case A::kPointerDiff16:
4427 P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
4428 break;
4429 case A::kDtraceProbeSite:
4430 if ( finalLinkedImage ) {
4431 // change call site to a NOP
4432 BigEndian::set32(*fixUp, 0x60000000);
4433 }
4434 else {
4435 // set bl instuction to branch to address zero in .o file
4436 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
4437 instruction = BigEndian::get32(*fixUp);
4438 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4439 BigEndian::set32(*fixUp, newInstruction);
4440 }
4441 break;
4442 case A::kDtraceIsEnabledSite:
4443 if ( finalLinkedImage ) {
4444 // change call site to a li r3,0
4445 BigEndian::set32(*fixUp, 0x38600000);
4446 }
4447 else {
4448 // set bl instuction to branch to address zero in .o file
4449 int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
4450 instruction = BigEndian::get32(*fixUp);
4451 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4452 BigEndian::set32(*fixUp, newInstruction);
4453 }
4454 break;
4455 case A::kBranch24WeakImport:
4456 case A::kBranch24:
4457 {
4458 //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
4459 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4460 if ( relocateableExternal ) {
4461 // doing "ld -r" to an external symbol
4462 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4463 displacement -= ref->getTarget().getAddress();
4464 }
4465 else {
4466 const int64_t bl_eightMegLimit = 0x00FFFFFF;
4467 if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
4468 //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());
4469 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",
4470 displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
4471 ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
4472 }
4473 }
4474 instruction = BigEndian::get32(*fixUp);
4475 newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
4476 //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
4477 BigEndian::set32(*fixUp, newInstruction);
4478 }
4479 break;
4480 case A::kBranch14:
4481 {
4482 //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
4483 int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
4484 if ( relocateableExternal ) {
4485 // doing "ld -r" to an external symbol
4486 // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
4487 displacement -= ref->getTarget().getAddress();
4488 }
4489 else {
4490 const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
4491 if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
4492 //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());
4493 throwf("bc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
4494 displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
4495 ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
4496 }
4497 }
4498 //fprintf(stderr, "bc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
4499 instruction = BigEndian::get32(*fixUp);
4500 newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
4501 //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
4502 BigEndian::set32(*fixUp, newInstruction);
4503 }
4504 break;
4505 case A::kPICBaseLow16:
4506 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4507 displacement = targetAddr - picBaseAddr;
4508 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4509 throw "32-bit pic-base out of range";
4510 instructionLowHalf = (displacement & 0xFFFF);
4511 instruction = BigEndian::get32(*fixUp);
4512 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4513 BigEndian::set32(*fixUp, newInstruction);
4514 break;
4515 case A::kPICBaseLow14:
4516 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4517 displacement = targetAddr - picBaseAddr;
4518 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4519 throw "32-bit pic-base out of range";
4520 if ( (displacement & 0x3) != 0 )
4521 throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
4522 instructionLowHalf = (displacement & 0xFFFC);
4523 instruction = BigEndian::get32(*fixUp);
4524 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
4525 BigEndian::set32(*fixUp, newInstruction);
4526 break;
4527 case A::kPICBaseHigh16:
4528 picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
4529 displacement = targetAddr - picBaseAddr;
4530 if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
4531 throw "32-bit pic-base out of range";
4532 instructionLowHalf = displacement >> 16;
4533 if ( (displacement & 0x00008000) != 0 )
4534 ++instructionLowHalf;
4535 instruction = BigEndian::get32(*fixUp);
4536 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4537 BigEndian::set32(*fixUp, newInstruction);
4538 break;
4539 case A::kAbsLow16:
4540 if ( relocateableExternal && !finalLinkedImage )
4541 targetAddr -= ref->getTarget().getAddress();
4542 instructionLowHalf = (targetAddr & 0xFFFF);
4543 instruction = BigEndian::get32(*fixUp);
4544 newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
4545 BigEndian::set32(*fixUp, newInstruction);
4546 break;
4547 case A::kAbsLow14:
4548 if ( relocateableExternal && !finalLinkedImage )
4549 targetAddr -= ref->getTarget().getAddress();
4550 if ( (targetAddr & 0x3) != 0 )
4551 throw "bad address for absolute lo14 instruction fix-up";
4552 instructionLowHalf = (targetAddr & 0xFFFF);
4553 instruction = BigEndian::get32(*fixUp);
4554 newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
4555 BigEndian::set32(*fixUp, newInstruction);
4556 break;
4557 case A::kAbsHigh16:
4558 if ( relocateableExternal ) {
4559 if ( finalLinkedImage ) {
4560 switch (ref->getTarget().getDefinitionKind()) {
4561 case ObjectFile::Atom::kExternalDefinition:
4562 case ObjectFile::Atom::kExternalWeakDefinition:
4563 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
4564 break;
4565 case ObjectFile::Atom::kTentativeDefinition:
4566 case ObjectFile::Atom::kRegularDefinition:
4567 case ObjectFile::Atom::kWeakDefinition:
4568 // use target address
4569 break;
4570 case ObjectFile::Atom::kAbsoluteSymbol:
4571 targetAddr = ref->getTarget().getSectionOffset();
4572 break;
4573 }
4574 }
4575 else {
4576 targetAddr -= ref->getTarget().getAddress();
4577 }
4578 }
4579 instructionHighHalf = (targetAddr >> 16);
4580 instruction = BigEndian::get32(*fixUp);
4581 newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
4582 BigEndian::set32(*fixUp, newInstruction);
4583 break;
4584 case A::kAbsHigh16AddLow:
4585 if ( relocateableExternal ) {
4586 if ( finalLinkedImage ) {
4587 switch (ref->getTarget().getDefinitionKind()) {
4588 case ObjectFile::Atom::kExternalDefinition:
4589 case ObjectFile::Atom::kExternalWeakDefinition:
4590 throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
4591 break;
4592 case ObjectFile::Atom::kTentativeDefinition:
4593 case ObjectFile::Atom::kRegularDefinition:
4594 case ObjectFile::Atom::kWeakDefinition:
4595 // use target address
4596 break;
4597 case ObjectFile::Atom::kAbsoluteSymbol:
4598 targetAddr = ref->getTarget().getSectionOffset();
4599 break;
4600 }
4601 }
4602 else {
4603 targetAddr -= ref->getTarget().getAddress();
4604 }
4605 }
4606 if ( targetAddr & 0x00008000 )
4607 targetAddr += 0x00010000;
4608 instruction = BigEndian::get32(*fixUp);
4609 newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
4610 BigEndian::set32(*fixUp, newInstruction);
4611 break;
4612 case A::kDtraceTypeReference:
4613 case A::kDtraceProbe:
4614 // nothing to fix up
4615 break;
4616 }
4617 }
4618
4619 template <>
4620 bool Writer<ppc>::stubableReference(const ObjectFile::Reference* ref)
4621 {
4622 uint8_t kind = ref->getKind();
4623 switch ( (ppc::ReferenceKinds)kind ) {
4624 case ppc::kNoFixUp:
4625 case ppc::kFollowOn:
4626 case ppc::kPointer:
4627 case ppc::kPointerWeakImport:
4628 case ppc::kPointerDiff16:
4629 case ppc::kPointerDiff32:
4630 case ppc::kPointerDiff64:
4631 case ppc::kDtraceProbe:
4632 case ppc::kDtraceProbeSite:
4633 case ppc::kDtraceIsEnabledSite:
4634 case ppc::kDtraceTypeReference:
4635 // these are never used to call external functions
4636 return false;
4637 case ppc::kBranch24:
4638 case ppc::kBranch24WeakImport:
4639 case ppc::kBranch14:
4640 // these are used to call external functions
4641 return true;
4642 case ppc::kPICBaseLow16:
4643 case ppc::kPICBaseLow14:
4644 case ppc::kPICBaseHigh16:
4645 case ppc::kAbsLow16:
4646 case ppc::kAbsLow14:
4647 case ppc::kAbsHigh16:
4648 case ppc::kAbsHigh16AddLow:
4649 // these are only used to call external functions
4650 // in -mlong-branch stubs
4651 switch ( ref->getTarget().getDefinitionKind() ) {
4652 case ObjectFile::Atom::kExternalDefinition:
4653 case ObjectFile::Atom::kExternalWeakDefinition:
4654 return true;
4655 case ObjectFile::Atom::kTentativeDefinition:
4656 case ObjectFile::Atom::kRegularDefinition:
4657 case ObjectFile::Atom::kWeakDefinition:
4658 case ObjectFile::Atom::kAbsoluteSymbol:
4659 return false;
4660 }
4661 break;
4662 }
4663 return false;
4664 }
4665
4666
4667 template <>
4668 bool Writer<ppc64>::stubableReference(const ObjectFile::Reference* ref)
4669 {
4670 uint8_t kind = ref->getKind();
4671 switch ( (ppc64::ReferenceKinds)kind ) {
4672 case ppc::kNoFixUp:
4673 case ppc::kFollowOn:
4674 case ppc::kPointer:
4675 case ppc::kPointerWeakImport:
4676 case ppc::kPointerDiff16:
4677 case ppc::kPointerDiff32:
4678 case ppc::kPointerDiff64:
4679 case ppc::kPICBaseLow16:
4680 case ppc::kPICBaseLow14:
4681 case ppc::kPICBaseHigh16:
4682 case ppc::kAbsLow16:
4683 case ppc::kAbsLow14:
4684 case ppc::kAbsHigh16:
4685 case ppc::kAbsHigh16AddLow:
4686 case ppc::kDtraceProbe:
4687 case ppc::kDtraceProbeSite:
4688 case ppc::kDtraceIsEnabledSite:
4689 case ppc::kDtraceTypeReference:
4690 // these are never used to call external functions
4691 return false;
4692 case ppc::kBranch24:
4693 case ppc::kBranch24WeakImport:
4694 case ppc::kBranch14:
4695 // these are used to call external functions
4696 return true;
4697 }
4698 return false;
4699 }
4700
4701 template <>
4702 bool Writer<x86>::stubableReference(const ObjectFile::Reference* ref)
4703 {
4704 uint8_t kind = ref->getKind();
4705 return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
4706 }
4707
4708 template <>
4709 bool Writer<x86_64>::stubableReference(const ObjectFile::Reference* ref)
4710 {
4711 uint8_t kind = ref->getKind();
4712 return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
4713 }
4714
4715
4716 template <>
4717 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
4718 {
4719 return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
4720 }
4721
4722 template <>
4723 bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
4724 {
4725 return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
4726 }
4727
4728 template <>
4729 bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
4730 {
4731 return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
4732 }
4733
4734 template <>
4735 bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
4736 {
4737 switch ( kind ) {
4738 case x86_64::kPointerWeakImport:
4739 case x86_64::kBranchPCRel32WeakImport:
4740 case x86_64::kPCRel32GOTWeakImport:
4741 case x86_64::kPCRel32GOTLoadWeakImport:
4742 return true;
4743 }
4744 return false;
4745 }
4746
4747
4748
4749 template <>
4750 bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
4751 {
4752 return false;
4753 }
4754
4755 template <>
4756 bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
4757 {
4758 return false;
4759 }
4760
4761 template <>
4762 bool Writer<x86>::GOTReferenceKind(uint8_t kind)
4763 {
4764 return false;
4765 }
4766
4767 template <>
4768 bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
4769 {
4770 switch ( kind ) {
4771 case x86_64::kPCRel32GOT:
4772 case x86_64::kPCRel32GOTWeakImport:
4773 case x86_64::kPCRel32GOTLoad:
4774 case x86_64::kPCRel32GOTLoadWeakImport:
4775 return true;
4776 }
4777 return false;
4778 }
4779
4780 template <>
4781 bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
4782 {
4783 return false;
4784 }
4785
4786 template <>
4787 bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
4788 {
4789 return false;
4790 }
4791
4792 template <>
4793 bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
4794 {
4795 return false;
4796 }
4797
4798 template <>
4799 bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
4800 {
4801 switch ( kind ) {
4802 case x86_64::kPCRel32GOTLoad:
4803 case x86_64::kPCRel32GOTLoadWeakImport:
4804 return true;
4805 }
4806 return false;
4807 }
4808
4809
4810
4811 // 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
4812 template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
4813 template <> bool Writer<ppc64>::needsModuleTable() { return false; }
4814 template <> bool Writer<x86_64>::needsModuleTable() { return false; }
4815
4816
4817 template <typename A>
4818 void Writer<A>::optimizeDylibReferences()
4819 {
4820 //fprintf(stderr, "original ordinals table:\n");
4821 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4822 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
4823 //}
4824 // find unused dylibs that can be removed
4825 std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
4826 std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
4827 for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4828 ObjectFile::Reader* reader = it->first;
4829 std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
4830 if ( aliasPos != fLibraryAliases.end() ) {
4831 // already noticed that this reader has same install name as another reader
4832 readerAliases[reader] = aliasPos->second;
4833 }
4834 else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || fOptions.deadStripDylibs()) ) {
4835 // this reader can be optimized away
4836 it->second = 0xFFFFFFFF;
4837 typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
4838 if ( pos != fLibraryToLoadCommand.end() )
4839 pos->second->optimizeAway();
4840 }
4841 else {
4842 // mark this reader as using it ordinal
4843 std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
4844 if ( pos == ordinalToReader.end() )
4845 ordinalToReader[it->second] = reader;
4846 else
4847 readerAliases[reader] = pos->second;
4848 }
4849 }
4850 // renumber ordinals (depends on iterator walking in ordinal order)
4851 uint32_t newOrdinal = 0;
4852 for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
4853 if ( it->first <= fLibraryToOrdinal.size() )
4854 fLibraryToOrdinal[it->second] = ++newOrdinal;
4855 }
4856
4857 // add aliases (e.g. -lm points to libSystem.dylib)
4858 for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
4859 fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
4860 }
4861
4862 // fprintf(stderr, "new ordinals table:\n");
4863 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
4864 // fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
4865 //}
4866 }
4867
4868
4869 template <>
4870 void Writer<x86_64>::scanForAbsoluteReferences()
4871 {
4872 // x86_64 codegen never has absolute references
4873 }
4874
4875 template <>
4876 void Writer<x86>::scanForAbsoluteReferences()
4877 {
4878 // when linking -pie verify there are no absolute addressing
4879 if ( fOptions.positionIndependentExecutable() ) {
4880 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4881 ObjectFile::Atom* atom = *it;
4882 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4883 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4884 ObjectFile::Reference* ref = *rit;
4885 switch (ref->getKind()) {
4886 case x86::kAbsolute32:
4887 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4888 return;
4889 }
4890 }
4891 }
4892 }
4893 }
4894
4895 template <>
4896 void Writer<ppc>::scanForAbsoluteReferences()
4897 {
4898 // when linking -pie verify there are no absolute addressing
4899 if ( fOptions.positionIndependentExecutable() ) {
4900 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4901 ObjectFile::Atom* atom = *it;
4902 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4903 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4904 ObjectFile::Reference* ref = *rit;
4905 switch (ref->getKind()) {
4906 case ppc::kAbsLow16:
4907 case ppc::kAbsLow14:
4908 case ppc::kAbsHigh16:
4909 case ppc::kAbsHigh16AddLow:
4910 throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4911 return;
4912 }
4913 }
4914 }
4915 }
4916 }
4917
4918
4919 // for ppc64 look for any -mdynamic-no-pic codegen
4920 template <>
4921 void Writer<ppc64>::scanForAbsoluteReferences()
4922 {
4923 // only do this for main executable
4924 if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
4925 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4926 ObjectFile::Atom* atom = *it;
4927 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4928 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4929 ObjectFile::Reference* ref = *rit;
4930 switch (ref->getKind()) {
4931 case ppc64::kAbsLow16:
4932 case ppc64::kAbsLow14:
4933 case ppc64::kAbsHigh16:
4934 case ppc64::kAbsHigh16AddLow:
4935 //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
4936 // shrink page-zero and add pad segment to compensate
4937 fPadSegmentInfo = new SegmentInfo();
4938 strcpy(fPadSegmentInfo->fName, "__4GBFILL");
4939 fPageZeroAtom->setSize(0x1000);
4940 return;
4941 }
4942 }
4943 }
4944 }
4945 }
4946
4947
4948 template <typename A>
4949 void Writer<A>::insertDummyStubs()
4950 {
4951 // only needed for x86
4952 }
4953
4954 template <>
4955 void Writer<x86>::insertDummyStubs()
4956 {
4957 // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
4958 std::vector<class StubAtom<x86>*> betterStubs;
4959 for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
4960 switch (betterStubs.size() % 64 ) {
4961 case 12:// stub would occupy 0x3C->0x41
4962 case 25:// stub would occupy 0x7D->0x82
4963 case 38:// stub would occupy 0xBE->0xC3
4964 case 51:// stub would occupy 0xFF->0x04
4965 betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL))); //pad with dummy stub
4966 break;
4967 }
4968 betterStubs.push_back(*it);
4969 }
4970 // replace
4971 fAllSynthesizedStubs.clear();
4972 fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
4973 }
4974
4975 template <typename A>
4976 void Writer<A>::synthesizeStubs()
4977 {
4978 switch ( fOptions.outputKind() ) {
4979 case Options::kObjectFile:
4980 // these output kinds never have stubs
4981 return;
4982 case Options::kStaticExecutable:
4983 case Options::kDyld:
4984 case Options::kDynamicLibrary:
4985 case Options::kDynamicBundle:
4986 case Options::kDynamicExecutable:
4987 // try to synthesize stubs for these
4988 break;
4989 }
4990
4991 // walk every atom and reference
4992 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
4993 ObjectFile::Atom* atom = *it;
4994 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
4995 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
4996 ObjectFile::Reference* ref = *rit;
4997 switch ( ref->getTargetBinding()) {
4998 case ObjectFile::Reference::kUnboundByName:
4999 case ObjectFile::Reference::kDontBind:
5000 break;
5001 case ObjectFile::Reference::kBoundByName:
5002 case ObjectFile::Reference::kBoundDirectly:
5003 ObjectFile::Atom& target = ref->getTarget();
5004 // build map of which symbols need weak importing
5005 if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
5006 || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
5007 bool weakImport = this->weakImportReferenceKind(ref->getKind());
5008 std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
5009 if ( pos == fWeakImportMap.end() ) {
5010 // target not in fWeakImportMap, so add
5011 fWeakImportMap[&target] = weakImport;
5012 }
5013 else {
5014 // target in fWeakImportMap, check for weakness mismatch
5015 if ( pos->second != weakImport ) {
5016 // found mismatch
5017 switch ( fOptions.weakReferenceMismatchTreatment() ) {
5018 case Options::kWeakReferenceMismatchError:
5019 throwf("mismatching weak references for symbol: %s", target.getName());
5020 case Options::kWeakReferenceMismatchWeak:
5021 pos->second = true;
5022 break;
5023 case Options::kWeakReferenceMismatchNonWeak:
5024 pos->second = false;
5025 break;
5026 }
5027 }
5028 }
5029 }
5030 // create stubs as needed
5031 if ( this->stubableReference(ref)
5032 && (ref->getTargetOffset() == 0)
5033 && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
5034 ObjectFile::Atom* stub = NULL;
5035 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
5036 if ( pos == fStubsMap.end() ) {
5037 stub = new StubAtom<A>(*this, target);
5038 fStubsMap[&target] = stub;
5039 }
5040 else {
5041 stub = pos->second;
5042 }
5043 // alter reference to use stub instead
5044 ref->setTarget(*stub, 0);
5045 }
5046 // create GOT slots (non-lazy pointers) as needed
5047 else if ( this->GOTReferenceKind(ref->getKind()) ) {
5048 //
5049 bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
5050 bool useGOT;
5051 if ( fBiggerThanTwoGigs ) {
5052 // in big images use GOT for all zero fill atoms
5053 // this is just a heuristic and may need to be re-examined
5054 useGOT = mustUseGOT || ref->getTarget().isZeroFill();
5055 }
5056 else {
5057 // < 2GB image so remove all GOT entries that we can
5058 useGOT = mustUseGOT;
5059 }
5060 // if this GOT usage cannot be optimized away then make a GOT enry
5061 if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
5062 useGOT = true;
5063 if ( useGOT ) {
5064 ObjectFile::Atom* nlp = NULL;
5065 std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
5066 if ( pos == fGOTMap.end() ) {
5067 nlp = new NonLazyPointerAtom<A>(*this, target);
5068 fGOTMap[&target] = nlp;
5069 }
5070 else {
5071 nlp = pos->second;
5072 }
5073 // alter reference to use non lazy pointer instead
5074 ref->setTarget(*nlp, ref->getTargetOffset());
5075 }
5076 }
5077 }
5078 }
5079 }
5080
5081 // sort stubs
5082 std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
5083
5084 // add dummy stubs (x86 only)
5085 this->insertDummyStubs();
5086
5087 // sort lazy pointers
5088 std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
5089
5090 // add stubs to fAllAtoms
5091 if ( fAllSynthesizedStubs.size() != 0 ) {
5092 std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
5093 std::vector<ObjectFile::Atom*> mergedStubs;
5094 if ( fAllSynthesizedStubHelpers.size() != 0 ) {
5095 // when we have stubs and helpers, insert both into fAllAtoms
5096 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
5097 mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
5098 stubs = &mergedStubs;
5099 }
5100 ObjectFile::Section* curSection = NULL;
5101 ObjectFile::Atom* prevAtom = NULL;
5102 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5103 ObjectFile::Atom* atom = *it;
5104 ObjectFile::Section* nextSection = atom->getSection();
5105 if ( nextSection != curSection ) {
5106 // HACK HACK for i386 where stubs are not in _TEXT segment
5107 if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
5108 if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
5109 || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
5110 // insert stubs at end of __IMPORT segment, or before __LINKEDIT
5111 fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
5112 break;
5113 }
5114 }
5115 else {
5116 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
5117 // found end of __text section, insert stubs here
5118 fAllAtoms->insert(it, stubs->begin(), stubs->end());
5119 break;
5120 }
5121 }
5122 curSection = nextSection;
5123 }
5124 prevAtom = atom;
5125 }
5126 }
5127
5128
5129 // add lazy pointers to fAllAtoms
5130 if ( fAllSynthesizedLazyPointers.size() != 0 ) {
5131 ObjectFile::Section* curSection = NULL;
5132 ObjectFile::Atom* prevAtom = NULL;
5133 bool inserted = false;
5134 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5135 ObjectFile::Atom* atom = *it;
5136 ObjectFile::Section* nextSection = atom->getSection();
5137 if ( nextSection != curSection ) {
5138 if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
5139 // found end of __dyld section, insert lazy pointers here
5140 fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
5141 inserted = true;
5142 break;
5143 }
5144 curSection = nextSection;
5145 }
5146 prevAtom = atom;
5147 }
5148 if ( !inserted ) {
5149 throw "can't insert lazy pointers, __dyld section not found";
5150 }
5151 }
5152
5153 // add non-lazy pointers to fAllAtoms
5154 if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
5155 ObjectFile::Section* curSection = NULL;
5156 ObjectFile::Atom* prevAtom = NULL;
5157 bool inserted = false;
5158 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5159 ObjectFile::Atom* atom = *it;
5160 ObjectFile::Section* nextSection = atom->getSection();
5161 if ( nextSection != curSection ) {
5162 if ( (prevAtom != NULL)
5163 && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0)
5164 || ((strcmp(prevAtom->getSectionName(), "__data") == 0) &&
5165 ((fOptions.outputKind() == Options::kDyld) || (fOptions.outputKind() == Options::kStaticExecutable))) ) ) {
5166 // found end of __dyld section, insert lazy pointers here
5167 fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
5168 inserted = true;
5169 break;
5170 }
5171 curSection = nextSection;
5172 }
5173 prevAtom = atom;
5174 }
5175 if ( !inserted ) {
5176 throw "can't insert non-lazy pointers, __dyld section not found";
5177 }
5178 }
5179
5180 // build LC_SEGMENT_SPLIT_INFO content now that all atoms exist
5181 if ( fSplitCodeToDataContentAtom != NULL ) {
5182 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5183 ObjectFile::Atom* atom = *it;
5184 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5185 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
5186 ObjectFile::Reference* ref = *rit;
5187 switch ( ref->getTargetBinding()) {
5188 case ObjectFile::Reference::kUnboundByName:
5189 case ObjectFile::Reference::kDontBind:
5190 break;
5191 case ObjectFile::Reference::kBoundByName:
5192 case ObjectFile::Reference::kBoundDirectly:
5193 if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
5194 this->addCrossSegmentRef(atom, ref);
5195 }
5196 break;
5197 }
5198 }
5199 }
5200 }
5201
5202 }
5203
5204
5205 template <typename A>
5206 void Writer<A>::partitionIntoSections()
5207 {
5208 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
5209
5210 // for every atom, set its sectionInfo object and section offset
5211 // build up fSegmentInfos along the way
5212 ObjectFile::Section* curSection = NULL;
5213 SectionInfo* currentSectionInfo = NULL;
5214 SegmentInfo* currentSegmentInfo = NULL;
5215 SectionInfo* cstringSectionInfo = NULL;
5216 unsigned int sectionIndex = 1;
5217 fSegmentInfos.reserve(8);
5218 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
5219 ObjectFile::Atom* atom = (*fAllAtoms)[i];
5220 if ( (atom->getSection() != curSection) || ((curSection==NULL) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
5221 if ( oneSegmentCommand ) {
5222 if ( currentSegmentInfo == NULL ) {
5223 currentSegmentInfo = new SegmentInfo();
5224 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5225 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5226 this->fSegmentInfos.push_back(currentSegmentInfo);
5227 }
5228 currentSectionInfo = new SectionInfo();
5229 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
5230 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
5231 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
5232 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
5233 currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
5234 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
5235 currentSectionInfo->setIndex(sectionIndex++);
5236 currentSegmentInfo->fSections.push_back(currentSectionInfo);
5237 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) )
5238 cstringSectionInfo = currentSectionInfo;
5239 }
5240 else {
5241 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
5242 currentSegmentInfo = new SegmentInfo();
5243 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
5244 uint32_t initprot = 0;
5245 if ( atom->getSegment().isContentReadable() )
5246 initprot |= VM_PROT_READ;
5247 if ( atom->getSegment().isContentWritable() )
5248 initprot |= VM_PROT_WRITE;
5249 if ( atom->getSegment().isContentExecutable() )
5250 initprot |= VM_PROT_EXECUTE;
5251 if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
5252 initprot &= ~VM_PROT_WRITE; // hack until i386 __pointers section is synthesized by linker
5253 currentSegmentInfo->fInitProtection = initprot;
5254 if ( initprot == 0 )
5255 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
5256 else
5257 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
5258 std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
5259 for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
5260 if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
5261 currentSegmentInfo->fInitProtection = it->init;
5262 currentSegmentInfo->fMaxProtection = it->max;
5263 }
5264 }
5265 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
5266 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
5267 if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
5268 currentSegmentInfo->fIndependentAddress = true;
5269 this->fSegmentInfos.push_back(currentSegmentInfo);
5270 }
5271 currentSectionInfo = new SectionInfo();
5272 currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
5273 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
5274 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
5275 currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
5276 // check for -sectalign override
5277 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
5278 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
5279 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
5280 currentSectionInfo->fAlignment = it->alignment;
5281 }
5282 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
5283 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
5284 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
5285 currentSectionInfo->setIndex(sectionIndex++);
5286 currentSegmentInfo->fSections.push_back(currentSectionInfo);
5287 }
5288 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
5289 fLoadCommandsSection = currentSectionInfo;
5290 fLoadCommandsSegment = currentSegmentInfo;
5291 }
5292 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
5293 currentSectionInfo->fAllLazyPointers = true;
5294 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
5295 currentSectionInfo->fAllLazyPointers = true;
5296 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
5297 currentSectionInfo->fAllNonLazyPointers = true;
5298 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
5299 currentSectionInfo->fAllNonLazyPointers = true;
5300 if ( (fOptions.outputKind() == Options::kDyld) && (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
5301 currentSectionInfo->fAllNonLazyPointers = true;
5302 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
5303 currentSectionInfo->fAllStubs = true;
5304 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
5305 currentSectionInfo->fAllStubs = true;
5306 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
5307 currentSectionInfo->fAllStubs = true;
5308 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
5309 currentSectionInfo->fAllStubs = true;
5310 if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
5311 currentSectionInfo->fAllSelfModifyingStubs = true;
5312 currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
5313 }
5314 curSection = atom->getSection();
5315 if ( currentSectionInfo->fAllNonLazyPointers || currentSectionInfo->fAllLazyPointers
5316 || currentSectionInfo->fAllStubs || currentSectionInfo->fAllStubs ) {
5317 fSymbolTableCommands->needDynamicTable();
5318 }
5319 }
5320 // any non-zero fill atoms make whole section marked not-zero-fill
5321 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
5322 currentSectionInfo->fAllZeroFill = false;
5323 // change section object to be Writer's SectionInfo object
5324 atom->setSection(currentSectionInfo);
5325 // section alignment is that of a contained atom with the greatest alignment
5326 uint8_t atomAlign = atom->getAlignment().powerOf2;
5327 if ( currentSectionInfo->fAlignment < atomAlign )
5328 currentSectionInfo->fAlignment = atomAlign;
5329 // calculate section offset for this atom
5330 uint64_t offset = currentSectionInfo->fSize;
5331 uint64_t alignment = 1 << atomAlign;
5332 uint64_t currentModulus = (offset % alignment);
5333 uint64_t requiredModulus = atom->getAlignment().modulus;
5334 if ( currentModulus != requiredModulus ) {
5335 if ( requiredModulus > currentModulus )
5336 offset += requiredModulus-currentModulus;
5337 else
5338 offset += requiredModulus+alignment-currentModulus;
5339 }
5340 atom->setSectionOffset(offset);
5341 uint64_t curAtomSize = atom->getSize();
5342 currentSectionInfo->fSize = offset + curAtomSize;
5343 // add atom to section vector
5344 currentSectionInfo->fAtoms.push_back(atom);
5345 // update largest size
5346 if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
5347 fLargestAtomSize = curAtomSize;
5348 }
5349 if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
5350 // when merging cstring sections in .o files, all strings need to use the max alignment
5351 uint64_t offset = 0;
5352 uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
5353 for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
5354 offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
5355 ObjectFile::Atom* atom = *it;
5356 atom->setSectionOffset(offset);
5357 offset += atom->getSize();
5358 }
5359 cstringSectionInfo->fSize = offset;
5360 }
5361 }
5362
5363
5364 struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
5365 class TargetAndOffsetComparor
5366 {
5367 public:
5368 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
5369 {
5370 if ( left.atom != right.atom )
5371 return ( left.atom < right.atom );
5372 return ( left.offset < right.offset );
5373 }
5374 };
5375
5376 template <>
5377 bool Writer<ppc>::addBranchIslands()
5378 {
5379 return this->addPPCBranchIslands();
5380 }
5381
5382 template <>
5383 bool Writer<ppc64>::addBranchIslands()
5384 {
5385 return this->addPPCBranchIslands();
5386 }
5387
5388 template <>
5389 bool Writer<x86>::addBranchIslands()
5390 {
5391 // x86 branches can reach entire 4G address space, so no need for branch islands
5392 return false;
5393 }
5394
5395 template <>
5396 bool Writer<x86_64>::addBranchIslands()
5397 {
5398 // x86 branches can reach entire 4G size of largest image
5399 return false;
5400 }
5401
5402
5403 template <>
5404 bool Writer<ppc>::isBranch24Reference(uint8_t kind)
5405 {
5406 switch (kind) {
5407 case ppc::kBranch24:
5408 case ppc::kBranch24WeakImport:
5409 return true;
5410 }
5411 return false;
5412 }
5413
5414 template <>
5415 bool Writer<ppc64>::isBranch24Reference(uint8_t kind)
5416 {
5417 switch (kind) {
5418 case ppc64::kBranch24:
5419 case ppc64::kBranch24WeakImport:
5420 return true;
5421 }
5422 return false;
5423 }
5424
5425 //
5426 // PowerPC can do PC relative branches as far as +/-16MB.
5427 // If a branch target is >16MB then we insert one or more
5428 // "branch islands" between the branch and its target that
5429 // allows island hoping to the target.
5430 //
5431 // Branch Island Algorithm
5432 //
5433 // If the __TEXT segment < 16MB, then no branch islands needed
5434 // Otherwise, every 15MB into the __TEXT segment is region is
5435 // added which can contain branch islands. Every out of range
5436 // bl instruction is checked. If it crosses a region, an island
5437 // is added to that region with the same target and the bl is
5438 // adjusted to target the island instead.
5439 //
5440 // In theory, if too many islands are added to one region, it
5441 // could grow the __TEXT enough that other previously in-range
5442 // bl branches could be pushed out of range. We reduce the
5443 // probability this could happen by placing the ranges every
5444 // 15MB which means the region would have to be 1MB (256K islands)
5445 // before any branches could be pushed out of range.
5446 //
5447 template <typename A>
5448 bool Writer<A>::addPPCBranchIslands()
5449 {
5450 bool log = false;
5451 bool result = false;
5452 // Can only possibly need branch islands if __TEXT segment > 16M
5453 if ( fLoadCommandsSegment->fSize > 16000000 ) {
5454 if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
5455 const uint32_t kBetweenRegions = 15*1024*1024; // place regions of islands every 15MB in __text section
5456 SectionInfo* textSection = NULL;
5457 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
5458 if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
5459 textSection = *it;
5460 if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
5461 break;
5462 }
5463 }
5464 const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
5465 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
5466 AtomToIsland regionsMap[kIslandRegionsCount];
5467 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
5468 unsigned int islandCount = 0;
5469
5470 // create islands for branch references that are out of range
5471 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
5472 ObjectFile::Atom* atom = *it;
5473 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
5474 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
5475 ObjectFile::Reference* ref = *rit;
5476 if ( this->isBranch24Reference(ref->getKind()) ) {
5477 ObjectFile::Atom& target = ref->getTarget();
5478 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
5479 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
5480 int64_t displacement = dstAddr - srcAddr;
5481 TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
5482 const int64_t kFifteenMegLimit = kBetweenRegions;
5483 if ( displacement > kFifteenMegLimit ) {
5484 // create forward branch chain
5485 ObjectFile::Atom* nextTarget = &target;
5486 uint64_t nextTargetOffset = ref->getTargetOffset();
5487 for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
5488 AtomToIsland* region = &regionsMap[i];
5489 int64_t islandRegionAddr = kBetweenRegions * (i+1);
5490 if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) {
5491 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
5492 if ( pos == region->end() ) {
5493 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, nextTargetOffset);
5494 island->setSection(textSection);
5495 (*region)[finalTargetAndOffset] = island;
5496 if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
5497 regionsIslands[i].push_back(island);
5498 ++islandCount;
5499 nextTarget = island;
5500 nextTargetOffset = 0;
5501 }
5502 else {
5503 nextTarget = pos->second;
5504 nextTargetOffset = 0;
5505 }
5506 }
5507 }
5508 if (log) fprintf(stderr, "using island %s for %s\n", nextTarget->getDisplayName(), atom->getDisplayName());
5509 ref->setTarget(*nextTarget, nextTargetOffset);
5510 }
5511 else if ( displacement < (-kFifteenMegLimit) ) {
5512 // create back branching chain
5513 ObjectFile::Atom* prevTarget = &target;
5514 uint64_t prevTargetOffset = ref->getTargetOffset();
5515 for (int i=0; i < kIslandRegionsCount ; ++i) {
5516 AtomToIsland* region = &regionsMap[i];
5517 int64_t islandRegionAddr = kBetweenRegions * (i+1);
5518 if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
5519 AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
5520 if ( pos == region->end() ) {
5521 BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, prevTargetOffset);
5522 island->setSection(textSection);
5523 (*region)[finalTargetAndOffset] = island;
5524 if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
5525 regionsIslands[i].push_back(island);
5526 ++islandCount;
5527 prevTarget = island;
5528 prevTargetOffset = 0;
5529 }
5530 else {
5531 prevTarget = pos->second;
5532 prevTargetOffset = 0;
5533 }
5534 }
5535 }
5536 if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
5537 ref->setTarget(*prevTarget, prevTargetOffset);
5538 }
5539 }
5540 }
5541 }
5542
5543 // insert islands into __text section and adjust section offsets
5544 if ( islandCount > 0 ) {
5545 if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
5546 std::vector<ObjectFile::Atom*> newAtomList;
5547 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
5548 uint64_t islandRegionAddr = kBetweenRegions;
5549 uint64_t textSectionAlignment = (1 << textSection->fAlignment);
5550 int regionIndex = 0;
5551 uint64_t atomSlide = 0;
5552 uint64_t sectionOffset = 0;
5553 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
5554 ObjectFile::Atom* atom = *it;
5555 newAtomList.push_back(atom);
5556 if ( atom->getAddress() > islandRegionAddr ) {
5557 uint64_t islandStartOffset = atom->getSectionOffset();
5558 sectionOffset = islandStartOffset + atomSlide;
5559 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
5560 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
5561 ObjectFile::Atom* islandAtom = *rit;
5562 newAtomList.push_back(islandAtom);
5563 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
5564 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5565 islandAtom->setSectionOffset(sectionOffset);
5566 sectionOffset += islandAtom->getSize();
5567 }
5568 ++regionIndex;
5569 islandRegionAddr += kBetweenRegions;
5570 uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
5571 atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
5572 }
5573 if ( atomSlide != 0 )
5574 atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
5575 }
5576 sectionOffset = textSection->fSize+atomSlide;
5577 // put any remaining islands at end of __text section
5578 if ( regionIndex < kIslandRegionsCount ) {
5579 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
5580 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
5581 ObjectFile::Atom* islandAtom = *rit;
5582 newAtomList.push_back(islandAtom);
5583 uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
5584 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5585 islandAtom->setSectionOffset(sectionOffset);
5586 sectionOffset += islandAtom->getSize();
5587 }
5588 }
5589
5590 textSection->fAtoms = newAtomList;
5591 textSection->fSize = sectionOffset;
5592 result = true;
5593 }
5594
5595 }
5596 return result;
5597 }
5598
5599
5600 template <typename A>
5601 void Writer<A>::adjustLoadCommandsAndPadding()
5602 {
5603 fSegmentCommands->computeSize();
5604
5605 // recompute load command section offsets
5606 uint64_t offset = 0;
5607 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
5608 const unsigned int atomCount = loadCommandAtoms.size();
5609 for (unsigned int i=0; i < atomCount; ++i) {
5610 ObjectFile::Atom* atom = loadCommandAtoms[i];
5611 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
5612 offset = ( (offset+alignment-1) & (-alignment) );
5613 atom->setSectionOffset(offset);
5614 uint32_t atomSize = atom->getSize();
5615 if ( atomSize > fLargestAtomSize )
5616 fLargestAtomSize = atomSize;
5617 offset += atomSize;
5618 fLoadCommandsSection->fSize = offset;
5619 }
5620
5621 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
5622 const int sectionCount = sectionInfos.size();
5623 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
5624 for(int j=0; j < sectionCount; ++j) {
5625 SectionInfo* curSection = sectionInfos[j];
5626 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
5627 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
5628 break;
5629 }
5630 uint64_t paddingSize = 0;
5631 if ( fOptions.outputKind() == Options::kDyld ) {
5632 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
5633 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
5634 }
5635 else if ( fOptions.outputKind() == Options::kObjectFile ) {
5636 // mach-o .o files need no padding between load commands and first section
5637 paddingSize = 0;
5638 }
5639 else {
5640 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
5641 uint64_t addr = 0;
5642 for(int j=sectionCount-1; j >=0; --j) {
5643 SectionInfo* curSection = sectionInfos[j];
5644 addr -= curSection->fSize;
5645 addr = addr & (0 - (1 << curSection->fAlignment));
5646 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
5647 addr -= totalSizeOfHeaderAndLoadCommands;
5648 paddingSize = addr % 4096;
5649 break;
5650 }
5651 }
5652
5653 // if command line requires more padding than this
5654 uint32_t minPad = fOptions.minimumHeaderPad();
5655 if ( fOptions.maxMminimumHeaderPad() ) {
5656 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
5657 uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
5658 if ( fOptions.outputKind() == Options::kDynamicLibrary )
5659 altMin += MAXPATHLEN;
5660 if ( altMin > minPad )
5661 minPad = altMin;
5662 }
5663 if ( paddingSize < minPad ) {
5664 int extraPages = (minPad - paddingSize + 4095)/4096;
5665 paddingSize += extraPages * 4096;
5666 }
5667 }
5668
5669 // adjust atom size and update section size
5670 fHeaderPadding->setSize(paddingSize);
5671 for(int j=0; j < sectionCount; ++j) {
5672 SectionInfo* curSection = sectionInfos[j];
5673 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
5674 curSection->fSize = paddingSize;
5675 }
5676 }
5677
5678 // assign file offsets and logical address to all segments
5679 template <typename A>
5680 void Writer<A>::assignFileOffsets()
5681 {
5682 bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
5683 bool haveFixedSegments = false;
5684 uint64_t fileOffset = 0;
5685 uint64_t nextContiguousAddress = fOptions.baseAddress();
5686 uint64_t nextReadOnlyAddress = fOptions.baseAddress();
5687 uint64_t nextWritableAddress = fOptions.baseWritableAddress();
5688
5689 // process segments with fixed addresses (-segaddr)
5690 for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
5691 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5692 SegmentInfo* curSegment = *segit;
5693 if ( strcmp(curSegment->fName, it->name) == 0 ) {
5694 curSegment->fBaseAddress = it->address;
5695 curSegment->fFixedAddress = true;
5696 break;
5697 }
5698 }
5699 }
5700
5701 // Run through the segments and each segment's sections to assign addresses
5702 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5703 SegmentInfo* curSegment = *segit;
5704
5705 if ( fOptions.splitSeg() ) {
5706 if ( curSegment->fInitProtection & VM_PROT_WRITE )
5707 nextContiguousAddress = nextWritableAddress;
5708 else
5709 nextContiguousAddress = nextReadOnlyAddress;
5710 }
5711
5712 fileOffset = (fileOffset+4095) & (-4096);
5713 curSegment->fFileOffset = fileOffset;
5714
5715 // Set the segment base address
5716 if ( curSegment->fFixedAddress )
5717 haveFixedSegments = true;
5718 else
5719 curSegment->fBaseAddress = nextContiguousAddress;
5720
5721 // We've set the segment address, now run through each section.
5722 uint64_t address = curSegment->fBaseAddress;
5723 SectionInfo* firstZeroFillSection = NULL;
5724 SectionInfo* prevSection = NULL;
5725
5726 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
5727
5728 for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
5729 SectionInfo* curSection = *it;
5730
5731 // adjust section address based on alignment
5732 uint64_t alignment = 1 << curSection->fAlignment;
5733 address = ( (address+alignment-1) & (-alignment) );
5734
5735 // adjust file offset to match address
5736 if ( prevSection != NULL ) {
5737 if ( finalLinkedImage || !prevSection->fVirtualSection )
5738 fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
5739 else
5740 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
5741 }
5742
5743 // update section info
5744 curSection->fFileOffset = fileOffset;
5745 curSection->setBaseAddress(address);
5746
5747 // keep track of trailing zero fill sections
5748 if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
5749 firstZeroFillSection = curSection;
5750 if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage )
5751 throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
5752
5753 // update running pointers
5754 if ( finalLinkedImage || !curSection->fVirtualSection )
5755 address += curSection->fSize;
5756 fileOffset += curSection->fSize;
5757
5758 // sanity check size of 32-bit binaries
5759 if ( address > maxAddress() )
5760 throwf("section %s exceeds 4GB limit", curSection->fSectionName);
5761
5762 // update segment info
5763 curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
5764 curSegment->fSize = curSegment->fFileSize;
5765 prevSection = curSection;
5766 }
5767
5768 if ( fOptions.outputKind() == Options::kObjectFile ) {
5769 // don't page align .o files
5770 }
5771 else {
5772 // optimize trailing zero-fill sections to not occupy disk space
5773 if ( firstZeroFillSection != NULL ) {
5774 curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
5775 fileOffset = firstZeroFillSection->fFileOffset;
5776 }
5777 // page align segment size
5778 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
5779 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
5780 if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
5781 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
5782 if ( curSegment->fInitProtection & VM_PROT_WRITE )
5783 nextWritableAddress = nextContiguousAddress;
5784 else
5785 nextReadOnlyAddress = nextContiguousAddress;
5786 }
5787 }
5788 }
5789
5790 // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
5791 if ( haveFixedSegments ) {
5792 int segCount = fSegmentInfos.size();
5793 for(int i=0; i < segCount; ++i) {
5794 SegmentInfo* segment1 = fSegmentInfos[i];
5795
5796 for(int j=0; j < segCount; ++j) {
5797 if ( i != j ) {
5798 SegmentInfo* segment2 = fSegmentInfos[j];
5799
5800 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
5801 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
5802 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5803 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5804 }
5805 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
5806 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
5807 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5808 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5809 }
5810 else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
5811 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
5812 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
5813 }
5814 }
5815 }
5816 }
5817 }
5818
5819 // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
5820 for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
5821 SegmentInfo* curSegment = *segit;
5822 if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
5823 if ( fFirstWritableSegment == NULL )
5824 fFirstWritableSegment = curSegment;
5825 if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
5826 fWritableSegmentPastFirst4GB = true;
5827 }
5828 }
5829
5830 }
5831
5832 template <typename A>
5833 void Writer<A>::adjustLinkEditSections()
5834 {
5835 // link edit content is always in last segment
5836 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
5837 unsigned int firstLinkEditSectionIndex = 0;
5838 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
5839 ++firstLinkEditSectionIndex;
5840
5841 const unsigned int linkEditSectionCount = lastSeg->fSections.size();
5842 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
5843 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
5844 if ( fPadSegmentInfo != NULL ) {
5845 // insert __4GBFILL segment into segments vector before LINKEDIT
5846 for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
5847 if ( *it == lastSeg ) {
5848 fSegmentInfos.insert(it, fPadSegmentInfo);
5849 break;
5850 }
5851 }
5852 // adjust __4GBFILL segment to span from end of last segment to zeroPageSize
5853 fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
5854 fPadSegmentInfo->fBaseAddress = address;
5855 // adjust LINKEDIT to start at zeroPageSize
5856 address = fOptions.zeroPageSize();
5857 lastSeg->fBaseAddress = fOptions.zeroPageSize();
5858 }
5859 for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
5860 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
5861 // adjust section address based on alignment
5862 uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
5863 uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
5864 address += pad;
5865 fileOffset += pad; // adjust file offset to match address
5866 lastSeg->fSections[i]->setBaseAddress(address);
5867 if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
5868 lastSeg->fSections[i]->setBaseAddress(0);
5869 lastSeg->fSections[i]->fFileOffset = fileOffset;
5870 uint64_t sectionOffset = 0;
5871 for (unsigned int j=0; j < atoms.size(); ++j) {
5872 ObjectFile::Atom* atom = atoms[j];
5873 uint64_t alignment = 1 << atom->getAlignment().powerOf2;
5874 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
5875 atom->setSectionOffset(sectionOffset);
5876 uint64_t size = atom->getSize();
5877 sectionOffset += size;
5878 if ( size > fLargestAtomSize )
5879 fLargestAtomSize = size;
5880 }
5881 //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
5882 lastSeg->fSections[i]->fSize = sectionOffset;
5883 fileOffset += sectionOffset;
5884 address += sectionOffset;
5885 }
5886 if ( fOptions.outputKind() == Options::kObjectFile ) {
5887 //lastSeg->fBaseAddress = 0;
5888 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
5889 //lastSeg->fFileOffset = 0;
5890 //lastSeg->fFileSize =
5891 }
5892 else {
5893 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
5894 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
5895 }
5896 }
5897
5898
5899 template <typename A>
5900 ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
5901 {
5902 switch ( fWriter.fOptions.outputKind() ) {
5903 case Options::kDynamicExecutable:
5904 case Options::kStaticExecutable:
5905 return ObjectFile::Atom::scopeGlobal;
5906 case Options::kDynamicLibrary:
5907 case Options::kDynamicBundle:
5908 case Options::kDyld:
5909 case Options::kObjectFile:
5910 return ObjectFile::Atom::scopeLinkageUnit;
5911 }
5912 throw "unknown header type";
5913 }
5914
5915 template <typename A>
5916 ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
5917 {
5918 switch ( fWriter.fOptions.outputKind() ) {
5919 case Options::kDynamicExecutable:
5920 return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
5921 case Options::kStaticExecutable:
5922 return ObjectFile::Atom::kSymbolTableInAsAbsolute;
5923 case Options::kDynamicLibrary:
5924 case Options::kDynamicBundle:
5925 case Options::kDyld:
5926 return ObjectFile::Atom::kSymbolTableIn;
5927 case Options::kObjectFile:
5928 return ObjectFile::Atom::kSymbolTableNotIn;
5929 }
5930 throw "unknown header type";
5931 }
5932
5933 template <typename A>
5934 const char* MachHeaderAtom<A>::getName() const
5935 {
5936 switch ( fWriter.fOptions.outputKind() ) {
5937 case Options::kDynamicExecutable:
5938 case Options::kStaticExecutable:
5939 return "__mh_execute_header";
5940 case Options::kDynamicLibrary:
5941 return "__mh_dylib_header";
5942 case Options::kDynamicBundle:
5943 return "__mh_bundle_header";
5944 case Options::kObjectFile:
5945 return NULL;
5946 case Options::kDyld:
5947 return "__mh_dylinker_header";
5948 }
5949 throw "unknown header type";
5950 }
5951
5952 template <typename A>
5953 const char* MachHeaderAtom<A>::getDisplayName() const
5954 {
5955 switch ( fWriter.fOptions.outputKind() ) {
5956 case Options::kDynamicExecutable:
5957 case Options::kStaticExecutable:
5958 case Options::kDynamicLibrary:
5959 case Options::kDynamicBundle:
5960 case Options::kDyld:
5961 return this->getName();
5962 case Options::kObjectFile:
5963 return "mach header";
5964 }
5965 throw "unknown header type";
5966 }
5967
5968 template <typename A>
5969 void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
5970 {
5971 // get file type
5972 uint32_t fileType = 0;
5973 switch ( fWriter.fOptions.outputKind() ) {
5974 case Options::kDynamicExecutable:
5975 case Options::kStaticExecutable:
5976 fileType = MH_EXECUTE;
5977 break;
5978 case Options::kDynamicLibrary:
5979 fileType = MH_DYLIB;
5980 break;
5981 case Options::kDynamicBundle:
5982 fileType = MH_BUNDLE;
5983 break;
5984 case Options::kObjectFile:
5985 fileType = MH_OBJECT;
5986 break;
5987 case Options::kDyld:
5988 fileType = MH_DYLINKER;
5989 break;
5990 }
5991
5992 // get flags
5993 uint32_t flags = 0;
5994 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
5995 if ( fWriter.fCanScatter )
5996 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
5997 }
5998 else {
5999 if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
6000 flags |= MH_NOUNDEFS;
6001 }
6002 else {
6003 flags = MH_DYLDLINK;
6004 if ( fWriter.fOptions.bindAtLoad() )
6005 flags |= MH_BINDATLOAD;
6006 switch ( fWriter.fOptions.nameSpace() ) {
6007 case Options::kTwoLevelNameSpace:
6008 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
6009 break;
6010 case Options::kFlatNameSpace:
6011 break;
6012 case Options::kForceFlatNameSpace:
6013 flags |= MH_FORCE_FLAT;
6014 break;
6015 }
6016 if ( fWriter.fHasWeakExports )
6017 flags |= MH_WEAK_DEFINES;
6018 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
6019 flags |= MH_BINDS_TO_WEAK;
6020 if ( fWriter.fOptions.prebind() )
6021 flags |= MH_PREBOUND;
6022 if ( fWriter.fOptions.splitSeg() )
6023 flags |= MH_SPLIT_SEGS;
6024 if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs )
6025 flags |= MH_NO_REEXPORTED_DYLIBS;
6026 if ( fWriter.fOptions.positionIndependentExecutable() )
6027 flags |= MH_PIE;
6028 }
6029 if ( fWriter.fOptions.hasExecutableStack() )
6030 flags |= MH_ALLOW_STACK_EXECUTION;
6031 if ( fWriter.fOptions.readerOptions().fRootSafe )
6032 flags |= MH_ROOT_SAFE;
6033 if ( fWriter.fOptions.readerOptions().fSetuidSafe )
6034 flags |= MH_SETUID_SAFE;
6035 }
6036
6037 // get commands info
6038 uint32_t commandsSize = 0;
6039 uint32_t commandsCount = 0;
6040
6041 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
6042 for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
6043 ObjectFile::Atom* atom = *it;
6044 commandsSize += atom->getSize();
6045 // segment and symbol table atoms can contain more than one load command
6046 if ( atom == fWriter.fSegmentCommands )
6047 commandsCount += fWriter.fSegmentCommands->commandCount();
6048 else if ( atom == fWriter.fSymbolTableCommands )
6049 commandsCount += fWriter.fSymbolTableCommands->commandCount();
6050 else if ( atom->getSize() != 0 )
6051 ++commandsCount;
6052 }
6053
6054 // fill out mach_header
6055 macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
6056 setHeaderInfo(*mh);
6057 mh->set_filetype(fileType);
6058 mh->set_ncmds(commandsCount);
6059 mh->set_sizeofcmds(commandsSize);
6060 mh->set_flags(flags);
6061 }
6062
6063 template <>
6064 void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
6065 {
6066 header.set_magic(MH_MAGIC);
6067 header.set_cputype(CPU_TYPE_POWERPC);
6068 switch ( fWriter.fCpuConstraint ) {
6069 case ObjectFile::Reader::kCpuAny:
6070 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
6071 break;
6072 case ObjectFile::Reader::kCpuG3:
6073 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_750);
6074 break;
6075 case ObjectFile::Reader::kCpuG4:
6076 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_7400);
6077 break;
6078 case ObjectFile::Reader::kCpuG5:
6079 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_970);
6080 break;
6081 }
6082 }
6083
6084 template <>
6085 void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
6086 {
6087 header.set_magic(MH_MAGIC_64);
6088 header.set_cputype(CPU_TYPE_POWERPC64);
6089 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6090 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
6091 else
6092 header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
6093 header.set_reserved(0);
6094 }
6095
6096 template <>
6097 void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
6098 {
6099 header.set_magic(MH_MAGIC);
6100 header.set_cputype(CPU_TYPE_I386);
6101 header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
6102 }
6103
6104 template <>
6105 void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
6106 {
6107 header.set_magic(MH_MAGIC_64);
6108 header.set_cputype(CPU_TYPE_X86_64);
6109 if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6110 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
6111 else
6112 header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
6113 header.set_reserved(0);
6114 }
6115
6116
6117 template <typename A>
6118 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
6119 : WriterAtom<A>(writer, Segment::fgStackSegment)
6120 {
6121 if ( stackGrowsDown() )
6122 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
6123 else
6124 Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
6125 }
6126
6127
6128 template <>
6129 bool CustomStackAtom<ppc>::stackGrowsDown()
6130 {
6131 return true;
6132 }
6133
6134 template <>
6135 bool CustomStackAtom<ppc64>::stackGrowsDown()
6136 {
6137 return true;
6138 }
6139
6140 template <>
6141 bool CustomStackAtom<x86>::stackGrowsDown()
6142 {
6143 return true;
6144 }
6145
6146 template <>
6147 bool CustomStackAtom<x86_64>::stackGrowsDown()
6148 {
6149 return true;
6150 }
6151
6152
6153 template <typename A>
6154 void SegmentLoadCommandsAtom<A>::computeSize()
6155 {
6156 uint64_t size = 0;
6157 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6158 const int segCount = segmentInfos.size();
6159 for(int i=0; i < segCount; ++i) {
6160 size += sizeof(macho_segment_command<P>);
6161 std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
6162 const int sectionCount = sectionInfos.size();
6163 for(int j=0; j < sectionCount; ++j) {
6164 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
6165 size += sizeof(macho_section<P>);
6166 }
6167 }
6168 fSize = size;
6169 fCommandCount = segCount;
6170 if ( fWriter.fPadSegmentInfo != NULL ) {
6171 ++fCommandCount;
6172 fSize += sizeof(macho_segment_command<P>);
6173 }
6174 }
6175
6176 template <>
6177 uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
6178 {
6179 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
6180 }
6181
6182 template <>
6183 uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
6184 {
6185 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
6186 }
6187
6188 template <>
6189 uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
6190 {
6191 return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o
6192 }
6193
6194 template <>
6195 uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
6196 {
6197 return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o
6198 }
6199
6200 template <typename A>
6201 void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6202 {
6203 uint64_t size = this->getSize();
6204 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
6205 bzero(buffer, size);
6206 uint8_t* p = buffer;
6207 typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6208 const int segCount = segmentInfos.size();
6209 for(int i=0; i < segCount; ++i) {
6210 SegmentInfo* segInfo = segmentInfos[i];
6211 const int sectionCount = segInfo->fSections.size();
6212 macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
6213 cmd->set_cmd(macho_segment_command<P>::CMD);
6214 cmd->set_segname(segInfo->fName);
6215 cmd->set_vmaddr(segInfo->fBaseAddress);
6216 cmd->set_vmsize(segInfo->fSize);
6217 cmd->set_fileoff(segInfo->fFileOffset);
6218 cmd->set_filesize(segInfo->fFileSize);
6219 cmd->set_maxprot(segInfo->fMaxProtection);
6220 cmd->set_initprot(segInfo->fInitProtection);
6221 // add sections array
6222 macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
6223 unsigned int sectionsEmitted = 0;
6224 for (int j=0; j < sectionCount; ++j) {
6225 SectionInfo* sectInfo = segInfo->fSections[j];
6226 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
6227 macho_section<P>* sect = &sections[sectionsEmitted++];
6228 if ( oneSegment ) {
6229 // .o file segment does not cover load commands, so recalc at first real section
6230 if ( sectionsEmitted == 1 ) {
6231 cmd->set_vmaddr(sectInfo->getBaseAddress());
6232 cmd->set_fileoff(sectInfo->fFileOffset);
6233 }
6234 cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
6235 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
6236 }
6237 sect->set_sectname(sectInfo->fSectionName);
6238 sect->set_segname(sectInfo->fSegmentName);
6239 sect->set_addr(sectInfo->getBaseAddress());
6240 sect->set_size(sectInfo->fSize);
6241 sect->set_offset(sectInfo->fFileOffset);
6242 sect->set_align(sectInfo->fAlignment);
6243 if ( sectInfo->fRelocCount != 0 ) {
6244 sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
6245 sect->set_nreloc(sectInfo->fRelocCount);
6246 }
6247 if ( sectInfo->fAllZeroFill ) {
6248 sect->set_flags(S_ZEROFILL);
6249 sect->set_offset(0);
6250 }
6251 else if ( sectInfo->fAllLazyPointers ) {
6252 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
6253 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6254 }
6255 else if ( sectInfo->fAllNonLazyPointers ) {
6256 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
6257 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6258 }
6259 else if ( sectInfo->fAllStubs ) {
6260 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
6261 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6262 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
6263 }
6264 else if ( sectInfo->fAllSelfModifyingStubs ) {
6265 sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
6266 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
6267 sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
6268 }
6269 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6270 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
6271 }
6272 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6273 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
6274 }
6275 else if ( (strcmp(sectInfo->fSectionName, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6276 sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
6277 }
6278 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6279 sect->set_flags(S_COALESCED);
6280 }
6281 else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6282 sect->set_flags(S_COALESCED);
6283 }
6284 else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6285 sect->set_flags(S_INTERPOSING);
6286 }
6287 else if ( (strcmp(sectInfo->fSectionName, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6288 sect->set_flags(S_CSTRING_LITERALS);
6289 }
6290 else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6291 sect->set_flags(S_4BYTE_LITERALS);
6292 }
6293 else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6294 sect->set_flags(S_8BYTE_LITERALS);
6295 }
6296 else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6297 sect->set_flags(S_16BYTE_LITERALS);
6298 }
6299 else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
6300 sect->set_flags(S_LITERAL_POINTERS);
6301 }
6302 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6303 sect->set_flags(S_DTRACE_DOF);
6304 }
6305 else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
6306 sect->set_flags(S_DTRACE_DOF);
6307 }
6308 else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
6309 sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
6310 }
6311 }
6312 }
6313 p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
6314 cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
6315 cmd->set_nsects(sectionsEmitted);
6316 }
6317 }
6318
6319
6320 template <typename A>
6321 SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
6322 : LoadCommandAtom<A>(writer, Segment::fgTextSegment)
6323 {
6324 bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
6325 bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
6326 switch ( fWriter.fOptions.outputKind() ) {
6327 case Options::kDynamicExecutable:
6328 case Options::kDynamicLibrary:
6329 case Options::kDynamicBundle:
6330 case Options::kDyld:
6331 fNeedsDynamicSymbolTable = true;
6332 break;
6333 case Options::kObjectFile:
6334 case Options::kStaticExecutable:
6335 fNeedsDynamicSymbolTable = false;
6336 break;
6337 }
6338 writer.fSymbolTableCommands = this;
6339 }
6340
6341
6342
6343 template <typename A>
6344 void SymbolTableLoadCommandsAtom<A>::needDynamicTable()
6345 {
6346 fNeedsDynamicSymbolTable = true;
6347 }
6348
6349
6350 template <typename A>
6351 uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
6352 {
6353 if ( fNeedsDynamicSymbolTable )
6354 return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
6355 else
6356 return this->alignedSize(sizeof(macho_symtab_command<P>));
6357 }
6358
6359 template <typename A>
6360 void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6361 {
6362 // build LC_DYSYMTAB command
6363 macho_symtab_command<P>* symbolTableCmd = (macho_symtab_command<P>*)buffer;
6364 bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
6365 symbolTableCmd->set_cmd(LC_SYMTAB);
6366 symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
6367 symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
6368 symbolTableCmd->set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
6369 symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
6370 symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
6371
6372 // build LC_DYSYMTAB command
6373 if ( fNeedsDynamicSymbolTable ) {
6374 macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
6375 bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
6376 dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
6377 dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
6378 dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
6379 dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
6380 dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
6381 dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
6382 dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
6383 dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
6384 if ( fWriter.fModuleInfoAtom != NULL ) {
6385 dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
6386 dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
6387 dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
6388 dynamicSymbolTableCmd->set_nmodtab(1);
6389 dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
6390 dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
6391 }
6392 dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
6393 dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
6394 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
6395 dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
6396 dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
6397 dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
6398 dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
6399 }
6400 }
6401 }
6402
6403
6404 template <typename A>
6405 unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
6406 {
6407 return fNeedsDynamicSymbolTable ? 2 : 1;
6408 }
6409
6410 template <typename A>
6411 uint64_t DyldLoadCommandsAtom<A>::getSize() const
6412 {
6413 return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
6414 }
6415
6416 template <typename A>
6417 void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6418 {
6419 uint64_t size = this->getSize();
6420 bzero(buffer, size);
6421 macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
6422 if ( fWriter.fOptions.outputKind() == Options::kDyld )
6423 cmd->set_cmd(LC_ID_DYLINKER);
6424 else
6425 cmd->set_cmd(LC_LOAD_DYLINKER);
6426 cmd->set_cmdsize(this->getSize());
6427 cmd->set_name_offset();
6428 strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
6429 }
6430
6431 template <typename A>
6432 uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
6433 {
6434 return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
6435 }
6436
6437 template <typename A>
6438 void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6439 {
6440 uint64_t size = this->getSize();
6441
6442 bzero(buffer, size);
6443 macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
6444 cmd->set_cmd(LC_SUB_CLIENT);
6445 cmd->set_cmdsize(size);
6446 cmd->set_client_offset();
6447 strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
6448
6449 }
6450
6451 template <typename A>
6452 uint64_t DylibLoadCommandsAtom<A>::getSize() const
6453 {
6454 if ( fOptimizedAway ) {
6455 return 0;
6456 }
6457 else {
6458 const char* path = fInfo.reader->getInstallPath();
6459 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
6460 }
6461 }
6462
6463 template <typename A>
6464 void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6465 {
6466 if ( fOptimizedAway )
6467 return;
6468 uint64_t size = this->getSize();
6469 bzero(buffer, size);
6470 const char* path = fInfo.reader->getInstallPath();
6471 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
6472 if ( fInfo.options.fWeakImport )
6473 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
6474 else if ( fInfo.options.fReExport && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
6475 cmd->set_cmd(LC_REEXPORT_DYLIB);
6476 else
6477 cmd->set_cmd(LC_LOAD_DYLIB);
6478 cmd->set_cmdsize(this->getSize());
6479 cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
6480 cmd->set_current_version(fInfo.reader->getCurrentVersion());
6481 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
6482 cmd->set_name_offset();
6483 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
6484 }
6485
6486
6487
6488 template <typename A>
6489 uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
6490 {
6491 return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
6492 }
6493
6494 template <typename A>
6495 void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6496 {
6497 uint64_t size = this->getSize();
6498 bzero(buffer, size);
6499 macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
6500 cmd->set_cmd(LC_ID_DYLIB);
6501 cmd->set_cmdsize(this->getSize());
6502 cmd->set_name_offset();
6503 cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses
6504 cmd->set_current_version(fWriter.fOptions.currentVersion());
6505 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
6506 strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
6507 }
6508
6509
6510 template <typename A>
6511 void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6512 {
6513 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6514 bzero(buffer, sizeof(macho_routines_command<P>));
6515 macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
6516 cmd->set_cmd(macho_routines_command<P>::CMD);
6517 cmd->set_cmdsize(this->getSize());
6518 cmd->set_init_address(initAddr);
6519 }
6520
6521
6522 template <typename A>
6523 uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
6524 {
6525 return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
6526 }
6527
6528 template <typename A>
6529 void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6530 {
6531 uint64_t size = this->getSize();
6532 bzero(buffer, size);
6533 macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
6534 cmd->set_cmd(LC_SUB_UMBRELLA);
6535 cmd->set_cmdsize(this->getSize());
6536 cmd->set_sub_umbrella_offset();
6537 strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
6538 }
6539
6540 template <typename A>
6541 void UUIDLoadCommandAtom<A>::generate()
6542 {
6543 switch ( fWriter.fOptions.getUUIDMode() ) {
6544 case Options::kUUIDNone:
6545 fEmit = false;
6546 break;
6547 case Options::kUUIDRandom:
6548 ::uuid_generate_random(fUUID);
6549 fEmit = true;
6550 break;
6551 case Options::kUUIDContent:
6552 bzero(fUUID, 16);
6553 fEmit = true;
6554 break;
6555 }
6556 }
6557
6558 template <typename A>
6559 void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16])
6560 {
6561 memcpy(fUUID, uuid, 16);
6562 }
6563
6564 template <typename A>
6565 void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
6566 {
6567 if (fEmit) {
6568 uint64_t size = this->getSize();
6569 bzero(buffer, size);
6570 macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
6571 cmd->set_cmd(LC_UUID);
6572 cmd->set_cmdsize(this->getSize());
6573 cmd->set_uuid((uint8_t*)fUUID);
6574 }
6575 }
6576
6577
6578 template <typename A>
6579 uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
6580 {
6581 return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
6582 }
6583
6584 template <typename A>
6585 void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6586 {
6587 uint64_t size = this->getSize();
6588 bzero(buffer, size);
6589 macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
6590 cmd->set_cmd(LC_SUB_LIBRARY);
6591 cmd->set_cmdsize(this->getSize());
6592 cmd->set_sub_library_offset();
6593 strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
6594 buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
6595 }
6596
6597 template <typename A>
6598 uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
6599 {
6600 return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
6601 }
6602
6603 template <typename A>
6604 void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6605 {
6606 uint64_t size = this->getSize();
6607 bzero(buffer, size);
6608 macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
6609 cmd->set_cmd(LC_SUB_FRAMEWORK);
6610 cmd->set_cmdsize(this->getSize());
6611 cmd->set_umbrella_offset();
6612 strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
6613 }
6614
6615 template <>
6616 uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
6617 {
6618 return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4
6619 }
6620
6621 template <>
6622 uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
6623 {
6624 return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4
6625 }
6626
6627 template <>
6628 uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
6629 {
6630 return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4
6631 }
6632
6633 template <>
6634 uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
6635 {
6636 return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4);
6637 }
6638
6639 template <>
6640 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
6641 {
6642 uint64_t size = this->getSize();
6643 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6644 bzero(buffer, size);
6645 macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
6646 cmd->set_cmd(LC_UNIXTHREAD);
6647 cmd->set_cmdsize(size);
6648 cmd->set_flavor(1); // PPC_THREAD_STATE
6649 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
6650 cmd->set_thread_register(0, start);
6651 if ( fWriter.fOptions.hasCustomStack() )
6652 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
6653 }
6654
6655
6656 template <>
6657 void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
6658 {
6659 uint64_t size = this->getSize();
6660 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6661 bzero(buffer, size);
6662 macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
6663 cmd->set_cmd(LC_UNIXTHREAD);
6664 cmd->set_cmdsize(size);
6665 cmd->set_flavor(5); // PPC_THREAD_STATE64
6666 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
6667 cmd->set_thread_register(0, start);
6668 if ( fWriter.fOptions.hasCustomStack() )
6669 cmd->set_thread_register(3, fWriter.fOptions.customStackAddr()); // r1
6670 }
6671
6672 template <>
6673 void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
6674 {
6675 uint64_t size = this->getSize();
6676 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6677 bzero(buffer, size);
6678 macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
6679 cmd->set_cmd(LC_UNIXTHREAD);
6680 cmd->set_cmdsize(size);
6681 cmd->set_flavor(1); // i386_THREAD_STATE
6682 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
6683 cmd->set_thread_register(10, start);
6684 if ( fWriter.fOptions.hasCustomStack() )
6685 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // esp
6686 }
6687
6688
6689 template <>
6690 void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
6691 {
6692 uint64_t size = this->getSize();
6693 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
6694 bzero(buffer, size);
6695 macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
6696 cmd->set_cmd(LC_UNIXTHREAD);
6697 cmd->set_cmdsize(size);
6698 cmd->set_flavor(x86_THREAD_STATE64);
6699 cmd->set_count(x86_THREAD_STATE64_COUNT);
6700 cmd->set_thread_register(16, start); // rip
6701 if ( fWriter.fOptions.hasCustomStack() )
6702 cmd->set_thread_register(7, fWriter.fOptions.customStackAddr()); // uesp
6703 }
6704
6705
6706 template <typename A>
6707 uint64_t RPathLoadCommandsAtom<A>::getSize() const
6708 {
6709 return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
6710 }
6711
6712 template <typename A>
6713 void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
6714 {
6715 uint64_t size = this->getSize();
6716 bzero(buffer, size);
6717 macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
6718 cmd->set_cmd(LC_RPATH);
6719 cmd->set_cmdsize(this->getSize());
6720 cmd->set_path_offset();
6721 strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
6722 }
6723
6724
6725 template <typename A>
6726 void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
6727 {
6728 bzero(buffer, fSize);
6729 }
6730
6731 template <typename A>
6732 void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize)
6733 {
6734 fSize = newSize;
6735 // this resizing by-passes the way fLargestAtomSize is set, so re-check here
6736 if ( fWriter.fLargestAtomSize < newSize )
6737 fWriter.fLargestAtomSize = newSize;
6738 }
6739
6740 template <typename A>
6741 uint64_t LinkEditAtom<A>::getFileOffset() const
6742 {
6743 return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
6744 }
6745
6746
6747 template <typename A>
6748 uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
6749 {
6750 return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
6751 }
6752
6753 template <typename A>
6754 void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6755 {
6756 memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
6757 }
6758
6759
6760 template <typename A>
6761 uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
6762 {
6763 return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
6764 }
6765
6766 template <typename A>
6767 void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6768 {
6769 memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
6770 }
6771
6772
6773
6774 template <typename A>
6775 uint64_t SymbolTableLinkEditAtom<A>::getSize() const
6776 {
6777 return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
6778 }
6779
6780 template <typename A>
6781 void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6782 {
6783 memcpy(buffer, fWriter.fSymbolTable, this->getSize());
6784 }
6785
6786 template <typename A>
6787 uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
6788 {
6789 return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
6790 }
6791
6792 template <typename A>
6793 void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6794 {
6795 std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
6796 memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
6797 }
6798
6799
6800
6801 template <typename A>
6802 uint64_t IndirectTableLinkEditAtom<A>::getSize() const
6803 {
6804 return fTable.size() * sizeof(uint32_t);
6805 }
6806
6807 template <typename A>
6808 void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6809 {
6810 uint64_t size = this->getSize();
6811 bzero(buffer, size);
6812 const uint32_t indirectTableSize = fTable.size();
6813 uint32_t* indirectTable = (uint32_t*)buffer;
6814 for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
6815 if ( it->indirectIndex < indirectTableSize ) {
6816 A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
6817 }
6818 else {
6819 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
6820 }
6821 }
6822 }
6823
6824
6825
6826 template <typename A>
6827 uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
6828 {
6829 return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)
6830 + sizeof(macho_dylib_module<P>)
6831 + this->getReferencesCount()*sizeof(uint32_t);
6832 }
6833
6834 template <typename A>
6835 uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
6836 {
6837 return this->getFileOffset();
6838 }
6839
6840 template <typename A>
6841 uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
6842 {
6843 return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
6844 }
6845
6846 template <typename A>
6847 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
6848 {
6849 return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
6850 }
6851
6852 template <typename A>
6853 uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
6854 {
6855 return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
6856 }
6857
6858 template <typename A>
6859 void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6860 {
6861 uint64_t size = this->getSize();
6862 bzero(buffer, size);
6863 // create toc. The symbols are already sorted, they are all in the smae module
6864 macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
6865 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
6866 p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
6867 p->set_module_index(0);
6868 }
6869 // create module table (one entry)
6870 uint16_t numInits = 0;
6871 uint16_t numTerms = 0;
6872 std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
6873 for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
6874 if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
6875 std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
6876 for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
6877 if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 )
6878 numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
6879 else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 )
6880 numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
6881 }
6882 }
6883 }
6884 macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
6885 module->set_module_name(fModuleNameOffset);
6886 module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
6887 module->set_nextdefsym(fWriter.fSymbolTableExportCount);
6888 module->set_irefsym(0);
6889 module->set_nrefsym(this->getReferencesCount());
6890 module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
6891 module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
6892 module->set_iextrel(0);
6893 module->set_nextrel(fWriter.fExternalRelocs.size());
6894 module->set_iinit_iterm(0,0);
6895 module->set_ninit_nterm(numInits,numTerms);
6896 module->set_objc_module_info_addr(0); // Not used by ld_classic, and not used by objc runtime for many years
6897 module->set_objc_module_info_size(0); // Not used by ld_classic, and not used by objc runtime for many years
6898 // create reference table
6899 macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
6900 for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
6901 ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
6902 ref->set_flags(REFERENCE_FLAG_DEFINED);
6903 }
6904 for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
6905 ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
6906 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
6907 if ( pos != fWriter.fStubsMap.end() )
6908 ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
6909 else
6910 ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
6911 }
6912 }
6913
6914
6915
6916 template <typename A>
6917 StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
6918 : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
6919 {
6920 fCurrentBuffer = new char[kBufferSize];
6921 // burn first byte of string pool (so zero is never a valid string offset)
6922 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
6923 // make offset 1 always point to an empty string
6924 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
6925 }
6926
6927 template <typename A>
6928 uint64_t StringsLinkEditAtom<A>::getSize() const
6929 {
6930 // align size
6931 return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
6932 }
6933
6934 template <typename A>
6935 void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
6936 {
6937 uint64_t offset = 0;
6938 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
6939 memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
6940 offset += kBufferSize;
6941 }
6942 memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
6943 // zero fill end to align
6944 offset += fCurrentBufferUsed;
6945 while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
6946 buffer[offset++] = 0;
6947 }
6948
6949 template <typename A>
6950 int32_t StringsLinkEditAtom<A>::add(const char* name)
6951 {
6952 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
6953 int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
6954 if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
6955 fCurrentBufferUsed += lenNeeded;
6956 }
6957 else {
6958 int copied = kBufferSize-fCurrentBufferUsed-1;
6959 // change trailing '\0' that strlcpy added to real char
6960 fCurrentBuffer[kBufferSize-1] = name[copied];
6961 // alloc next buffer
6962 fFullBuffers.push_back(fCurrentBuffer);
6963 fCurrentBuffer = new char[kBufferSize];
6964 fCurrentBufferUsed = 0;
6965 // append rest of string
6966 this->add(&name[copied+1]);
6967 }
6968 return offset;
6969 }
6970
6971
6972 template <typename A>
6973 int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
6974 {
6975 StringToOffset::iterator pos = fUniqueStrings.find(name);
6976 if ( pos != fUniqueStrings.end() ) {
6977 return pos->second;
6978 }
6979 else {
6980 int32_t offset = this->add(name);
6981 fUniqueStrings[name] = offset;
6982 return offset;
6983 }
6984 }
6985
6986
6987 template <typename A>
6988 const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
6989 {
6990 int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
6991 int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
6992 // check for out of bounds
6993 if ( index > maxIndex )
6994 return "";
6995 // check for index in fCurrentBuffer
6996 if ( index > currentBufferStartIndex )
6997 return &fCurrentBuffer[index-currentBufferStartIndex];
6998 // otherwise index is in a full buffer
6999 uint32_t fullBufferIndex = index/kBufferSize;
7000 return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
7001 }
7002
7003
7004
7005 template <typename A>
7006 BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
7007 : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
7008 {
7009 char* buf = new char[strlen(name)+32];
7010 if ( targetOffset == 0 ) {
7011 if ( islandRegion == 0 )
7012 sprintf(buf, "%s$island", name);
7013 else
7014 sprintf(buf, "%s$island_%d", name, islandRegion);
7015 }
7016 else {
7017 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
7018 }
7019 fName = buf;
7020 }
7021
7022
7023 template <>
7024 void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
7025 {
7026 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
7027 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
7028 OSWriteBigInt32(buffer, 0, branchInstruction);
7029 }
7030
7031 template <>
7032 void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
7033 {
7034 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
7035 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
7036 OSWriteBigInt32(buffer, 0, branchInstruction);
7037 }
7038
7039 template <>
7040 uint64_t BranchIslandAtom<ppc>::getSize() const
7041 {
7042 return 4;
7043 }
7044
7045 template <>
7046 uint64_t BranchIslandAtom<ppc64>::getSize() const
7047 {
7048 return 4;
7049 }
7050
7051
7052
7053 template <typename A>
7054 uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
7055 {
7056 if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
7057 return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
7058 else
7059 return 0; // a zero size causes the load command to be suppressed
7060 }
7061
7062 template <typename A>
7063 void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
7064 {
7065 uint64_t size = this->getSize();
7066 bzero(buffer, size);
7067 macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
7068 cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
7069 cmd->set_cmdsize(size);
7070 cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
7071 cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
7072 }
7073
7074
7075 template <typename A>
7076 uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
7077 {
7078 return fEncodedData.size();
7079 }
7080
7081 template <typename A>
7082 void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
7083 {
7084 memcpy(buffer, &fEncodedData[0], fEncodedData.size());
7085 }
7086
7087
7088 template <typename A>
7089 void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
7090 {
7091 pint_t addr = fWriter.fOptions.baseAddress();
7092 for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
7093 pint_t nextAddr = it->atom->getAddress() + it->offset;
7094 //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
7095 uint64_t delta = nextAddr - addr;
7096 if ( delta == 0 )
7097 throw "double split seg info for same address";
7098 // uleb128 encode
7099 uint8_t byte;
7100 do {
7101 byte = delta & 0x7F;
7102 delta &= ~0x7F;
7103 if ( delta != 0 )
7104 byte |= 0x80;
7105 fEncodedData.push_back(byte);
7106 delta = delta >> 7;
7107 }
7108 while( byte >= 0x80 );
7109 addr = nextAddr;
7110 }
7111 }
7112
7113 template <typename A>
7114 void SegmentSplitInfoContentAtom<A>::encode()
7115 {
7116 if ( ! fCantEncode ) {
7117 fEncodedData.reserve(8192);
7118
7119 if ( fKind1Locations.size() != 0 ) {
7120 fEncodedData.push_back(1);
7121 //fprintf(stderr, "type 1:\n");
7122 this->uleb128EncodeAddresses(fKind1Locations);
7123 fEncodedData.push_back(0);
7124 }
7125
7126 if ( fKind2Locations.size() != 0 ) {
7127 fEncodedData.push_back(2);
7128 //fprintf(stderr, "type 2:\n");
7129 this->uleb128EncodeAddresses(fKind2Locations);
7130 fEncodedData.push_back(0);
7131 }
7132
7133 if ( fKind3Locations.size() != 0 ) {
7134 fEncodedData.push_back(3);
7135 //fprintf(stderr, "type 3:\n");
7136 this->uleb128EncodeAddresses(fKind3Locations);
7137 fEncodedData.push_back(0);
7138 }
7139
7140 if ( fKind4Locations.size() != 0 ) {
7141 fEncodedData.push_back(4);
7142 //fprintf(stderr, "type 4:\n");
7143 this->uleb128EncodeAddresses(fKind4Locations);
7144 fEncodedData.push_back(0);
7145 }
7146
7147 // always add zero byte to mark end
7148 fEncodedData.push_back(0);
7149
7150 // add zeros to end to align size
7151 while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
7152 fEncodedData.push_back(0);
7153 }
7154 }
7155
7156
7157 template <typename A>
7158 ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, bool objcReplacementClasses)
7159 : WriterAtom<A>(writer, getInfoSegment())
7160 {
7161 fContent[0] = 0;
7162 uint32_t value = 0;
7163 // struct objc_image_info {
7164 // uint32_t version; // initially 0
7165 // uint32_t flags;
7166 // };
7167 // #define OBJC_IMAGE_SUPPORTS_GC 2
7168 // #define OBJC_IMAGE_GC_ONLY 4
7169 //
7170 if ( objcReplacementClasses )
7171 value = 1;
7172 switch ( objcConstraint ) {
7173 case ObjectFile::Reader::kObjcNone:
7174 case ObjectFile::Reader::kObjcRetainRelease:
7175 break;
7176 case ObjectFile::Reader::kObjcRetainReleaseOrGC:
7177 value |= 2;
7178 break;
7179 case ObjectFile::Reader::kObjcGC:
7180 value |= 6;
7181 break;
7182 }
7183 A::P::E::set32(fContent[1], value);
7184 }
7185
7186 template <typename A>
7187 void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
7188 {
7189 memcpy(buffer, &fContent[0], 8);
7190 }
7191
7192
7193 // objc info section is in a different segment and section for 32 vs 64 bit runtimes
7194 template <> const char* ObjCInfoAtom<ppc>::getSectionName() const { return "__image_info"; }
7195 template <> const char* ObjCInfoAtom<x86>::getSectionName() const { return "__image_info"; }
7196 template <> const char* ObjCInfoAtom<ppc64>::getSectionName() const { return "__objc_imageinfo"; }
7197 template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
7198
7199 template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment() const { return Segment::fgObjCSegment; }
7200 template <> Segment& ObjCInfoAtom<x86>::getInfoSegment() const { return Segment::fgObjCSegment; }
7201 template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment() const { return Segment::fgDataSegment; }
7202 template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment() const { return Segment::fgDataSegment; }
7203
7204
7205
7206 }; // namespace executable
7207 }; // namespace mach_o
7208
7209
7210 #endif // __EXECUTABLE_MACH_O__