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