1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
27 namespace ExecutableFileMachO
{
29 class Writer
: public ExecutableFile::Writer
32 Writer(const char* path
, Options
& options
, std::vector
<ExecutableFile::DyLibUsed
>& dynamicLibraries
);
35 virtual const char* getPath();
36 virtual std::vector
<class ObjectFile::Atom
*>& getAtoms();
37 virtual std::vector
<class ObjectFile::Atom
*>* getJustInTimeAtomsFor(const char* name
);
38 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo();
40 virtual class ObjectFile::Atom
* getUndefinedProxyAtom(const char* name
);
41 virtual void write(std::vector
<class ObjectFile::Atom
*>& atoms
, class ObjectFile::Atom
* entryPointAtom
);
44 void assignFileOffsets();
45 void partitionIntoSections();
46 bool addBranchIslands();
47 void adjustLoadCommandsAndPadding();
48 void createDynamicLinkerCommand();
49 void createDylibCommands();
52 void collectExportedAndImportedAndLocalAtoms();
53 void setNlistRange(std::vector
<class ObjectFile::Atom
*>& atoms
, uint32_t startIndex
, uint32_t count
);
54 void buildSymbolTable();
55 void setExportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
);
56 void setImportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
);
57 void setLocalNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
);
58 uint64_t getAtomLoadAddress(const ObjectFile::Atom
* atom
);
59 uint8_t ordinalForLibrary(ObjectFile::Reader
* file
);
60 bool shouldExport(ObjectFile::Atom
& atom
);
62 void adjustLinkEditSections();
63 void buildObjectFileFixups();
64 void buildExecutableFixups();
65 uint32_t symbolIndex(ObjectFile::Atom
& atom
);
66 uint32_t addRelocs(ObjectFile::Atom
* atom
, ObjectFile::Reference
* ref
);
67 unsigned int collectStabs();
68 macho_uintptr_t
valueForStab(const ObjectFile::StabsInfo
& stab
, const ObjectFile::Atom
* atom
);
69 void addStabs(uint32_t startIndex
, uint32_t count
);
72 class SectionInfo
: public ObjectFile::Section
{
75 void setIndex(unsigned int index
) { fIndex
=index
; }
76 std::vector
<ObjectFile::Atom
*> fAtoms
;
77 char fSegmentName
[20];
78 char fSectionName
[20];
82 uint32_t fRelocOffset
;
83 uint32_t fIndirectSymbolOffset
;
85 bool fAllLazyPointers
;
86 bool fAllNonLazyPointers
;
95 std::vector
<class SectionInfo
*> fSections
;
97 uint32_t fInitProtection
;
98 uint32_t fMaxProtection
;
101 uint64_t fBaseAddress
;
107 struct DirectLibrary
{
108 class ObjectFile::Reader
* fLibrary
;
113 struct IndirectEntry
{
114 uint32_t indirectIndex
;
115 uint32_t symbolIndex
;
119 ObjectFile::Atom
* fAtom
;
120 ObjectFile::Reader
* fReader
;
121 unsigned int fReaderOrder
;
122 unsigned int fOrderInReader
;
123 std::vector
<ObjectFile::StabsInfo
>* fStabs
;
126 static bool stabChunkCompare(const StabChunks
& lhs
, const StabChunks
& rhs
);
128 friend class WriterAtom
;
129 friend class PageZeroAtom
;
130 friend class CustomStackAtom
;
131 friend class MachHeaderAtom
;
132 friend class SegmentLoadCommandsAtom
;
133 friend class SymbolTableLoadCommandsAtom
;
134 friend class ThreadsLoadCommandsAtom
;
135 friend class DylibIDLoadCommandsAtom
;
136 friend class RoutinesLoadCommandsAtom
;
137 friend class DyldLoadCommandsAtom
;
138 friend class LinkEditAtom
;
139 friend class LocalRelocationsLinkEditAtom
;
140 friend class ExternalRelocationsLinkEditAtom
;
141 friend class SymbolTableLinkEditAtom
;
142 friend class IndirectTableLinkEditAtom
;
143 friend class StringsLinkEditAtom
;
145 const char* fFilePath
;
148 std::vector
<class ObjectFile::Atom
*>* fAllAtoms
;
149 class SectionInfo
* fLoadCommandsSection
;
150 class SegmentInfo
* fLoadCommandsSegment
;
151 class SegmentLoadCommandsAtom
* fSegmentCommands
;
152 class SymbolTableLoadCommandsAtom
* fSymbolTableCommands
;
153 class LoadCommandsPaddingAtom
* fHeaderPadding
;
154 std::vector
<class ObjectFile::Atom
*> fWriterSynthesizedAtoms
;
155 std::vector
<SegmentInfo
*> fSegmentInfos
;
156 class ObjectFile::Atom
* fEntryPoint
;
157 std::vector
<DirectLibrary
> fDirectLibraries
;
158 std::map
<class ObjectFile::Reader
*, uint32_t> fLibraryToOrdinal
;
159 std::vector
<StabChunks
> fStabChunks
;
160 std::vector
<class ObjectFile::Atom
*> fExportedAtoms
;
161 std::vector
<class ObjectFile::Atom
*> fImportedAtoms
;
162 std::vector
<class ObjectFile::Atom
*> fLocalSymbolAtoms
;
163 LocalRelocationsLinkEditAtom
* fLocalRelocationsAtom
;
164 ExternalRelocationsLinkEditAtom
* fExternalRelocationsAtom
;
165 SymbolTableLinkEditAtom
* fSymbolTableAtom
;
166 IndirectTableLinkEditAtom
* fIndirectTableAtom
;
167 StringsLinkEditAtom
* fStringsAtom
;
168 macho_nlist
* fSymbolTable
;
170 //uint32_t fStringPoolUsed;
171 //uint32_t fStringPoolSize;
172 std::vector
<macho_relocation_info
> fInternalRelocs
;
173 std::vector
<macho_relocation_info
> fExternalRelocs
;
174 std::vector
<IndirectEntry
> fIndirectSymbolTable
;
175 uint32_t fSymbolTableCount
;
176 uint32_t fSymbolTableStabsCount
;
177 uint32_t fSymbolTableStabsStartIndex
;
178 uint32_t fSymbolTableLocalCount
;
179 uint32_t fSymbolTableLocalStartIndex
;
180 uint32_t fSymbolTableExportCount
;
181 uint32_t fSymbolTableExportStartIndex
;
182 uint32_t fSymbolTableImportCount
;
183 uint32_t fSymbolTableImportStartIndex
;
184 bool fEmitVirtualSections
;
185 bool fHasWeakExports
;
186 bool fReferencesWeakImports
;
190 class WriterAtom
: public ObjectFile::Atom
195 enum Kind
{ zeropage
, machHeaderApp
, machHeaderDylib
, machHeaderBundle
, machHeaderObject
, loadCommands
, undefinedProxy
};
196 WriterAtom(Writer
& writer
, class WriterAtom::Segment
& segment
) : fWriter(writer
), fSegment(segment
) {}
198 virtual ObjectFile::Reader
* getFile() const { return &fWriter
; }
199 virtual const char* getName() const { return NULL
; }
200 virtual const char* getDisplayName() const { return this->getName(); }
201 virtual Scope
getScope() const { return ObjectFile::Atom::scopeTranslationUnit
; }
202 virtual bool isTentativeDefinition() const { return false; }
203 virtual bool isWeakDefinition() const { return false; }
204 virtual bool isCoalesableByName() const { return false; }
205 virtual bool isCoalesableByValue() const { return false; }
206 virtual bool isZeroFill() const { return false; }
207 virtual bool dontDeadStrip() const { return true; }
208 virtual bool dontStripName() const { return false; }
209 virtual bool isImportProxy() const { return false; }
210 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return fgEmptyReferenceList
; }
211 virtual bool mustRemainInSection() const { return true; }
212 virtual ObjectFile::Segment
& getSegment() const { return fSegment
; }
213 virtual bool requiresFollowOnAtom() const { return false; }
214 virtual ObjectFile::Atom
& getFollowOnAtom() const { return *((ObjectFile::Atom
*)NULL
); }
215 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo() const { return NULL
; }
216 virtual uint8_t getAlignment() const { return 2; }
217 virtual WeakImportSetting
getImportWeakness() const { return Atom::kWeakUnset
; }
218 virtual void copyRawContent(uint8_t buffer
[]) const { throw "don't use copyRawContent"; }
219 virtual void setScope(Scope
) { }
220 virtual void setImportWeakness(bool weakImport
) { }
224 virtual ~WriterAtom() {}
226 class Segment
: public ObjectFile::Segment
229 Segment(const char* name
, bool readable
, bool writable
, bool executable
, bool fixedAddress
)
230 : fName(name
), fReadable(readable
), fWritable(writable
), fExecutable(executable
), fFixedAddress(fixedAddress
) {}
231 virtual const char* getName() const { return fName
; }
232 virtual bool isContentReadable() const { return fReadable
; }
233 virtual bool isContentWritable() const { return fWritable
; }
234 virtual bool isContentExecutable() const { return fExecutable
; }
235 virtual bool hasFixedAddress() const { return fFixedAddress
; }
238 const bool fReadable
;
239 const bool fWritable
;
240 const bool fExecutable
;
241 const bool fFixedAddress
;
244 static std::vector
<ObjectFile::Reference
*> fgEmptyReferenceList
;
245 static Segment fgTextSegment
;
246 static Segment fgPageZeroSegment
;
247 static Segment fgLinkEditSegment
;
248 static Segment fgStackSegment
;
256 WriterAtom::Segment
WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
257 WriterAtom::Segment
WriterAtom::fgTextSegment("__TEXT", true, false, true, false);
258 WriterAtom::Segment
WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
259 WriterAtom::Segment
WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false, true);
260 std::vector
<ObjectFile::Reference
*> WriterAtom::fgEmptyReferenceList
;
262 class PageZeroAtom
: public WriterAtom
265 PageZeroAtom(Writer
& writer
) : WriterAtom(writer
, fgPageZeroSegment
) {}
266 virtual const char* getDisplayName() const { return "page zero content"; }
267 virtual bool isZeroFill() const { return true; }
268 virtual uint64_t getSize() const { return fWriter
.fOptions
.zeroPageSize(); }
269 virtual const char* getSectionName() const { return "._zeropage"; }
270 virtual uint8_t getAlignment() const { return 12; }
271 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
274 class MachHeaderAtom
: public WriterAtom
277 MachHeaderAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
278 virtual const char* getName() const;
279 virtual const char* getDisplayName() const;
280 virtual Scope
getScope() const;
281 virtual bool dontStripName() const;
282 virtual uint64_t getSize() const;
283 virtual uint8_t getAlignment() const { return 12; }
284 virtual const char* getSectionName() const { return "._mach_header"; }
285 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
288 class CustomStackAtom
: public WriterAtom
291 CustomStackAtom(Writer
& writer
);
292 virtual const char* getDisplayName() const { return "custom stack content"; }
293 virtual bool isZeroFill() const { return true; }
294 virtual uint64_t getSize() const { return fWriter
.fOptions
.customStackSize(); }
295 virtual const char* getSectionName() const { return "._stack"; }
296 virtual uint8_t getAlignment() const { return 12; }
297 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
300 class SegmentLoadCommandsAtom
: public WriterAtom
303 SegmentLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
), fCommandCount(0), fSize(0) { writer
.fSegmentCommands
= this; }
304 virtual const char* getDisplayName() const { return "segment load commands"; }
305 virtual uint64_t getSize() const { return fSize
; }
306 virtual uint8_t getAlignment() const { return 2; }
307 virtual const char* getSectionName() const { return "._load_commands"; }
308 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
312 unsigned int commandCount() { return fCommandCount
; }
313 void assignFileOffsets();
315 unsigned int fCommandCount
;
319 class SymbolTableLoadCommandsAtom
: public WriterAtom
322 SymbolTableLoadCommandsAtom(Writer
&);
323 virtual const char* getDisplayName() const { return "symbol table load commands"; }
324 virtual uint64_t getSize() const;
325 virtual uint8_t getAlignment() const { return 2; }
326 virtual const char* getSectionName() const { return "._load_commands"; }
327 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
330 macho_symtab_command fSymbolTable
;
331 macho_dysymtab_command fDynamicSymbolTable
;
334 class ThreadsLoadCommandsAtom
: public WriterAtom
337 ThreadsLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
338 virtual const char* getDisplayName() const { return "thread load commands"; }
339 virtual uint64_t getSize() const;
340 virtual uint8_t getAlignment() const { return 2; }
341 virtual const char* getSectionName() const { return "._load_commands"; }
342 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
345 uint32_t fBufferSize
;
348 class DyldLoadCommandsAtom
: public WriterAtom
351 DyldLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
352 virtual const char* getDisplayName() const { return "dyld load command"; }
353 virtual uint64_t getSize() const;
354 virtual uint8_t getAlignment() const { return 2; }
355 virtual const char* getSectionName() const { return "._load_commands"; }
356 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
359 class DylibLoadCommandsAtom
: public WriterAtom
362 DylibLoadCommandsAtom(Writer
& writer
, ExecutableFile::DyLibUsed
& info
) : WriterAtom(writer
, fgTextSegment
), fInfo(info
) {}
363 virtual const char* getDisplayName() const { return "dylib load command"; }
364 virtual uint64_t getSize() const;
365 virtual uint8_t getAlignment() const { return 2; }
366 virtual const char* getSectionName() const { return "._load_commands"; }
367 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
369 ExecutableFile::DyLibUsed
& fInfo
;
372 class DylibIDLoadCommandsAtom
: public WriterAtom
375 DylibIDLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
376 virtual const char* getDisplayName() const { return "dylib ID load command"; }
377 virtual uint64_t getSize() const;
378 virtual uint8_t getAlignment() const { return 2; }
379 virtual const char* getSectionName() const { return "._load_commands"; }
380 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
383 class RoutinesLoadCommandsAtom
: public WriterAtom
386 RoutinesLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
387 virtual const char* getDisplayName() const { return "routines load command"; }
388 virtual uint64_t getSize() const;
389 virtual uint8_t getAlignment() const { return 2; }
390 virtual const char* getSectionName() const { return "._load_commands"; }
391 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
394 class SubUmbrellaLoadCommandsAtom
: public WriterAtom
397 SubUmbrellaLoadCommandsAtom(Writer
& writer
, const char* name
) : WriterAtom(writer
, fgTextSegment
), fName(name
) {}
398 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
399 virtual uint64_t getSize() const;
400 virtual uint8_t getAlignment() const { return 2; }
401 virtual const char* getSectionName() const { return "._load_commands"; }
402 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
407 class SubLibraryLoadCommandsAtom
: public WriterAtom
410 SubLibraryLoadCommandsAtom(Writer
& writer
, const char* nameStart
, int nameLen
)
411 : WriterAtom(writer
, fgTextSegment
), fNameStart(nameStart
), fNameLength(nameLen
) {}
412 virtual const char* getDisplayName() const { return "sub-library load command"; }
413 virtual uint64_t getSize() const;
414 virtual uint8_t getAlignment() const { return 2; }
415 virtual const char* getSectionName() const { return "._load_commands"; }
416 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
418 const char* fNameStart
;
422 class UmbrellaLoadCommandsAtom
: public WriterAtom
425 UmbrellaLoadCommandsAtom(Writer
& writer
, const char* name
)
426 : WriterAtom(writer
, fgTextSegment
), fName(name
) {}
427 virtual const char* getDisplayName() const { return "umbrella load command"; }
428 virtual uint64_t getSize() const;
429 virtual uint8_t getAlignment() const { return 2; }
430 virtual const char* getSectionName() const { return "._load_commands"; }
431 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
436 class LoadCommandsPaddingAtom
: public WriterAtom
439 LoadCommandsPaddingAtom(Writer
& writer
)
440 : WriterAtom(writer
, fgTextSegment
), fSize(0) {}
441 virtual const char* getDisplayName() const { return "header padding"; }
442 virtual uint64_t getSize() const;
443 virtual uint8_t getAlignment() const { return 2; }
444 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
445 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
447 void setSize(uint64_t newSize
) { fSize
= newSize
; }
452 class LinkEditAtom
: public WriterAtom
455 LinkEditAtom(Writer
& writer
) : WriterAtom(writer
, fgLinkEditSegment
) {}
456 uint64_t getFileOffset() const;
459 class LocalRelocationsLinkEditAtom
: public LinkEditAtom
462 LocalRelocationsLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
463 virtual const char* getDisplayName() const { return "local relocations"; }
464 virtual uint64_t getSize() const;
465 virtual uint8_t getAlignment() const { return 3; }
466 virtual const char* getSectionName() const { return "._local_relocs"; }
467 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
470 class SymbolTableLinkEditAtom
: public LinkEditAtom
473 SymbolTableLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
474 virtual const char* getDisplayName() const { return "symbol table"; }
475 virtual uint64_t getSize() const;
476 virtual uint8_t getAlignment() const { return 2; }
477 virtual const char* getSectionName() const { return "._symbol_table"; }
478 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
481 class ExternalRelocationsLinkEditAtom
: public LinkEditAtom
484 ExternalRelocationsLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
485 virtual const char* getDisplayName() const { return "external relocations"; }
486 virtual uint64_t getSize() const;
487 virtual uint8_t getAlignment() const { return 3; }
488 virtual const char* getSectionName() const { return "._extern_relocs"; }
489 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
492 class IndirectTableLinkEditAtom
: public LinkEditAtom
495 IndirectTableLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
496 virtual const char* getDisplayName() const { return "indirect symbol table"; }
497 virtual uint64_t getSize() const;
498 virtual uint8_t getAlignment() const { return 2; }
499 virtual const char* getSectionName() const { return "._indirect_syms"; }
500 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
503 class StringsLinkEditAtom
: public LinkEditAtom
506 StringsLinkEditAtom(Writer
& writer
);
507 virtual const char* getDisplayName() const { return "string pool"; }
508 virtual uint64_t getSize() const;
509 virtual uint8_t getAlignment() const { return 2; }
510 virtual const char* getSectionName() const { return "._string_pool"; }
511 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
513 int32_t add(const char* name
);
514 int32_t emptyString();
517 enum { kBufferSize
= 0x01000000 };
519 std::vector
<char*> fFullBuffers
;
520 char* fCurrentBuffer
;
521 uint32_t fCurrentBufferUsed
;
526 class UndefinedSymbolProxyAtom
: public WriterAtom
529 UndefinedSymbolProxyAtom(Writer
& writer
, const char* name
) : WriterAtom(writer
, fgLinkEditSegment
), fName(name
), fWeakImportSetting(Atom::kWeakUnset
) {}
530 virtual const char* getName() const { return fName
; }
531 virtual Scope
getScope() const { return ObjectFile::Atom::scopeGlobal
; }
532 virtual uint64_t getSize() const { return 0; }
533 virtual bool isWeakDefinition() const { return true; }
534 virtual bool isImportProxy() const { return true; }
535 virtual const char* getSectionName() const { return "._imports"; }
536 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
537 virtual WeakImportSetting
getImportWeakness() const { return fWeakImportSetting
; }
538 virtual void setImportWeakness(bool weakImport
) { fWeakImportSetting
= weakImport
? kWeakImport
: kNonWeakImport
; }
541 WeakImportSetting fWeakImportSetting
;
544 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
545 class BranchIslandAtom
: public WriterAtom
548 BranchIslandAtom(Writer
& writer
, const char* name
, int islandRegion
, ObjectFile::Atom
& target
, uint32_t targetOffset
);
549 virtual const char* getName() const { return fName
; }
550 virtual Scope
getScope() const { return ObjectFile::Atom::scopeLinkageUnit
; }
551 virtual uint64_t getSize() const { return 4; }
552 virtual const char* getSectionName() const { return "__text"; }
553 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
556 ObjectFile::Atom
& fTarget
;
557 uint32_t fTargetOffset
;
563 bool operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
)
565 return (strcmp(left
->getName(), right
->getName()) < 0);
570 ExecutableFile::Writer
* MakeWriter(const char* path
, Options
& options
, std::vector
<ExecutableFile::DyLibUsed
>& dynamicLibraries
)
572 return new Writer(path
, options
, dynamicLibraries
);
575 Writer::SectionInfo::SectionInfo()
576 : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
577 fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
579 fSegmentName
[0] = '\0';
580 fSectionName
[0] = '\0';
583 Writer::SegmentInfo::SegmentInfo()
584 : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0), fFixedAddress(false)
590 Writer::Writer(const char* path
, Options
& options
, std::vector
<ExecutableFile::DyLibUsed
>& dynamicLibraries
)
591 : ExecutableFile::Writer(dynamicLibraries
), fFilePath(strdup(path
)), fOptions(options
), fLoadCommandsSection(NULL
),
592 fLoadCommandsSegment(NULL
),
593 //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0),
594 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
596 int permissions
= 0777;
597 if ( fOptions
.outputKind() == Options::kObjectFile
)
599 // Calling unlink first assures the file is gone so that open creates it with correct permissions
600 // It also handles the case where fFilePath file is not writeable but its directory is
601 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
602 (void)unlink(fFilePath
);
603 fFileDescriptor
= open(fFilePath
, O_CREAT
| O_WRONLY
| O_TRUNC
, permissions
);
604 if ( fFileDescriptor
== -1 ) {
605 throw "can't open file for writing";
608 switch ( fOptions
.outputKind() ) {
609 case Options::kDynamicExecutable
:
610 case Options::kStaticExecutable
:
611 fWriterSynthesizedAtoms
.push_back(new PageZeroAtom(*this));
612 fWriterSynthesizedAtoms
.push_back(new MachHeaderAtom(*this));
613 fWriterSynthesizedAtoms
.push_back(new SegmentLoadCommandsAtom(*this));
614 fWriterSynthesizedAtoms
.push_back(new SymbolTableLoadCommandsAtom(*this));
615 if ( fOptions
.outputKind() == Options::kDynamicExecutable
)
616 fWriterSynthesizedAtoms
.push_back(new DyldLoadCommandsAtom(*this));
617 fWriterSynthesizedAtoms
.push_back(new ThreadsLoadCommandsAtom(*this));
618 if ( fOptions
.hasCustomStack() )
619 fWriterSynthesizedAtoms
.push_back(new CustomStackAtom(*this));
620 fWriterSynthesizedAtoms
.push_back(fHeaderPadding
= new LoadCommandsPaddingAtom(*this));
621 fWriterSynthesizedAtoms
.push_back(fLocalRelocationsAtom
= new LocalRelocationsLinkEditAtom(*this));
622 fWriterSynthesizedAtoms
.push_back(fSymbolTableAtom
= new SymbolTableLinkEditAtom(*this));
623 fWriterSynthesizedAtoms
.push_back(fExternalRelocationsAtom
= new ExternalRelocationsLinkEditAtom(*this));
624 fWriterSynthesizedAtoms
.push_back(fIndirectTableAtom
= new IndirectTableLinkEditAtom(*this));
625 fWriterSynthesizedAtoms
.push_back(fStringsAtom
= new StringsLinkEditAtom(*this));
627 case Options::kDynamicLibrary
:
628 case Options::kDynamicBundle
:
629 case Options::kObjectFile
:
630 fWriterSynthesizedAtoms
.push_back(new MachHeaderAtom(*this));
631 fWriterSynthesizedAtoms
.push_back(new SegmentLoadCommandsAtom(*this));
632 if ( fOptions
.outputKind() == Options::kDynamicLibrary
) {
633 fWriterSynthesizedAtoms
.push_back(new DylibIDLoadCommandsAtom(*this));
634 if ( fOptions
.initFunctionName() != NULL
)
635 fWriterSynthesizedAtoms
.push_back(new RoutinesLoadCommandsAtom(*this));
637 fWriterSynthesizedAtoms
.push_back(new SymbolTableLoadCommandsAtom(*this));
638 fWriterSynthesizedAtoms
.push_back(fHeaderPadding
= new LoadCommandsPaddingAtom(*this));
639 fWriterSynthesizedAtoms
.push_back(fLocalRelocationsAtom
= new LocalRelocationsLinkEditAtom(*this));
640 fWriterSynthesizedAtoms
.push_back(fSymbolTableAtom
= new SymbolTableLinkEditAtom(*this));
641 fWriterSynthesizedAtoms
.push_back(fExternalRelocationsAtom
= new ExternalRelocationsLinkEditAtom(*this));
642 fWriterSynthesizedAtoms
.push_back(fIndirectTableAtom
= new IndirectTableLinkEditAtom(*this));
643 fWriterSynthesizedAtoms
.push_back(fStringsAtom
= new StringsLinkEditAtom(*this));
646 fWriterSynthesizedAtoms
.push_back(new MachHeaderAtom(*this));
647 fWriterSynthesizedAtoms
.push_back(new SegmentLoadCommandsAtom(*this));
648 fWriterSynthesizedAtoms
.push_back(new SymbolTableLoadCommandsAtom(*this));
649 fWriterSynthesizedAtoms
.push_back(new DyldLoadCommandsAtom(*this));
650 fWriterSynthesizedAtoms
.push_back(new ThreadsLoadCommandsAtom(*this));
651 fWriterSynthesizedAtoms
.push_back(fHeaderPadding
= new LoadCommandsPaddingAtom(*this));
652 fWriterSynthesizedAtoms
.push_back(fLocalRelocationsAtom
= new LocalRelocationsLinkEditAtom(*this));
653 fWriterSynthesizedAtoms
.push_back(fSymbolTableAtom
= new SymbolTableLinkEditAtom(*this));
654 fWriterSynthesizedAtoms
.push_back(fExternalRelocationsAtom
= new ExternalRelocationsLinkEditAtom(*this));
655 fWriterSynthesizedAtoms
.push_back(fIndirectTableAtom
= new IndirectTableLinkEditAtom(*this));
656 fWriterSynthesizedAtoms
.push_back(fStringsAtom
= new StringsLinkEditAtom(*this));
660 // add extra commmands
662 switch ( fOptions
.outputKind() ) {
663 case Options::kDynamicExecutable
:
664 case Options::kDynamicLibrary
:
665 case Options::kDynamicBundle
:
667 // add dylib load command atoms for all dynamic libraries
668 const unsigned int libCount
= dynamicLibraries
.size();
669 for (unsigned int i
=0; i
< libCount
; ++i
) {
670 ExecutableFile::DyLibUsed
& dylibInfo
= dynamicLibraries
[i
];
671 if ( dylibInfo
.indirect
) {
672 // find ordinal of direct reader
673 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
) {
675 for (std::map
<class ObjectFile::Reader
*, uint32_t>::iterator it
= fLibraryToOrdinal
.begin(); it
!= fLibraryToOrdinal
.end(); ++it
) {
676 if ( it
->first
== dylibInfo
.directReader
) {
677 //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
678 fLibraryToOrdinal
[dylibInfo
.reader
] = it
->second
;
684 fprintf(stderr
, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo
.reader
->getPath(), dylibInfo
.directReader
!= NULL
? dylibInfo
.directReader
->getPath() : NULL
);
688 // see if a DylibLoadCommandsAtom has already been created for this install path
689 bool newDylib
= true;
690 const char* dylibInstallPath
= dylibInfo
.reader
->getInstallPath();
691 if ( dylibInfo
.options
.fInstallPathOverride
!= NULL
)
692 dylibInstallPath
= dylibInfo
.options
.fInstallPathOverride
;
693 for (unsigned int seenLib
=0; seenLib
< i
; ++seenLib
) {
694 ExecutableFile::DyLibUsed
& seenDylibInfo
= dynamicLibraries
[seenLib
];
695 if ( !seenDylibInfo
.indirect
) {
696 const char* seenDylibInstallPath
= seenDylibInfo
.reader
->getInstallPath();
697 if ( seenDylibInfo
.options
.fInstallPathOverride
!= NULL
)
698 seenDylibInstallPath
= dylibInfo
.options
.fInstallPathOverride
;
699 if ( strcmp(seenDylibInstallPath
, dylibInstallPath
) == 0 ) {
700 fLibraryToOrdinal
[dylibInfo
.reader
] = fLibraryToOrdinal
[seenDylibInfo
.reader
];
708 // assign new ordinal and check for other paired load commands
709 fLibraryToOrdinal
[dylibInfo
.reader
] = ordinal
++;
710 fWriterSynthesizedAtoms
.push_back(new DylibLoadCommandsAtom(*this, dylibInfo
));
711 if ( dylibInfo
.options
.fReExport
) {
712 // this dylib also needs a sub_x load command
713 bool isFrameworkReExport
= false;
714 const char* lastSlash
= strrchr(dylibInstallPath
, '/');
715 if ( lastSlash
!= NULL
) {
716 char frameworkName
[strlen(lastSlash
)+20];
717 sprintf(frameworkName
, "/%s.framework/", &lastSlash
[1]);
718 isFrameworkReExport
= (strstr(dylibInstallPath
, frameworkName
) != NULL
);
720 if ( isFrameworkReExport
) {
721 // needs a LC_SUB_UMBRELLA command
722 fWriterSynthesizedAtoms
.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash
[1]));
725 // needs a LC_SUB_LIBRARY command
726 const char* nameStart
= &lastSlash
[1];
727 if ( lastSlash
== NULL
)
728 nameStart
= dylibInstallPath
;
729 int len
= strlen(nameStart
);
730 const char* dot
= strchr(nameStart
, '.');
732 len
= dot
- nameStart
;
733 fWriterSynthesizedAtoms
.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart
, len
));
739 // add umbrella command if needed
740 if ( fOptions
.umbrellaName() != NULL
) {
741 fWriterSynthesizedAtoms
.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions
.umbrellaName()));
745 case Options::kStaticExecutable
:
746 case Options::kObjectFile
:
751 //fprintf(stderr, "ordinals table:\n");
752 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
753 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
759 if ( fFilePath
!= NULL
)
760 free((void*)fFilePath
);
761 if ( fSymbolTable
!= NULL
)
762 delete [] fSymbolTable
;
763 //if ( fStringPool != NULL )
764 // delete [] fStringPool;
767 const char* Writer::getPath()
773 std::vector
<class ObjectFile::Atom
*>& Writer::getAtoms()
775 return fWriterSynthesizedAtoms
;
778 std::vector
<class ObjectFile::Atom
*>* Writer::getJustInTimeAtomsFor(const char* name
)
783 std::vector
<ObjectFile::StabsInfo
>* Writer::getStabsDebugInfo()
788 ObjectFile::Atom
* Writer::getUndefinedProxyAtom(const char* name
)
790 if ( (fOptions
.outputKind() == Options::kObjectFile
)
791 || (fOptions
.undefinedTreatment() != Options::kUndefinedError
) )
792 return new UndefinedSymbolProxyAtom(*this, name
);
797 uint8_t Writer::ordinalForLibrary(ObjectFile::Reader
* lib
)
799 // flat namespace images use zero for all ordinals
800 if ( fOptions
.nameSpace() != Options::kTwoLevelNameSpace
)
803 // is an UndefinedSymbolProxyAtom
805 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
)
806 return DYNAMIC_LOOKUP_ORDINAL
;
808 std::map
<class ObjectFile::Reader
*, uint32_t>::iterator pos
= fLibraryToOrdinal
.find(lib
);
809 if ( pos
!= fLibraryToOrdinal
.end() )
812 throw "can't find ordinal for imported symbol";
816 void Writer::write(std::vector
<class ObjectFile::Atom
*>& atoms
, class ObjectFile::Atom
* entryPointAtom
)
819 fEntryPoint
= entryPointAtom
;
821 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
822 partitionIntoSections();
824 // segment load command can now be sized and padding can be set
825 adjustLoadCommandsAndPadding();
827 // assign each section a file offset
830 // if need to add branch islands, reassign file offsets
831 if ( addBranchIslands() )
834 // build symbol table and relocations
841 void Writer::buildLinkEdit()
843 this->collectExportedAndImportedAndLocalAtoms();
844 this->buildSymbolTable();
846 this->adjustLinkEditSections();
851 uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom
* atom
)
853 return atom
->getAddress();
854 // SectionInfo* info = (SectionInfo*)atom->getSection();
855 // return info->getBaseAddress() + atom->getSectionOffset();
858 void Writer::setExportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
)
861 entry
->set_n_type(N_EXT
| N_SECT
);
862 if ( (atom
->getScope() == ObjectFile::Atom::scopeLinkageUnit
) && fOptions
.keepPrivateExterns() && (fOptions
.outputKind() == Options::kObjectFile
) )
863 entry
->set_n_type(N_EXT
| N_SECT
| N_PEXT
);
865 // set n_sect (section number of implementation )
866 uint8_t sectionIndex
= atom
->getSection()->getIndex();
867 entry
->set_n_sect(sectionIndex
);
869 // the __mh_execute_header is magic and must be an absolute symbol
870 if ( (fOptions
.outputKind() == Options::kDynamicExecutable
) && (sectionIndex
==0) && atom
->dontStripName())
871 entry
->set_n_type(N_EXT
| N_ABS
);
875 if ( atom
->dontStripName() )
876 desc
|= REFERENCED_DYNAMICALLY
;
877 if ( atom
->isWeakDefinition() && (strcmp(atom
->getSectionName(), "__common") != 0) ) {
879 fHasWeakExports
= true;
881 entry
->set_n_desc(desc
);
883 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
884 entry
->set_n_value(this->getAtomLoadAddress(atom
));
887 void Writer::setImportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
)
890 entry
->set_n_type(N_UNDF
| N_EXT
);
893 entry
->set_n_sect(0);
896 if ( fOptions
.outputKind() != Options::kObjectFile
) {
897 // set n_desc ( high byte is library ordinal, low byte is reference type )
898 desc
= REFERENCE_FLAG_UNDEFINED_LAZY
; // FIXME
900 uint8_t ordinal
= this->ordinalForLibrary(atom
->getFile());
901 SET_LIBRARY_ORDINAL(desc
, ordinal
);
903 catch (const char* msg
) {
904 throwf("%s %s from %s", msg
, atom
->getDisplayName(), atom
->getFile()->getPath());
907 if ( atom
->dontStripName() )
908 desc
|= REFERENCED_DYNAMICALLY
;
909 // an import proxy is always weak (overridden by definition in .o files)
910 // so we ask its reader if the exported symbol in its dylib is weak
911 if ( ( fOptions
.outputKind() != Options::kObjectFile
) && atom
->getFile()->isDefinitionWeak(*atom
) ) {
912 desc
|= N_REF_TO_WEAK
;
913 fReferencesWeakImports
= true;
915 // set weak_import attribute
916 if ( atom
->getImportWeakness() == ObjectFile::Atom::kWeakImport
)
918 entry
->set_n_desc(desc
);
920 // set n_value, zero for import proxy and size for tentative definition
921 entry
->set_n_value(atom
->getSize());
924 void Writer::setLocalNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
)
927 uint8_t type
= N_SECT
;
928 if ( atom
->getScope() == ObjectFile::Atom::scopeLinkageUnit
)
930 entry
->set_n_type(type
);
932 // set n_sect (section number of implementation )
933 uint8_t sectIndex
= atom
->getSection()->getIndex();
934 if ( sectIndex
== 0 ) {
935 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
936 if ( strcmp(atom
->getSectionName(), "._mach_header") == 0 )
939 entry
->set_n_sect(sectIndex
);
943 if ( atom
->isWeakDefinition() && (strcmp(atom
->getSectionName(), "__common") != 0) ) // commons on not weak
945 entry
->set_n_desc(desc
);
947 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
948 entry
->set_n_value(this->getAtomLoadAddress(atom
));
952 void Writer::setNlistRange(std::vector
<class ObjectFile::Atom
*>& atoms
, uint32_t startIndex
, uint32_t count
)
954 macho_nlist
* entry
= &fSymbolTable
[startIndex
];
955 for (uint32_t i
=0; i
< count
; ++i
, ++entry
) {
956 ObjectFile::Atom
* atom
= atoms
[i
];
957 entry
->set_n_strx(this->fStringsAtom
->add(atom
->getName()));
958 if ( &atoms
== &fExportedAtoms
) {
959 this->setExportNlist(atom
, entry
);
961 else if ( &atoms
== &fImportedAtoms
) {
962 this->setImportNlist(atom
, entry
);
965 this->setLocalNlist(atom
, entry
);
970 void Writer::buildSymbolTable()
972 fSymbolTableStabsStartIndex
= 0;
973 fSymbolTableStabsCount
= this->collectStabs();
974 fSymbolTableLocalStartIndex
= fSymbolTableStabsStartIndex
+ fSymbolTableStabsCount
;
975 fSymbolTableLocalCount
= fLocalSymbolAtoms
.size();
976 fSymbolTableExportStartIndex
= fSymbolTableLocalStartIndex
+ fSymbolTableLocalCount
;
977 fSymbolTableExportCount
= fExportedAtoms
.size();
978 fSymbolTableImportStartIndex
= fSymbolTableExportStartIndex
+ fSymbolTableExportCount
;
979 fSymbolTableImportCount
= fImportedAtoms
.size();
981 // allocate symbol table
982 fSymbolTableCount
= fSymbolTableStabsCount
+ fSymbolTableLocalCount
+ fSymbolTableExportCount
+ fSymbolTableImportCount
;
983 fSymbolTable
= new macho_nlist
[fSymbolTableCount
];
985 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
986 setNlistRange(fLocalSymbolAtoms
, fSymbolTableLocalStartIndex
, fSymbolTableLocalCount
);
987 setNlistRange(fExportedAtoms
, fSymbolTableExportStartIndex
, fSymbolTableExportCount
);
988 setNlistRange(fImportedAtoms
, fSymbolTableImportStartIndex
, fSymbolTableImportCount
);
989 addStabs(fSymbolTableStabsStartIndex
, fSymbolTableStabsCount
);
994 bool Writer::shouldExport(ObjectFile::Atom
& atom
)
996 switch ( atom
.getScope() ) {
997 case ObjectFile::Atom::scopeGlobal
:
999 case ObjectFile::Atom::scopeLinkageUnit
:
1000 return ( fOptions
.keepPrivateExterns() && (fOptions
.outputKind() == Options::kObjectFile
) );
1006 void Writer::collectExportedAndImportedAndLocalAtoms()
1008 const int atomCount
= fAllAtoms
->size();
1009 for (int i
=0; i
< atomCount
; ++i
) {
1010 ObjectFile::Atom
* atom
= (*fAllAtoms
)[i
];
1011 // only named atoms go in symbol table
1012 if ( atom
->getName() != NULL
) {
1013 // put atom into correct bucket: imports, exports, locals
1014 //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
1015 if ( atom
->isImportProxy() || ((fOptions
.outputKind() == Options::kObjectFile
) && (strcmp(atom
->getSectionName(), "__common") == 0)) )
1016 fImportedAtoms
.push_back(atom
);
1017 else if ( this->shouldExport(*atom
) )
1018 fExportedAtoms
.push_back(atom
);
1019 else if ( !fOptions
.stripLocalSymbols() )
1020 fLocalSymbolAtoms
.push_back(atom
);
1024 // sort exported atoms by name
1025 std::sort(fExportedAtoms
.begin(), fExportedAtoms
.end(), ExportSorter());
1029 bool Writer::stabChunkCompare(const struct StabChunks
& lhs
, const struct StabChunks
& rhs
)
1031 if ( lhs
.fReader
!= rhs
.fReader
) {
1032 return lhs
.fReaderOrder
< rhs
.fReaderOrder
;
1034 return lhs
.fOrderInReader
< rhs
.fOrderInReader
;
1037 unsigned int Writer::collectStabs()
1039 unsigned int count
= 0;
1041 // collect all stabs chunks
1042 std::set
<ObjectFile::Reader
*> seenReaders
;
1043 std::map
<ObjectFile::Reader
*, unsigned int> readerOrdinals
;
1044 const int atomCount
= fAllAtoms
->size();
1045 for (int i
=0; i
< atomCount
; ++i
) {
1046 ObjectFile::Atom
* atom
= (*fAllAtoms
)[i
];
1047 ObjectFile::Reader
* atomsReader
= atom
->getFile();
1048 unsigned int readerOrder
= 0;
1049 if ( atomsReader
!= NULL
) {
1050 std::map
<ObjectFile::Reader
*, unsigned int>::iterator pos
= readerOrdinals
.find(atomsReader
);
1051 if ( pos
== readerOrdinals
.end() ) {
1052 readerOrder
= readerOrdinals
.size();
1053 readerOrdinals
[atomsReader
] = readerOrder
;
1054 std::vector
<ObjectFile::StabsInfo
>* readerStabs
= atomsReader
->getStabsDebugInfo();
1055 if ( readerStabs
!= NULL
) {
1058 chunk
.fReader
= atomsReader
;
1059 chunk
.fReaderOrder
= readerOrder
;
1060 chunk
.fOrderInReader
= 0;
1061 chunk
.fStabs
= readerStabs
;
1062 fStabChunks
.push_back(chunk
);
1063 count
+= readerStabs
->size() + 1; // extra one is for trailing N_SO
1067 readerOrder
= pos
->second
;
1070 std::vector
<ObjectFile::StabsInfo
>* atomStabs
= atom
->getStabsDebugInfo();
1071 if ( atomStabs
!= NULL
) {
1074 chunk
.fReader
= atomsReader
;
1075 chunk
.fReaderOrder
= readerOrder
;
1076 chunk
.fOrderInReader
= atom
->getSortOrder();
1077 chunk
.fStabs
= atomStabs
;
1078 fStabChunks
.push_back(chunk
);
1079 count
+= atomStabs
->size();
1083 // sort stabs: group by .o file
1084 std::sort(fStabChunks
.begin(), fStabChunks
.end(), stabChunkCompare
);
1086 //fprintf(stderr, "Sorted stabs:\n");
1087 //for (std::vector<StabChunks>::iterator it=fStabChunks.begin(); it != fStabChunks.end(); it++) {
1088 // ObjectFile::Atom* atom = (*it).fAtom;
1089 // if ( atom != NULL )
1090 // fprintf(stderr, "\t%s\n", (*it).fAtom->getDisplayName());
1092 // fprintf(stderr, "\t%s\n", (*it).fReader->getPath());
1098 macho_uintptr_t
Writer::valueForStab(const ObjectFile::StabsInfo
& stab
, const ObjectFile::Atom
* atom
)
1100 switch ( stab
.type
) {
1102 if ( stab
.other
== 0 )
1104 // end of function N_FUN has size (not address) so should not be adjusted
1113 // all these stab types need their value changed from an offset in the atom to an address
1115 return getAtomLoadAddress(atom
) + stab
.atomOffset
;
1117 return stab
.atomOffset
;
1121 void Writer::addStabs(uint32_t startIndex
, uint32_t count
)
1123 macho_nlist
* entry
= &fSymbolTable
[startIndex
];
1124 const int chunkCount
= fStabChunks
.size();
1125 for (int i
=0; i
< chunkCount
; ++i
) {
1126 const StabChunks
& chunk
= fStabChunks
[i
];
1127 const int stabCount
= chunk
.fStabs
->size();
1128 for (int j
=0; j
< stabCount
; ++j
) {
1129 const ObjectFile::StabsInfo
& stab
= (*chunk
.fStabs
)[j
];
1130 entry
->set_n_type(stab
.type
);
1131 entry
->set_n_sect(stab
.other
);
1132 entry
->set_n_desc(stab
.desc
);
1133 entry
->set_n_value(valueForStab(stab
, chunk
.fAtom
));
1134 entry
->set_n_strx(this->fStringsAtom
->add(stab
.string
));
1137 if ( (i
== chunkCount
-1) || (fStabChunks
[i
+1].fReader
!= chunk
.fReader
) ) {
1138 // need to add empty SO at end of each file
1139 entry
->set_n_type(N_SO
);
1140 entry
->set_n_sect(1);
1141 entry
->set_n_desc(0);
1142 entry
->set_n_value(0);
1143 entry
->set_n_strx(this->fStringsAtom
->emptyString());
1151 uint32_t Writer::symbolIndex(ObjectFile::Atom
& atom
)
1155 for(std::vector
<ObjectFile::Atom
*>::iterator it
=fImportedAtoms
.begin(); it
!= fImportedAtoms
.end(); ++it
) {
1157 return i
+ fSymbolTableImportStartIndex
;
1163 for(std::vector
<ObjectFile::Atom
*>::iterator it
=fLocalSymbolAtoms
.begin(); it
!= fLocalSymbolAtoms
.end(); ++it
) {
1165 return i
+ fSymbolTableLocalStartIndex
;
1171 for(std::vector
<ObjectFile::Atom
*>::iterator it
=fExportedAtoms
.begin(); it
!= fExportedAtoms
.end(); ++it
) {
1173 return i
+ fSymbolTableExportStartIndex
;
1177 fprintf(stderr
, "symbolIndex(%s)\n", atom
.getDisplayName());
1178 fprintf(stderr
, "from %s\n", atom
.getFile()->getPath());
1179 throw "atom not found";
1182 void Writer::buildFixups()
1184 if ( fOptions
.outputKind() == Options::kObjectFile
)
1185 this->buildObjectFileFixups();
1187 this->buildExecutableFixups();
1190 uint32_t Writer::addRelocs(ObjectFile::Atom
* atom
, ObjectFile::Reference
* ref
)
1192 ObjectFile::Atom
& target
= ref
->getTarget();
1193 bool isExtern
= target
.isImportProxy() || ( strcmp(target
.getSectionName(), "__common") == 0 );
1194 uint32_t symbolIndex
= 0;
1196 symbolIndex
= this->symbolIndex(target
);
1197 uint32_t sectionNum
= target
.getSection()->getIndex();
1198 uint32_t address
= atom
->getSectionOffset()+ref
->getFixUpOffset();
1199 macho_relocation_info reloc1
;
1200 macho_relocation_info reloc2
;
1201 macho_scattered_relocation_info
* sreloc1
= (macho_scattered_relocation_info
*)&reloc1
;
1202 macho_scattered_relocation_info
* sreloc2
= (macho_scattered_relocation_info
*)&reloc2
;
1204 switch ( ref
->getKind() ) {
1205 case ObjectFile::Reference::noFixUp
:
1208 case ObjectFile::Reference::pointer
:
1209 reloc1
.set_r_address(address
);
1211 reloc1
.set_r_symbolnum(symbolIndex
);
1213 reloc1
.set_r_symbolnum(sectionNum
);
1214 reloc1
.set_r_pcrel(false);
1215 reloc1
.set_r_length(macho_relocation_info::pointer_length
);
1216 reloc1
.set_r_extern(isExtern
);
1217 reloc1
.set_r_type(GENERIC_RELOC_VANILLA
);
1218 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1221 case ObjectFile::Reference::ppcFixupBranch24
:
1222 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1223 reloc1
.set_r_address(address
);
1225 reloc1
.set_r_symbolnum(symbolIndex
);
1227 reloc1
.set_r_symbolnum(sectionNum
);
1228 reloc1
.set_r_pcrel(true);
1229 reloc1
.set_r_length(2);
1230 reloc1
.set_r_type(PPC_RELOC_BR24
);
1231 reloc1
.set_r_extern(isExtern
);
1234 sreloc1
->set_r_scattered(true);
1235 sreloc1
->set_r_pcrel(true);
1236 sreloc1
->set_r_length(2);
1237 sreloc1
->set_r_type(PPC_RELOC_BR24
);
1238 sreloc1
->set_r_address(address
);
1239 sreloc1
->set_r_value(target
.getAddress());
1241 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1244 case ObjectFile::Reference::ppcFixupBranch14
:
1245 reloc1
.set_r_address(address
);
1246 reloc1
.set_r_symbolnum(sectionNum
);
1247 reloc1
.set_r_pcrel(true);
1248 reloc1
.set_r_length(2);
1249 reloc1
.set_r_extern(false);
1250 reloc1
.set_r_type(PPC_RELOC_BR14
);
1251 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1254 case ObjectFile::Reference::ppcFixupPicBaseLow14
:
1255 case ObjectFile::Reference::ppcFixupPicBaseLow16
:
1257 macho_uintptr_t fromAddr
= atom
->getAddress() + ref
->getFromTargetOffset();
1258 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1259 uint32_t overflow
= 0;
1260 if ( ((toAddr
-fromAddr
) & 0x00008000) != 0 )
1262 sreloc1
->set_r_scattered(true);
1263 sreloc1
->set_r_pcrel(false);
1264 sreloc1
->set_r_length(2);
1265 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16
)
1266 sreloc1
->set_r_type(PPC_RELOC_LO16_SECTDIFF
);
1268 sreloc1
->set_r_type(PPC_RELOC_LO14_SECTDIFF
);
1269 sreloc1
->set_r_address(address
);
1270 sreloc1
->set_r_value(target
.getAddress());
1271 sreloc2
->set_r_scattered(true);
1272 sreloc2
->set_r_pcrel(false);
1273 sreloc2
->set_r_length(2);
1274 sreloc2
->set_r_type(PPC_RELOC_PAIR
);
1275 sreloc2
->set_r_address(((toAddr
-fromAddr
) >> 16));
1276 sreloc2
->set_r_value(fromAddr
);
1277 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1278 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1282 case ObjectFile::Reference::ppcFixupPicBaseHigh16
:
1284 macho_uintptr_t fromAddr
= atom
->getAddress() + ref
->getFromTargetOffset();
1285 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1286 sreloc1
->set_r_scattered(true);
1287 sreloc1
->set_r_pcrel(false);
1288 sreloc1
->set_r_length(2);
1289 sreloc1
->set_r_type(PPC_RELOC_HA16_SECTDIFF
);
1290 sreloc1
->set_r_address(address
);
1291 sreloc1
->set_r_value(target
.getAddress());
1292 sreloc2
->set_r_scattered(true);
1293 sreloc2
->set_r_pcrel(false);
1294 sreloc2
->set_r_length(2);
1295 sreloc2
->set_r_type(PPC_RELOC_PAIR
);
1296 sreloc2
->set_r_address((toAddr
-fromAddr
) & 0xFFFF);
1297 sreloc2
->set_r_value(fromAddr
);
1298 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1299 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1303 case ObjectFile::Reference::ppcFixupAbsLow14
:
1304 case ObjectFile::Reference::ppcFixupAbsLow16
:
1306 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1307 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1308 reloc1
.set_r_address(address
);
1310 reloc1
.set_r_symbolnum(symbolIndex
);
1312 reloc1
.set_r_symbolnum(sectionNum
);
1313 reloc1
.set_r_pcrel(false);
1314 reloc1
.set_r_length(2);
1315 reloc1
.set_r_extern(isExtern
);
1316 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupAbsLow16
)
1317 reloc1
.set_r_type(PPC_RELOC_LO16
);
1319 reloc1
.set_r_type(PPC_RELOC_LO14
);
1322 sreloc1
->set_r_scattered(true);
1323 sreloc1
->set_r_pcrel(false);
1324 sreloc1
->set_r_length(2);
1325 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupAbsLow16
)
1326 sreloc1
->set_r_type(PPC_RELOC_LO16
);
1328 sreloc1
->set_r_type(PPC_RELOC_LO14
);
1329 sreloc1
->set_r_address(address
);
1330 sreloc1
->set_r_value(target
.getAddress());
1333 reloc2
.set_r_address(ref
->getTargetOffset() >> 16);
1335 reloc2
.set_r_address(toAddr
>> 16);
1336 reloc2
.set_r_symbolnum(0);
1337 reloc2
.set_r_pcrel(false);
1338 reloc2
.set_r_length(2);
1339 reloc2
.set_r_extern(false);
1340 reloc2
.set_r_type(PPC_RELOC_PAIR
);
1341 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1342 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1346 case ObjectFile::Reference::ppcFixupAbsHigh16
:
1348 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1349 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1350 reloc1
.set_r_address(address
);
1352 reloc1
.set_r_symbolnum(symbolIndex
);
1354 reloc1
.set_r_symbolnum(sectionNum
);
1355 reloc1
.set_r_pcrel(false);
1356 reloc1
.set_r_length(2);
1357 reloc1
.set_r_extern(isExtern
);
1358 reloc1
.set_r_type(PPC_RELOC_HI16
);
1361 sreloc1
->set_r_scattered(true);
1362 sreloc1
->set_r_pcrel(false);
1363 sreloc1
->set_r_length(2);
1364 sreloc1
->set_r_type(PPC_RELOC_HI16
);
1365 sreloc1
->set_r_address(address
);
1366 sreloc1
->set_r_value(target
.getAddress());
1369 reloc2
.set_r_address(ref
->getTargetOffset() & 0xFFFF);
1371 reloc2
.set_r_address(toAddr
& 0xFFFF);
1372 reloc2
.set_r_symbolnum(0);
1373 reloc2
.set_r_pcrel(false);
1374 reloc2
.set_r_length(2);
1375 reloc2
.set_r_extern(false);
1376 reloc2
.set_r_type(PPC_RELOC_PAIR
);
1377 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1378 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1382 case ObjectFile::Reference::ppcFixupAbsHigh16AddLow
:
1384 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1385 uint32_t overflow
= 0;
1386 if ( (toAddr
& 0x00008000) != 0 )
1388 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1389 reloc1
.set_r_address(address
);
1391 reloc1
.set_r_symbolnum(symbolIndex
);
1393 reloc1
.set_r_symbolnum(sectionNum
);
1394 reloc1
.set_r_pcrel(false);
1395 reloc1
.set_r_length(2);
1396 reloc1
.set_r_extern(isExtern
);
1397 reloc1
.set_r_type(PPC_RELOC_HA16
);
1400 sreloc1
->set_r_scattered(true);
1401 sreloc1
->set_r_pcrel(false);
1402 sreloc1
->set_r_length(2);
1403 sreloc1
->set_r_type(PPC_RELOC_HA16
);
1404 sreloc1
->set_r_address(address
);
1405 sreloc1
->set_r_value(target
.getAddress());
1408 reloc2
.set_r_address(ref
->getTargetOffset() & 0xFFFF);
1410 reloc2
.set_r_address(toAddr
& 0xFFFF);
1411 reloc2
.set_r_symbolnum(0);
1412 reloc2
.set_r_pcrel(false);
1413 reloc2
.set_r_length(2);
1414 reloc2
.set_r_extern(false);
1415 reloc2
.set_r_type(PPC_RELOC_PAIR
);
1416 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1417 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1421 case ObjectFile::Reference::pointer32Difference
:
1422 case ObjectFile::Reference::pointer64Difference
:
1424 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1425 macho_uintptr_t fromAddr
= ref
->getFromTarget().getAddress() + ref
->getFromTargetOffset();
1426 sreloc1
->set_r_scattered(true);
1427 sreloc1
->set_r_pcrel(false);
1428 if ( ref
->getKind() == ObjectFile::Reference::pointer64Difference
)
1429 sreloc1
->set_r_length(3);
1431 sreloc1
->set_r_length(2);
1432 if ( ref
->getTargetOffset() != 0 )
1433 sreloc1
->set_r_type(PPC_RELOC_LOCAL_SECTDIFF
);
1435 sreloc1
->set_r_type(PPC_RELOC_SECTDIFF
);
1436 sreloc1
->set_r_address(address
);
1437 sreloc1
->set_r_value(toAddr
);
1438 sreloc2
->set_r_scattered(true);
1439 sreloc2
->set_r_pcrel(false);
1440 sreloc2
->set_r_length(macho_relocation_info::pointer_length
);
1441 sreloc2
->set_r_type(PPC_RELOC_PAIR
);
1442 sreloc2
->set_r_address(0);
1443 sreloc2
->set_r_value(fromAddr
);
1444 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1445 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1449 case ObjectFile::Reference::x86FixupBranch32
:
1450 reloc1
.set_r_address(address
);
1451 reloc1
.set_r_symbolnum(sectionNum
);
1452 reloc1
.set_r_pcrel(true);
1453 reloc1
.set_r_length(2);
1454 reloc1
.set_r_extern(false);
1455 reloc1
.set_r_type(GENERIC_RELOC_VANILLA
);
1456 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1464 void Writer::buildObjectFileFixups()
1466 uint32_t relocIndex
= 0;
1467 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1468 const int segCount
= segmentInfos
.size();
1469 for(int i
=0; i
< segCount
; ++i
) {
1470 SegmentInfo
* curSegment
= segmentInfos
[i
];
1471 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1472 const int sectionCount
= sectionInfos
.size();
1473 for(int j
=0; j
< sectionCount
; ++j
) {
1474 SectionInfo
* curSection
= sectionInfos
[j
];
1475 std::vector
<ObjectFile::Atom
*>& sectionAtoms
= curSection
->fAtoms
;
1476 if ( ! curSection
->fAllZeroFill
) {
1477 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
)
1478 curSection
->fIndirectSymbolOffset
= fIndirectSymbolTable
.size();
1479 curSection
->fRelocOffset
= relocIndex
;
1480 const int atomCount
= sectionAtoms
.size();
1481 for (int k
=0; k
< atomCount
; ++k
) {
1482 ObjectFile::Atom
* atom
= sectionAtoms
[k
];
1483 std::vector
<ObjectFile::Reference
*>& refs
= atom
->getReferences();
1484 const int refCount
= refs
.size();
1485 for (int l
=0; l
< refCount
; ++l
) {
1486 ObjectFile::Reference
* ref
= refs
[l
];
1487 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
) {
1488 uint32_t offsetInSection
= atom
->getSectionOffset();
1489 uint32_t indexInSection
= offsetInSection
/ sizeof(macho_uintptr_t
);
1490 uint32_t undefinedSymbolIndex
= this->symbolIndex(ref
->getTarget());
1491 uint32_t indirectTableIndex
= indexInSection
+ curSection
->fIndirectSymbolOffset
;
1492 IndirectEntry entry
= { indirectTableIndex
, undefinedSymbolIndex
};
1493 //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
1494 fIndirectSymbolTable
.push_back(entry
);
1495 if ( curSection
->fAllLazyPointers
) {
1496 ObjectFile::Atom
& target
= ref
->getTarget();
1497 ObjectFile::Atom
& fromTarget
= ref
->getFromTarget();
1498 if ( &fromTarget
== NULL
) {
1499 fprintf(stderr
, "lazy pointer %s missing initial binding\n", atom
->getDisplayName());
1502 bool isExtern
= target
.isImportProxy();
1503 uint32_t symbolIndex
= 0;
1505 symbolIndex
= this->symbolIndex(target
);
1506 uint32_t sectionNum
= target
.getSection()->getIndex();
1507 uint32_t address
= atom
->getSectionOffset();
1508 macho_relocation_info reloc1
;
1509 reloc1
.set_r_address(address
);
1511 reloc1
.set_r_symbolnum(symbolIndex
);
1513 reloc1
.set_r_symbolnum(sectionNum
);
1514 reloc1
.set_r_pcrel(false);
1515 reloc1
.set_r_length(macho_relocation_info::pointer_length
);
1516 reloc1
.set_r_extern(isExtern
);
1517 reloc1
.set_r_type(GENERIC_RELOC_VANILLA
);
1518 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1524 relocIndex
+= this->addRelocs(atom
, ref
);
1528 curSection
->fRelocCount
= relocIndex
- curSection
->fRelocOffset
;
1533 // now reverse reloc entries
1534 for(int i
=0; i
< segCount
; ++i
) {
1535 SegmentInfo
* curSegment
= segmentInfos
[i
];
1536 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1537 const int sectionCount
= sectionInfos
.size();
1538 for(int j
=0; j
< sectionCount
; ++j
) {
1539 SectionInfo
* curSection
= sectionInfos
[j
];
1540 curSection
->fRelocOffset
= relocIndex
- curSection
->fRelocOffset
- curSection
->fRelocCount
;
1547 void Writer::buildExecutableFixups()
1549 const bool slideable
= (fOptions
.outputKind() != Options::kDynamicExecutable
) && (fOptions
.outputKind() != Options::kStaticExecutable
);
1550 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1551 const int segCount
= segmentInfos
.size();
1552 for(int i
=0; i
< segCount
; ++i
) {
1553 SegmentInfo
* curSegment
= segmentInfos
[i
];
1554 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1555 const int sectionCount
= sectionInfos
.size();
1556 for(int j
=0; j
< sectionCount
; ++j
) {
1557 SectionInfo
* curSection
= sectionInfos
[j
];
1558 std::vector
<ObjectFile::Atom
*>& sectionAtoms
= curSection
->fAtoms
;
1559 if ( ! curSection
->fAllZeroFill
) {
1560 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
)
1561 curSection
->fIndirectSymbolOffset
= fIndirectSymbolTable
.size();
1562 const int atomCount
= sectionAtoms
.size();
1563 for (int k
=0; k
< atomCount
; ++k
) {
1564 ObjectFile::Atom
* atom
= sectionAtoms
[k
];
1565 std::vector
<ObjectFile::Reference
*>& refs
= atom
->getReferences();
1566 const int refCount
= refs
.size();
1567 //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
1568 for (int l
=0; l
< refCount
; ++l
) {
1569 ObjectFile::Reference
* ref
= refs
[l
];
1570 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
) {
1571 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
1572 if ( atom
->getSize() != sizeof(macho_uintptr_t
) ) {
1573 printf("wrong size pointer atom %s from file %s\n", atom
->getDisplayName(), atom
->getFile()->getPath());
1575 uint32_t offsetInSection
= atom
->getSectionOffset();
1576 uint32_t indexInSection
= offsetInSection
/ sizeof(macho_uintptr_t
);
1577 uint32_t undefinedSymbolIndex
= INDIRECT_SYMBOL_LOCAL
;
1578 //fprintf(stderr,"indirect pointer atom %p %s section offset = %d\n", atom, atom->getDisplayName(), offsetInSection);
1579 if ( ref
->getTarget().isImportProxy()
1580 || ref
->getTarget().isWeakDefinition()
1581 || (fOptions
.interposable() && fOptions
.shouldExport(ref
->getTarget().getName()))
1582 || (fOptions
.nameSpace() == Options::kFlatNameSpace
)
1583 || (fOptions
.nameSpace() == Options::kForceFlatNameSpace
) ) {
1584 undefinedSymbolIndex
= this->symbolIndex(ref
->getTarget());
1586 uint32_t indirectTableIndex
= indexInSection
+ curSection
->fIndirectSymbolOffset
;
1587 IndirectEntry entry
= { indirectTableIndex
, undefinedSymbolIndex
};
1588 //fprintf(stderr,"fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
1589 fIndirectSymbolTable
.push_back(entry
);
1590 if ( slideable
&& curSection
->fAllLazyPointers
) {
1591 // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
1592 macho_relocation_info pblaReloc
;
1593 SectionInfo
* sectInfo
= (SectionInfo
*)ref
->getFromTarget().getSection();
1594 uint32_t sectionNum
= sectInfo
->getIndex();
1595 pblaReloc
.set_r_address(atom
->getAddress()-fOptions
.baseAddress());
1596 pblaReloc
.set_r_symbolnum(sectionNum
);
1597 pblaReloc
.set_r_pcrel(false);
1598 pblaReloc
.set_r_length(macho_relocation_info::pointer_length
);
1599 pblaReloc
.set_r_extern(false);
1600 pblaReloc
.set_r_type(GENERIC_RELOC_VANILLA
);
1601 fInternalRelocs
.push_back(pblaReloc
);
1604 else if ( ref
->requiresRuntimeFixUp(slideable
) ) {
1605 if ( ! atom
->getSegment().isContentWritable() )
1606 throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom
->getDisplayName(), atom
->getFile()->getPath(), ref
->getTarget().getDisplayName());
1607 if ( ref
->getTarget().isImportProxy() ) {
1608 // if import is to antoher dylib, this is encoded as an external relocation
1609 macho_relocation_info externalReloc
;
1610 externalReloc
.set_r_address(atom
->getAddress()+ref
->getFixUpOffset()-fOptions
.baseAddress());
1611 externalReloc
.set_r_symbolnum(this->symbolIndex(ref
->getTarget()));
1612 externalReloc
.set_r_pcrel(false);
1613 externalReloc
.set_r_length(macho_relocation_info::pointer_length
);
1614 externalReloc
.set_r_extern(true);
1615 externalReloc
.set_r_type(GENERIC_RELOC_VANILLA
);
1616 fExternalRelocs
.push_back(externalReloc
);
1619 // if this is a dylib/bundle, need fix-up encoded as an internal relocation
1620 macho_relocation_info internalReloc
;
1621 SectionInfo
* sectInfo
= (SectionInfo
*)ref
->getTarget().getSection();
1622 uint32_t sectionNum
= sectInfo
->getIndex();
1623 // special case _mh_dylib_header and friends which are not in any real section
1624 if ( (sectionNum
==0) && sectInfo
->fVirtualSection
&& (strcmp(sectInfo
->fSectionName
, "._mach_header") == 0) )
1626 internalReloc
.set_r_address(atom
->getAddress()+ref
->getFixUpOffset()-fOptions
.baseAddress());
1627 internalReloc
.set_r_symbolnum(sectionNum
);
1628 internalReloc
.set_r_pcrel(false);
1629 internalReloc
.set_r_length(macho_relocation_info::pointer_length
);
1630 internalReloc
.set_r_extern(false);
1631 internalReloc
.set_r_type(GENERIC_RELOC_VANILLA
);
1632 fInternalRelocs
.push_back(internalReloc
);
1642 class ContentWriter
: public ObjectFile::ContentWriter
1645 ContentWriter(int fd
, uint64_t fileOffset
) : fFileDescriptor(fd
), fFileOffset(fileOffset
) {}
1646 virtual void write(uint64_t atomOffset
, const void* buffer
, uint64_t size
) {
1647 ::pwrite(fFileDescriptor
, buffer
, size
, fFileOffset
+atomOffset
);
1650 int fFileDescriptor
;
1651 uint64_t fFileOffset
;
1655 void Writer::writeAtoms()
1657 const bool requireAllFixUps
= (fOptions
.outputKind() != Options::kObjectFile
);
1659 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1660 const int segCount
= segmentInfos
.size();
1661 for(int i
=0; i
< segCount
; ++i
) {
1662 SegmentInfo
* curSegment
= segmentInfos
[i
];
1663 bool isText
= ((curSegment
->fInitProtection
& VM_PROT_EXECUTE
) != 0);
1664 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1665 const int sectionCount
= sectionInfos
.size();
1666 for(int j
=0; j
< sectionCount
; ++j
) {
1667 SectionInfo
* curSection
= sectionInfos
[j
];
1668 std::vector
<ObjectFile::Atom
*>& sectionAtoms
= curSection
->fAtoms
;
1669 //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
1670 if ( ! curSection
->fAllZeroFill
) {
1671 const int atomCount
= sectionAtoms
.size();
1672 uint32_t end
= curSection
->fFileOffset
;
1673 for (int k
=0; k
< atomCount
; ++k
) {
1674 ObjectFile::Atom
* atom
= sectionAtoms
[k
];
1675 if ( !atom
->isImportProxy() ) {
1676 uint32_t offset
= curSection
->fFileOffset
+ atom
->getSectionOffset();
1677 if ( isText
&& (offset
!= end
) ) {
1678 // fill gaps with no-ops
1679 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1681 OSWriteBigInt32(&ppcNop
, 0, 0x60000000);
1682 for (uint32_t p
=end
; p
< offset
; p
+= 4)
1683 ::pwrite(fFileDescriptor
, &ppcNop
, 4, p
);
1684 #else defined(ARCH_I386)
1685 uint8_t x86Nop
= 0x90;
1686 for (uint32_t p
=end
; p
< offset
; ++p
)
1687 ::pwrite(fFileDescriptor
, &x86Nop
, 1, p
);
1690 end
= offset
+atom
->getSize();
1691 //fprintf(stderr, "writing 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
1692 ContentWriter
writer(fFileDescriptor
, offset
);
1693 atom
->writeContent(requireAllFixUps
, writer
);
1702 void Writer::partitionIntoSections()
1704 const bool oneSegmentCommand
= (fOptions
.outputKind() == Options::kObjectFile
);
1706 // for every atom, set its sectionInfo object and section offset
1707 // build up fSegmentInfos along the way
1708 ObjectFile::Section
* curSection
= NULL
;
1709 SectionInfo
* currentSectionInfo
= NULL
;
1710 SegmentInfo
* currentSegmentInfo
= NULL
;
1711 unsigned int sectionIndex
= 1;
1712 for (unsigned int i
=0; i
< fAllAtoms
->size(); ++i
) {
1713 ObjectFile::Atom
* atom
= (*fAllAtoms
)[i
];
1714 if ( atom
->getSection() != curSection
) {
1715 if ( oneSegmentCommand
) {
1716 if ( currentSegmentInfo
== NULL
) {
1717 currentSegmentInfo
= new SegmentInfo();
1718 currentSegmentInfo
->fInitProtection
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1719 currentSegmentInfo
->fMaxProtection
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1720 this->fSegmentInfos
.push_back(currentSegmentInfo
);
1722 currentSectionInfo
= new SectionInfo();
1723 strcpy(currentSectionInfo
->fSectionName
, atom
->getSectionName());
1724 strcpy(currentSectionInfo
->fSegmentName
, atom
->getSegment().getName());
1725 currentSectionInfo
->fAlignment
= atom
->getAlignment();
1726 currentSectionInfo
->fAllZeroFill
= atom
->isZeroFill();
1727 currentSectionInfo
->fVirtualSection
= ( currentSectionInfo
->fSectionName
[0] == '.');
1728 if ( !currentSectionInfo
->fVirtualSection
|| fEmitVirtualSections
)
1729 currentSectionInfo
->setIndex(sectionIndex
++);
1730 currentSegmentInfo
->fSections
.push_back(currentSectionInfo
);
1733 if ( (currentSegmentInfo
== NULL
) || (strcmp(currentSegmentInfo
->fName
, atom
->getSegment().getName()) != 0) ) {
1734 currentSegmentInfo
= new SegmentInfo();
1735 strcpy(currentSegmentInfo
->fName
, atom
->getSegment().getName());
1736 uint32_t initprot
= 0;
1737 if ( atom
->getSegment().isContentReadable() )
1738 initprot
|= VM_PROT_READ
;
1739 if ( atom
->getSegment().isContentWritable() )
1740 initprot
|= VM_PROT_WRITE
;
1741 if ( atom
->getSegment().isContentExecutable() )
1742 initprot
|= VM_PROT_EXECUTE
;
1743 currentSegmentInfo
->fInitProtection
= initprot
;
1744 if ( initprot
== 0 )
1745 currentSegmentInfo
->fMaxProtection
= 0; // pagezero should have maxprot==initprot==0
1747 currentSegmentInfo
->fMaxProtection
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1748 currentSegmentInfo
->fBaseAddress
= atom
->getSegment().getBaseAddress();
1749 currentSegmentInfo
->fFixedAddress
= atom
->getSegment().hasFixedAddress();
1750 this->fSegmentInfos
.push_back(currentSegmentInfo
);
1752 currentSectionInfo
= new SectionInfo();
1753 strcpy(currentSectionInfo
->fSectionName
, atom
->getSectionName());
1754 strcpy(currentSectionInfo
->fSegmentName
, atom
->getSegment().getName());
1755 currentSectionInfo
->fAlignment
= atom
->getAlignment();
1756 // check for -sectalign override
1757 std::vector
<Options::SectionAlignment
>& alignmentOverrides
= fOptions
.sectionAlignments();
1758 for(std::vector
<Options::SectionAlignment
>::iterator it
=alignmentOverrides
.begin(); it
!= alignmentOverrides
.end(); ++it
) {
1759 if ( (strcmp(it
->segmentName
, currentSectionInfo
->fSegmentName
) == 0) && (strcmp(it
->sectionName
, currentSectionInfo
->fSectionName
) == 0) )
1760 currentSectionInfo
->fAlignment
= it
->alignment
;
1762 currentSectionInfo
->fAllZeroFill
= atom
->isZeroFill();
1763 currentSectionInfo
->fVirtualSection
= ( currentSectionInfo
->fSectionName
[0] == '.');
1764 if ( !currentSectionInfo
->fVirtualSection
|| fEmitVirtualSections
)
1765 currentSectionInfo
->setIndex(sectionIndex
++);
1766 currentSegmentInfo
->fSections
.push_back(currentSectionInfo
);
1768 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__TEXT") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "._load_commands") == 0) ) {
1769 fLoadCommandsSection
= currentSectionInfo
;
1770 fLoadCommandsSegment
= currentSegmentInfo
;
1772 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__DATA") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "__la_symbol_ptr") == 0) )
1773 currentSectionInfo
->fAllLazyPointers
= true;
1774 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__DATA") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "__la_sym_ptr2") == 0) )
1775 currentSectionInfo
->fAllLazyPointers
= true;
1776 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__DATA") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "__nl_symbol_ptr") == 0) )
1777 currentSectionInfo
->fAllNonLazyPointers
= true;
1778 curSection
= atom
->getSection();
1780 // any non-zero fill atoms make whole section marked not-zero-fill
1781 if ( currentSectionInfo
->fAllZeroFill
&& ! atom
->isZeroFill() )
1782 currentSectionInfo
->fAllZeroFill
= false;
1783 // change section object to be Writer's SectionInfo object
1784 atom
->setSection(currentSectionInfo
);
1785 // section alignment is that of a contained atom with the greatest alignment
1786 uint8_t atomAlign
= atom
->getAlignment();
1787 if ( currentSectionInfo
->fAlignment
< atomAlign
)
1788 currentSectionInfo
->fAlignment
= atomAlign
;
1789 // calculate section offset for this atom
1790 uint64_t offset
= currentSectionInfo
->fSize
;
1791 uint64_t alignment
= 1 << atomAlign
;
1792 offset
= ( (offset
+alignment
-1) & (-alignment
) );
1793 atom
->setSectionOffset(offset
);
1794 currentSectionInfo
->fSize
= offset
+ atom
->getSize();
1795 // add atom to section vector
1796 currentSectionInfo
->fAtoms
.push_back(atom
);
1801 struct TargetAndOffset
{ ObjectFile::Atom
* atom
; uint32_t offset
; };
1802 class TargetAndOffsetComparor
1805 bool operator()(const TargetAndOffset
& left
, const TargetAndOffset
& right
) const
1807 if ( left
.atom
!= right
.atom
)
1808 return ( left
.atom
< right
.atom
);
1809 return ( left
.offset
< right
.offset
);
1814 // PowerPC can do PC relative branches as far as +/-16MB.
1815 // If a branch target is >16MB then we insert one or more
1816 // "branch islands" between the branch and its target that
1817 // allows island hoping to the target.
1819 // Branch Island Algorithm
1821 // If the __TEXT segment < 16MB, then no branch islands needed
1822 // Otherwise, every 15MB into the __TEXT segment is region is
1823 // added which can contain branch islands. Every out of range
1824 // bl instruction is checked. If it crosses a region, an island
1825 // is added to that region with the same target and the bl is
1826 // adjusted to target the island instead.
1828 // In theory, if too many islands are added to one region, it
1829 // could grow the __TEXT enough that other previously in-range
1830 // bl branches could be pushed out of range. We reduce the
1831 // probability this could happen by placing the ranges every
1832 // 15MB which means the region would have to be 1MB (256K islands)
1833 // before any branches could be pushed out of range.
1835 bool Writer::addBranchIslands()
1837 bool result
= false;
1838 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1839 // Can only possibly need branch islands if __TEXT segment > 16M
1840 if ( fLoadCommandsSegment
->fSize
> 16000000 ) {
1841 const uint32_t kBetweenRegions
= 15000000; // place regions of islands every 15MB in __text section
1842 SectionInfo
* textSection
= NULL
;
1843 for (std::vector
<SectionInfo
*>::iterator it
=fLoadCommandsSegment
->fSections
.begin(); it
!= fLoadCommandsSegment
->fSections
.end(); it
++) {
1844 if ( strcmp((*it
)->fSectionName
, "__text") == 0 )
1847 const int kIslandRegionsCount
= textSection
->fSize
/ kBetweenRegions
;
1848 typedef std::map
<TargetAndOffset
,ObjectFile::Atom
*, TargetAndOffsetComparor
> AtomToIsland
;
1849 AtomToIsland regionsMap
[kIslandRegionsCount
];
1850 std::vector
<ObjectFile::Atom
*> regionsIslands
[kIslandRegionsCount
];
1851 unsigned int islandCount
= 0;
1853 // create islands for branch references that are out of range
1854 for (std::vector
<ObjectFile::Atom
*>::iterator it
=fAllAtoms
->begin(); it
!= fAllAtoms
->end(); it
++) {
1855 ObjectFile::Atom
* atom
= *it
;
1856 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
1857 for (std::vector
<ObjectFile::Reference
*>::iterator rit
=references
.begin(); rit
!= references
.end(); rit
++) {
1858 ObjectFile::Reference
* ref
= *rit
;
1859 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupBranch24
) {
1860 ObjectFile::Atom
& target
= ref
->getTarget();
1861 int64_t srcAddr
= atom
->getAddress() + ref
->getFixUpOffset();
1862 int64_t dstAddr
= target
.getAddress() + ref
->getTargetOffset();
1863 int64_t displacement
= dstAddr
- srcAddr
;
1864 const int64_t kFifteenMegLimit
= kBetweenRegions
;
1865 if ( (displacement
> kFifteenMegLimit
) || (displacement
< (-kFifteenMegLimit
)) ) {
1866 for (int i
=0; i
< kIslandRegionsCount
; ++i
) {
1867 AtomToIsland
* region
=®ionsMap
[i
];
1868 int64_t islandRegionAddr
= kBetweenRegions
* (i
+1);
1869 if ( ((srcAddr
< islandRegionAddr
) && (dstAddr
> islandRegionAddr
))
1870 ||((dstAddr
< islandRegionAddr
) && (srcAddr
> islandRegionAddr
)) ) {
1871 TargetAndOffset islandTarget
= { &target
, ref
->getTargetOffset() };
1872 AtomToIsland::iterator pos
= region
->find(islandTarget
);
1873 if ( pos
== region
->end() ) {
1874 BranchIslandAtom
* island
= new BranchIslandAtom(*this, target
.getDisplayName(), i
, target
, ref
->getTargetOffset());
1875 (*region
)[islandTarget
] = island
;
1876 regionsIslands
[i
].push_back(island
);
1878 ref
->setTarget(*island
, 0);
1881 ref
->setTarget(*(pos
->second
), 0);
1890 // insert islands into __text section and adjust section offsets
1891 if ( islandCount
> 0 ) {
1892 std::vector
<ObjectFile::Atom
*> newAtomList
;
1893 newAtomList
.reserve(textSection
->fAtoms
.size()+islandCount
);
1894 uint64_t islandRegionAddr
= kBetweenRegions
;
1895 int regionIndex
= 0;
1896 uint64_t sectionOffset
= 0;
1897 for (std::vector
<ObjectFile::Atom
*>::iterator it
=textSection
->fAtoms
.begin(); it
!= textSection
->fAtoms
.end(); it
++) {
1898 ObjectFile::Atom
* atom
= *it
;
1899 newAtomList
.push_back(atom
);
1900 if ( atom
->getAddress() > islandRegionAddr
) {
1901 std::vector
<ObjectFile::Atom
*>* regionIslands
= ®ionsIslands
[regionIndex
];
1902 for (std::vector
<ObjectFile::Atom
*>::iterator rit
=regionIslands
->begin(); rit
!= regionIslands
->end(); rit
++) {
1903 ObjectFile::Atom
* islandAtom
= *rit
;
1904 newAtomList
.push_back(islandAtom
);
1905 islandAtom
->setSection(textSection
);
1906 uint64_t alignment
= 1 << (islandAtom
->getAlignment());
1907 sectionOffset
= ( (sectionOffset
+alignment
-1) & (-alignment
) );
1908 islandAtom
->setSectionOffset(sectionOffset
);
1909 sectionOffset
+= islandAtom
->getSize();
1912 islandRegionAddr
+= kBetweenRegions
;
1914 uint64_t alignment
= 1 << (atom
->getAlignment());
1915 sectionOffset
= ( (sectionOffset
+alignment
-1) & (-alignment
) );
1916 atom
->setSectionOffset(sectionOffset
);
1917 sectionOffset
+= atom
->getSize();
1919 textSection
->fAtoms
= newAtomList
;
1920 textSection
->fSize
= sectionOffset
;
1930 void Writer::adjustLoadCommandsAndPadding()
1932 fSegmentCommands
->computeSize();
1934 // recompute load command section offsets
1935 uint64_t offset
= 0;
1936 std::vector
<class ObjectFile::Atom
*>& loadCommandAtoms
= fLoadCommandsSection
->fAtoms
;
1937 const unsigned int atomCount
= loadCommandAtoms
.size();
1938 for (unsigned int i
=0; i
< atomCount
; ++i
) {
1939 ObjectFile::Atom
* atom
= loadCommandAtoms
[i
];
1940 uint64_t alignment
= 1 << atom
->getAlignment();
1941 offset
= ( (offset
+alignment
-1) & (-alignment
) );
1942 atom
->setSectionOffset(offset
);
1943 offset
+= atom
->getSize();
1944 fLoadCommandsSection
->fSize
= offset
;
1947 std::vector
<SectionInfo
*>& sectionInfos
= fLoadCommandsSegment
->fSections
;
1948 const int sectionCount
= sectionInfos
.size();
1949 uint64_t paddingSize
= 0;
1950 if ( fOptions
.outputKind() == Options::kDyld
) {
1951 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
1952 uint32_t totalSizeOfHeaderAndLoadCommands
= 0;
1953 for(int j
=0; j
< sectionCount
; ++j
) {
1954 SectionInfo
* curSection
= sectionInfos
[j
];
1955 totalSizeOfHeaderAndLoadCommands
+= curSection
->fSize
;
1956 if ( strcmp(curSection
->fSectionName
, fHeaderPadding
->getSectionName()) == 0 )
1959 paddingSize
= 4096 - (totalSizeOfHeaderAndLoadCommands
% 4096);
1962 // calculate max padding to keep segment size same, but all free space at end of load commands
1963 uint64_t totalSize
= 0;
1964 uint64_t worstCaseAlignmentPadding
= 0;
1965 for(int j
=0; j
< sectionCount
; ++j
) {
1966 SectionInfo
* curSection
= sectionInfos
[j
];
1967 totalSize
+= curSection
->fSize
;
1968 if ( j
!= 0 ) // don't count aligment of mach_header which is page-aligned
1969 worstCaseAlignmentPadding
+= (1 << curSection
->fAlignment
) - 1;
1971 uint64_t segmentSize
= ((totalSize
+worstCaseAlignmentPadding
+4095) & (-4096));
1972 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
1973 paddingSize
= segmentSize
- totalSize
;
1975 // if command line requires more padding than this
1976 if ( paddingSize
< fOptions
.minimumHeaderPad() ) {
1977 int extraPages
= (fOptions
.minimumHeaderPad() - paddingSize
+ 4095)/4096;
1978 paddingSize
+= extraPages
* 4096;
1982 // adjust atom size and update section size
1983 fHeaderPadding
->setSize(paddingSize
);
1984 for(int j
=0; j
< sectionCount
; ++j
) {
1985 SectionInfo
* curSection
= sectionInfos
[j
];
1986 if ( strcmp(curSection
->fSectionName
, fHeaderPadding
->getSectionName()) == 0 )
1987 curSection
->fSize
= paddingSize
;
1991 // assign file offsets and logical address to all segments
1992 void Writer::assignFileOffsets()
1994 bool haveFixedSegments
= false;
1995 uint64_t fileOffset
= 0;
1996 uint64_t nextContiguousAddress
= 0;
1997 bool baseAddressUsed
= false;
1998 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1999 const int segCount
= segmentInfos
.size();
2000 for(int i
=0; i
< segCount
; ++i
) {
2001 SegmentInfo
* curSegment
= segmentInfos
[i
];
2002 fileOffset
= (fileOffset
+4095) & (-4096);
2003 curSegment
->fFileOffset
= fileOffset
;
2004 if ( curSegment
->fFixedAddress
) {
2005 // segment has fixed address already set
2006 haveFixedSegments
= true;
2009 // segment uses next address
2010 if ( !baseAddressUsed
) {
2011 baseAddressUsed
= true;
2012 if ( fOptions
.baseAddress() != 0 )
2013 nextContiguousAddress
= fOptions
.baseAddress();
2015 curSegment
->fBaseAddress
= nextContiguousAddress
;
2017 uint64_t address
= curSegment
->fBaseAddress
;
2018 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
2019 const int sectionCount
= sectionInfos
.size();
2020 for(int j
=0; j
< sectionCount
; ++j
) {
2021 SectionInfo
* curSection
= sectionInfos
[j
];
2022 uint64_t alignment
= 1 << curSection
->fAlignment
;
2023 fileOffset
= ( (fileOffset
+alignment
-1) & (-alignment
) );
2024 address
= ( (address
+alignment
-1) & (-alignment
) );
2025 curSection
->fFileOffset
= fileOffset
;
2026 curSection
->setBaseAddress(address
);
2027 //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address);
2028 curSegment
->fSize
= curSection
->getBaseAddress() + curSection
->fSize
- curSegment
->fBaseAddress
;
2029 if ( (fOptions
.outputKind() != Options::kObjectFile
) || ! curSection
->fVirtualSection
)
2030 address
+= curSection
->fSize
;
2031 if ( !curSection
->fAllZeroFill
) {
2032 curSegment
->fFileSize
= curSegment
->fSize
;
2033 fileOffset
+= curSection
->fSize
;
2036 // page align segment size
2037 curSegment
->fFileSize
= (curSegment
->fFileSize
+4095) & (-4096);
2038 curSegment
->fSize
= (curSegment
->fSize
+4095) & (-4096);
2039 if ( curSegment
->fBaseAddress
== nextContiguousAddress
)
2040 nextContiguousAddress
= (curSegment
->fBaseAddress
+curSegment
->fSize
+4095) & (-4096);
2043 // check for segment overlaps
2044 if ( haveFixedSegments
) {
2045 for(int i
=0; i
< segCount
; ++i
) {
2046 SegmentInfo
* segment1
= segmentInfos
[i
];
2047 for(int j
=0; j
< segCount
; ++j
) {
2049 SegmentInfo
* segment2
= segmentInfos
[j
];
2050 if ( segment1
->fBaseAddress
< segment2
->fBaseAddress
) {
2051 if ( (segment1
->fBaseAddress
+segment1
->fSize
) > segment2
->fBaseAddress
)
2052 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
2053 segment1
->fName
, segment1
->fBaseAddress
, segment1
->fSize
, segment2
->fName
, segment2
->fBaseAddress
, segment2
->fSize
);
2055 else if ( segment1
->fBaseAddress
> segment2
->fBaseAddress
) {
2056 if ( (segment2
->fBaseAddress
+segment2
->fSize
) > segment1
->fBaseAddress
)
2057 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
2058 segment1
->fName
, segment1
->fBaseAddress
, segment1
->fSize
, segment2
->fName
, segment2
->fBaseAddress
, segment2
->fSize
);
2061 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
2062 segment1
->fName
, segment1
->fBaseAddress
, segment1
->fSize
, segment2
->fName
, segment2
->fBaseAddress
, segment2
->fSize
);
2070 void Writer::adjustLinkEditSections()
2072 // link edit content is always in last segment
2073 SegmentInfo
* lastSeg
= fSegmentInfos
[fSegmentInfos
.size()-1];
2074 unsigned int firstLinkEditSectionIndex
= 0;
2075 while ( strcmp(lastSeg
->fSections
[firstLinkEditSectionIndex
]->fSegmentName
, "__LINKEDIT") != 0 )
2076 ++firstLinkEditSectionIndex
;
2078 const unsigned int sectionCount
= lastSeg
->fSections
.size();
2079 uint64_t fileOffset
= lastSeg
->fSections
[firstLinkEditSectionIndex
]->fFileOffset
;
2080 uint64_t address
= lastSeg
->fSections
[firstLinkEditSectionIndex
]->getBaseAddress();
2081 for (unsigned int i
=firstLinkEditSectionIndex
; i
< sectionCount
; ++i
) {
2082 std::vector
<class ObjectFile::Atom
*>& atoms
= lastSeg
->fSections
[i
]->fAtoms
;
2083 const unsigned int atomCount
= atoms
.size();
2084 uint64_t sectionOffset
= 0;
2085 lastSeg
->fSections
[i
]->fFileOffset
= fileOffset
;
2086 lastSeg
->fSections
[i
]->setBaseAddress(address
);
2087 for (unsigned int j
=0; j
< atomCount
; ++j
) {
2088 ObjectFile::Atom
* atom
= atoms
[j
];
2089 uint64_t alignment
= 1 << atom
->getAlignment();
2090 sectionOffset
= ( (sectionOffset
+alignment
-1) & (-alignment
) );
2091 atom
->setSectionOffset(sectionOffset
);
2092 sectionOffset
+= atom
->getSize();
2094 lastSeg
->fSections
[i
]->fSize
= sectionOffset
;
2095 fileOffset
+= sectionOffset
;
2096 address
+= sectionOffset
;
2098 if ( fOptions
.outputKind() == Options::kObjectFile
) {
2099 //lastSeg->fBaseAddress = 0;
2100 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
2101 //lastSeg->fFileOffset = 0;
2102 //lastSeg->fFileSize =
2105 lastSeg
->fFileSize
= fileOffset
- lastSeg
->fFileOffset
;
2106 lastSeg
->fSize
= (address
- lastSeg
->fBaseAddress
+4095) & (-4096);
2111 ObjectFile::Atom::Scope
MachHeaderAtom::getScope() const
2113 switch ( fWriter
.fOptions
.outputKind() ) {
2114 case Options::kDynamicExecutable
:
2115 case Options::kStaticExecutable
:
2116 return ObjectFile::Atom::scopeGlobal
;
2117 case Options::kDynamicLibrary
:
2118 case Options::kDynamicBundle
:
2119 case Options::kDyld
:
2120 case Options::kObjectFile
:
2121 return ObjectFile::Atom::scopeLinkageUnit
;
2123 throw "unknown header type";
2126 bool MachHeaderAtom::dontStripName() const
2128 switch ( fWriter
.fOptions
.outputKind() ) {
2129 case Options::kDynamicExecutable
:
2130 case Options::kStaticExecutable
:
2132 case Options::kDynamicLibrary
:
2133 case Options::kDynamicBundle
:
2134 case Options::kDyld
:
2135 case Options::kObjectFile
:
2138 throw "unknown header type";
2141 const char* MachHeaderAtom::getName() const
2143 switch ( fWriter
.fOptions
.outputKind() ) {
2144 case Options::kDynamicExecutable
:
2145 case Options::kStaticExecutable
:
2146 return "__mh_execute_header";
2147 case Options::kDynamicLibrary
:
2148 return "__mh_dylib_header";
2149 case Options::kDynamicBundle
:
2150 return "__mh_bundle_header";
2151 case Options::kObjectFile
:
2153 case Options::kDyld
:
2154 return "__mh_dylinker_header";
2156 throw "unknown header type";
2159 const char* MachHeaderAtom::getDisplayName() const
2161 switch ( fWriter
.fOptions
.outputKind() ) {
2162 case Options::kDynamicExecutable
:
2163 case Options::kStaticExecutable
:
2164 case Options::kDynamicLibrary
:
2165 case Options::kDynamicBundle
:
2166 case Options::kDyld
:
2167 return this->getName();
2168 case Options::kObjectFile
:
2169 return "mach header";
2171 throw "unknown header type";
2174 uint64_t MachHeaderAtom::getSize() const
2176 return macho_header::size
;
2179 void MachHeaderAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2184 uint32_t fileType
= 0;
2185 switch ( fWriter
.fOptions
.outputKind() ) {
2186 case Options::kDynamicExecutable
:
2187 case Options::kStaticExecutable
:
2188 fileType
= MH_EXECUTE
;
2190 case Options::kDynamicLibrary
:
2191 fileType
= MH_DYLIB
;
2193 case Options::kDynamicBundle
:
2194 fileType
= MH_BUNDLE
;
2196 case Options::kObjectFile
:
2197 fileType
= MH_OBJECT
;
2199 case Options::kDyld
:
2200 fileType
= MH_DYLINKER
;
2206 if ( fWriter
.fOptions
.outputKind() == Options::kObjectFile
) {
2207 flags
= MH_SUBSECTIONS_VIA_SYMBOLS
;
2210 flags
= MH_DYLDLINK
;
2211 if ( fWriter
.fOptions
.bindAtLoad() )
2212 flags
|= MH_BINDATLOAD
;
2213 switch ( fWriter
.fOptions
.nameSpace() ) {
2214 case Options::kTwoLevelNameSpace
:
2215 flags
|= MH_TWOLEVEL
| MH_NOUNDEFS
;
2217 case Options::kFlatNameSpace
:
2219 case Options::kForceFlatNameSpace
:
2220 flags
|= MH_FORCE_FLAT
;
2223 if ( fWriter
.fHasWeakExports
)
2224 flags
|= MH_WEAK_DEFINES
;
2225 if ( fWriter
.fReferencesWeakImports
|| fWriter
.fHasWeakExports
)
2226 flags
|= MH_BINDS_TO_WEAK
;
2229 // get commands info
2230 uint32_t commandsSize
= 0;
2231 uint32_t commandsCount
= 0;
2233 std::vector
<class ObjectFile::Atom
*>& loadCommandAtoms
= fWriter
.fLoadCommandsSection
->fAtoms
;
2234 const unsigned int atomCount
= loadCommandAtoms
.size();
2235 for (unsigned int i
=0; i
< atomCount
; ++i
) {
2236 ObjectFile::Atom
* atom
= loadCommandAtoms
[i
];
2237 commandsSize
+= atom
->getSize();
2238 // segment and symbol table atoms can contain more than one load command
2239 if ( atom
== fWriter
.fSegmentCommands
)
2240 commandsCount
+= fWriter
.fSegmentCommands
->commandCount();
2241 else if ( atom
== fWriter
.fSymbolTableCommands
)
2247 // fill out mach_header
2248 mh
.set_magic(macho_header::magic_value
);
2249 mh
.set_cputype(fWriter
.fOptions
.architecture());
2250 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
2251 mh
.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL
);
2252 #elif defined(ARCH_I386)
2253 mh
.set_cpusubtype(CPU_SUBTYPE_I386_ALL
);
2255 #error unknown architecture
2257 mh
.set_filetype(fileType
);
2258 mh
.set_ncmds(commandsCount
);
2259 mh
.set_sizeofcmds(commandsSize
);
2260 mh
.set_flags(flags
);
2264 writer
.write(0, &mh
, macho_header::size
);
2268 CustomStackAtom::CustomStackAtom(Writer
& writer
)
2269 : WriterAtom(writer
, fgStackSegment
)
2271 #if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
2272 // stack grows down for these architectures
2273 fgStackSegment
.setBaseAddress(writer
.fOptions
.customStackAddr() - writer
.fOptions
.customStackSize());
2275 #error unknown architecture
2280 void SegmentLoadCommandsAtom::computeSize()
2283 std::vector
<Writer::SegmentInfo
*>& segmentInfos
= fWriter
.fSegmentInfos
;
2284 const int segCount
= segmentInfos
.size();
2285 for(int i
=0; i
< segCount
; ++i
) {
2286 size
+= macho_segment_command::size
;
2287 std::vector
<Writer::SectionInfo
*>& sectionInfos
= segmentInfos
[i
]->fSections
;
2288 const int sectionCount
= sectionInfos
.size();
2289 for(int j
=0; j
< sectionCount
; ++j
) {
2290 if ( fWriter
.fEmitVirtualSections
|| ! sectionInfos
[j
]->fVirtualSection
)
2291 size
+= macho_section::content_size
;
2295 fCommandCount
= segCount
;
2300 void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2302 uint64_t size
= this->getSize();
2303 uint8_t buffer
[size
];
2304 const bool oneSegment
=( fWriter
.fOptions
.outputKind() == Options::kObjectFile
);
2305 bzero(buffer
, fSize
);
2306 uint8_t* p
= buffer
;
2307 std::vector
<Writer::SegmentInfo
*>& segmentInfos
= fWriter
.fSegmentInfos
;
2308 const int segCount
= segmentInfos
.size();
2309 for(int i
=0; i
< segCount
; ++i
) {
2310 Writer::SegmentInfo
* segInfo
= segmentInfos
[i
];
2311 const int sectionCount
= segInfo
->fSections
.size();
2312 macho_segment_command
* cmd
= (macho_segment_command
*)p
;
2313 cmd
->set_cmd(macho_segment_command::command
);
2314 cmd
->set_segname(segInfo
->fName
);
2315 cmd
->set_vmaddr(segInfo
->fBaseAddress
);
2316 cmd
->set_vmsize(segInfo
->fSize
);
2317 cmd
->set_fileoff(segInfo
->fFileOffset
);
2318 cmd
->set_filesize(segInfo
->fFileSize
);
2319 cmd
->set_maxprot(segInfo
->fMaxProtection
);
2320 cmd
->set_initprot(segInfo
->fInitProtection
);
2321 // add sections array
2322 macho_section
* const sections
= (macho_section
*)&p
[macho_segment_command::size
];
2323 unsigned int sectionsEmitted
= 0;
2324 for (int j
=0; j
< sectionCount
; ++j
) {
2325 Writer::SectionInfo
* sectInfo
= segInfo
->fSections
[j
];
2326 if ( fWriter
.fEmitVirtualSections
|| !sectInfo
->fVirtualSection
) {
2327 macho_section
* sect
= §ions
[sectionsEmitted
++];
2329 // .o files have weird segment range
2330 if ( sectionsEmitted
== 1 ) {
2331 cmd
->set_vmaddr(sectInfo
->getBaseAddress());
2332 cmd
->set_fileoff(sectInfo
->fFileOffset
);
2333 cmd
->set_filesize(segInfo
->fFileSize
-sectInfo
->fFileOffset
);
2335 cmd
->set_vmsize(sectInfo
->getBaseAddress() + sectInfo
->fSize
);
2337 sect
->set_sectname(sectInfo
->fSectionName
);
2338 sect
->set_segname(sectInfo
->fSegmentName
);
2339 sect
->set_addr(sectInfo
->getBaseAddress());
2340 sect
->set_size(sectInfo
->fSize
);
2341 sect
->set_offset(sectInfo
->fFileOffset
);
2342 sect
->set_align(sectInfo
->fAlignment
);
2343 if ( sectInfo
->fRelocCount
!= 0 ) {
2344 sect
->set_reloff(sectInfo
->fRelocOffset
* macho_relocation_info::size
+ fWriter
.fLocalRelocationsAtom
->getFileOffset());
2345 sect
->set_nreloc(sectInfo
->fRelocCount
);
2347 if ( sectInfo
->fAllZeroFill
) {
2348 sect
->set_flags(S_ZEROFILL
);
2350 else if ( sectInfo
->fAllLazyPointers
) {
2351 sect
->set_flags(S_LAZY_SYMBOL_POINTERS
);
2352 sect
->set_reserved1(sectInfo
->fIndirectSymbolOffset
);
2354 else if ( sectInfo
->fAllNonLazyPointers
) {
2355 sect
->set_flags(S_NON_LAZY_SYMBOL_POINTERS
);
2356 sect
->set_reserved1(sectInfo
->fIndirectSymbolOffset
);
2358 else if ( (strcmp(sectInfo
->fSectionName
, "__mod_init_func") == 0) && (strcmp(sectInfo
->fSegmentName
, "__DATA") == 0) ) {
2359 sect
->set_flags(S_MOD_INIT_FUNC_POINTERS
);
2361 else if ( (strcmp(sectInfo
->fSectionName
, "__mod_term_func") == 0) && (strcmp(sectInfo
->fSegmentName
, "__DATA") == 0) ) {
2362 sect
->set_flags(S_MOD_TERM_FUNC_POINTERS
);
2364 else if ( (strcmp(sectInfo
->fSectionName
, "__textcoal_nt") == 0) && (strcmp(sectInfo
->fSegmentName
, "__TEXT") == 0) ) {
2365 sect
->set_flags(S_COALESCED
);
2369 p
= &p
[macho_segment_command::size
+ sectionsEmitted
*macho_section::content_size
];
2370 cmd
->set_cmdsize(macho_segment_command::size
+ sectionsEmitted
*macho_section::content_size
);
2371 cmd
->set_nsects(sectionsEmitted
);
2373 writer
.write(0, buffer
, size
);
2377 SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer
& writer
)
2378 : WriterAtom(writer
, fgTextSegment
)
2380 bzero(&fSymbolTable
, macho_symtab_command::size
);
2381 bzero(&fDynamicSymbolTable
, macho_dysymtab_command::size
);
2382 writer
.fSymbolTableCommands
= this;
2385 uint64_t SymbolTableLoadCommandsAtom::getSize() const
2387 return macho_symtab_command::size
+ macho_dysymtab_command::size
;
2390 void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2392 // build LC_DYSYMTAB command
2393 macho_symtab_command symbolTableCmd
;
2394 bzero(&symbolTableCmd
, macho_symtab_command::size
);
2395 symbolTableCmd
.set_cmd(LC_SYMTAB
);
2396 symbolTableCmd
.set_cmdsize(macho_symtab_command::size
);
2397 symbolTableCmd
.set_nsyms(fWriter
.fSymbolTableCount
);
2398 symbolTableCmd
.set_symoff(fWriter
.fSymbolTableAtom
->getFileOffset());
2399 symbolTableCmd
.set_stroff(fWriter
.fStringsAtom
->getFileOffset());
2400 symbolTableCmd
.set_strsize(fWriter
.fStringsAtom
->getSize());
2401 writer
.write(0, &symbolTableCmd
, macho_symtab_command::size
);
2403 // build LC_DYSYMTAB command
2404 macho_dysymtab_command dynamicSymbolTableCmd
;
2405 bzero(&dynamicSymbolTableCmd
, macho_dysymtab_command::size
);
2406 dynamicSymbolTableCmd
.set_cmd(LC_DYSYMTAB
);
2407 dynamicSymbolTableCmd
.set_cmdsize(macho_dysymtab_command::size
);
2408 dynamicSymbolTableCmd
.set_ilocalsym(fWriter
.fSymbolTableStabsStartIndex
);
2409 dynamicSymbolTableCmd
.set_nlocalsym(fWriter
.fSymbolTableStabsCount
+ fWriter
.fSymbolTableLocalCount
);
2410 dynamicSymbolTableCmd
.set_iextdefsym(fWriter
.fSymbolTableExportStartIndex
);
2411 dynamicSymbolTableCmd
.set_nextdefsym(fWriter
.fSymbolTableExportCount
);
2412 dynamicSymbolTableCmd
.set_iundefsym(fWriter
.fSymbolTableImportStartIndex
);
2413 dynamicSymbolTableCmd
.set_nundefsym(fWriter
.fSymbolTableImportCount
);
2414 dynamicSymbolTableCmd
.set_indirectsymoff(fWriter
.fIndirectTableAtom
->getFileOffset());
2415 dynamicSymbolTableCmd
.set_nindirectsyms(fWriter
.fIndirectSymbolTable
.size());
2416 if ( fWriter
.fOptions
.outputKind() != Options::kObjectFile
) {
2417 dynamicSymbolTableCmd
.set_extreloff((fWriter
.fExternalRelocs
.size()==0) ? 0 : fWriter
.fExternalRelocationsAtom
->getFileOffset());
2418 dynamicSymbolTableCmd
.set_nextrel(fWriter
.fExternalRelocs
.size());
2419 dynamicSymbolTableCmd
.set_locreloff((fWriter
.fInternalRelocs
.size()==0) ? 0 : fWriter
.fLocalRelocationsAtom
->getFileOffset());
2420 dynamicSymbolTableCmd
.set_nlocrel(fWriter
.fInternalRelocs
.size());
2422 writer
.write(macho_symtab_command::size
, &dynamicSymbolTableCmd
, macho_dysymtab_command::size
);
2425 uint64_t DyldLoadCommandsAtom::getSize() const
2427 uint32_t len
= macho_dylinker_command::name_offset
+ strlen("/usr/lib/dyld");
2428 len
= (len
+7) & (-8); // 8-byte align
2432 void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2434 uint64_t size
= this->getSize();
2435 uint8_t buffer
[size
];
2436 bzero(buffer
, size
);
2437 macho_dylinker_command
* cmd
= (macho_dylinker_command
*)buffer
;
2438 if ( fWriter
.fOptions
.outputKind() == Options::kDyld
)
2439 cmd
->set_cmd(LC_ID_DYLINKER
);
2441 cmd
->set_cmd(LC_LOAD_DYLINKER
);
2442 cmd
->set_cmdsize(this->getSize());
2443 cmd
->set_name_offset();
2444 strcpy((char*)&buffer
[macho_dylinker_command::name_offset
], "/usr/lib/dyld");
2445 writer
.write(0, buffer
, size
);
2450 uint64_t DylibLoadCommandsAtom::getSize() const
2452 const char* path
= fInfo
.reader
->getInstallPath();
2453 if ( fInfo
.options
.fInstallPathOverride
!= NULL
)
2454 path
= fInfo
.options
.fInstallPathOverride
;
2455 uint32_t len
= macho_dylib_command::name_offset
+ strlen(path
);
2456 len
= (len
+7) & (-8); // 8-byte align
2460 void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2462 uint64_t size
= this->getSize();
2463 uint8_t buffer
[size
];
2464 bzero(buffer
, size
);
2465 const char* path
= fInfo
.reader
->getInstallPath();
2466 if ( fInfo
.options
.fInstallPathOverride
!= NULL
)
2467 path
= fInfo
.options
.fInstallPathOverride
;
2468 macho_dylib_command
* cmd
= (macho_dylib_command
*)buffer
;
2469 if ( fInfo
.options
.fWeakImport
)
2470 cmd
->set_cmd(LC_LOAD_WEAK_DYLIB
);
2472 cmd
->set_cmd(LC_LOAD_DYLIB
);
2473 cmd
->set_cmdsize(this->getSize());
2474 cmd
->set_timestamp(fInfo
.reader
->getTimestamp());
2475 cmd
->set_current_version(fInfo
.reader
->getCurrentVersion());
2476 cmd
->set_compatibility_version(fInfo
.reader
->getCompatibilityVersion());
2477 cmd
->set_name_offset();
2478 strcpy((char*)&buffer
[macho_dylib_command::name_offset
], path
);
2479 writer
.write(0, buffer
, size
);
2484 uint64_t DylibIDLoadCommandsAtom::getSize() const
2486 uint32_t len
= macho_dylib_command::name_offset
+ strlen(fWriter
.fOptions
.installPath());
2487 len
= (len
+7) & (-8); // 8-byte align
2491 void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2493 struct timeval currentTime
= { 0 , 0 };
2494 gettimeofday(¤tTime
, NULL
);
2495 time_t timestamp
= currentTime
.tv_sec
;
2496 uint64_t size
= this->getSize();
2497 uint8_t buffer
[size
];
2498 bzero(buffer
, size
);
2499 macho_dylib_command
* cmd
= (macho_dylib_command
*)buffer
;
2500 cmd
->set_cmd(LC_ID_DYLIB
);
2501 cmd
->set_cmdsize(this->getSize());
2502 cmd
->set_name_offset();
2503 cmd
->set_timestamp(timestamp
);
2504 cmd
->set_current_version(fWriter
.fOptions
.currentVersion());
2505 cmd
->set_compatibility_version(fWriter
.fOptions
.compatibilityVersion());
2506 strcpy((char*)&buffer
[macho_dylib_command::name_offset
], fWriter
.fOptions
.installPath());
2507 writer
.write(0, buffer
, size
);
2511 uint64_t RoutinesLoadCommandsAtom::getSize() const
2513 return macho_routines_command::size
;
2516 void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2518 uint64_t initAddr
= fWriter
.getAtomLoadAddress(fWriter
.fEntryPoint
);
2519 uint8_t buffer
[macho_routines_command::size
];
2520 bzero(buffer
, macho_routines_command::size
);
2521 macho_routines_command
* cmd
= (macho_routines_command
*)buffer
;
2522 cmd
->set_cmd(macho_routines_command::command
);
2523 cmd
->set_cmdsize(this->getSize());
2524 cmd
->set_init_address(initAddr
);
2525 writer
.write(0, buffer
, macho_routines_command::size
);
2529 uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
2531 uint32_t len
= macho_sub_umbrella_command::name_offset
+ strlen(fName
);
2532 len
= (len
+7) & (-8); // 8-byte align
2536 void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2538 uint64_t size
= this->getSize();
2539 uint8_t buffer
[size
];
2540 bzero(buffer
, size
);
2541 macho_sub_umbrella_command
* cmd
= (macho_sub_umbrella_command
*)buffer
;
2542 cmd
->set_cmd(LC_SUB_UMBRELLA
);
2543 cmd
->set_cmdsize(this->getSize());
2544 cmd
->set_name_offset();
2545 strcpy((char*)&buffer
[macho_sub_umbrella_command::name_offset
], fName
);
2546 writer
.write(0, buffer
, size
);
2550 uint64_t SubLibraryLoadCommandsAtom::getSize() const
2552 uint32_t len
= macho_sub_library_command::name_offset
+ fNameLength
+ 1;
2553 len
= (len
+7) & (-8); // 8-byte align
2557 void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2559 uint64_t size
= this->getSize();
2560 uint8_t buffer
[size
];
2561 bzero(buffer
, size
);
2562 macho_sub_library_command
* cmd
= (macho_sub_library_command
*)buffer
;
2563 cmd
->set_cmd(LC_SUB_LIBRARY
);
2564 cmd
->set_cmdsize(this->getSize());
2565 cmd
->set_name_offset();
2566 strncpy((char*)&buffer
[macho_sub_library_command::name_offset
], fNameStart
, fNameLength
);
2567 buffer
[macho_sub_library_command::name_offset
+fNameLength
] = '\0';
2568 writer
.write(0, buffer
, size
);
2571 uint64_t UmbrellaLoadCommandsAtom::getSize() const
2573 uint32_t len
= macho_sub_framework_command::name_offset
+ strlen(fName
);
2574 len
= (len
+7) & (-8); // 8-byte align
2578 void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2580 uint64_t size
= this->getSize();
2581 uint8_t buffer
[size
];
2582 bzero(buffer
, size
);
2583 macho_sub_framework_command
* cmd
= (macho_sub_framework_command
*)buffer
;
2584 cmd
->set_cmd(LC_SUB_FRAMEWORK
);
2585 cmd
->set_cmdsize(this->getSize());
2586 cmd
->set_name_offset();
2587 strcpy((char*)&buffer
[macho_sub_framework_command::name_offset
], fName
);
2588 writer
.write(0, buffer
, size
);
2591 uint64_t ThreadsLoadCommandsAtom::getSize() const
2593 #if defined(ARCH_PPC)
2594 uint32_t stateSize
= 40; // PPC_THREAD_STATE_COUNT;
2595 #elif defined(ARCH_PPC64)
2596 uint32_t stateSize
= 76; // PPC_THREAD_STATE64_COUNT;
2597 #elif defined(ARCH_I386)
2598 uint32_t stateSize
= 16; // i386_THREAD_STATE_COUNT;
2600 #error unknown architecture
2602 return macho_thread_command::size
+ stateSize
*4;
2605 void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2607 uint64_t size
= this->getSize();
2608 uint8_t buffer
[size
];
2609 uint64_t start
= fWriter
.getAtomLoadAddress(fWriter
.fEntryPoint
);
2610 bzero(buffer
, size
);
2611 macho_thread_command
* cmd
= (macho_thread_command
*)buffer
;
2612 cmd
->set_cmd(LC_UNIXTHREAD
);
2613 cmd
->set_cmdsize(size
);
2614 #if defined(ARCH_PPC)
2615 cmd
->set_flavor(1); // PPC_THREAD_STATE
2616 cmd
->set_count(40); // PPC_THREAD_STATE_COUNT;
2617 cmd
->set_threadState32(0, start
);
2618 if ( fWriter
.fOptions
.hasCustomStack() )
2619 cmd
->set_threadState32(3, fWriter
.fOptions
.customStackAddr()); // r1
2620 #elif defined(ARCH_PPC64)
2621 cmd
->set_flavor(5); // PPC_THREAD_STATE64
2622 cmd
->set_count(76); // PPC_THREAD_STATE64_COUNT;
2623 cmd
->set_threadState64(0, start
);
2624 if ( fWriter
.fOptions
.hasCustomStack() )
2625 cmd
->set_threadState64(6, fWriter
.fOptions
.customStackAddr()); // r1
2626 #elif defined(ARCH_I386)
2627 cmd
->set_flavor(0xFFFFFFFF); // i386_THREAD_STATE
2628 cmd
->set_count(16); // i386_THREAD_STATE_COUNT;
2629 cmd
->set_threadState32(0, start
);
2630 if ( fWriter
.fOptions
.hasCustomStack() )
2631 cmd
->set_threadState32(15, fWriter
.fOptions
.customStackAddr()); // uesp
2633 #error unknown architecture
2635 writer
.write(0, buffer
, size
);
2640 uint64_t LoadCommandsPaddingAtom::getSize() const
2645 void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2647 uint8_t buffer
[fSize
];
2648 bzero(buffer
, fSize
);
2649 writer
.write(0, buffer
, fSize
);
2653 uint64_t LinkEditAtom::getFileOffset() const
2655 return ((Writer::SectionInfo
*)this->getSection())->fFileOffset
+ this->getSectionOffset();
2659 uint64_t LocalRelocationsLinkEditAtom::getSize() const
2661 return fWriter
.fInternalRelocs
.size() * macho_relocation_info::size
;
2664 void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2666 writer
.write(0, &fWriter
.fInternalRelocs
[0], this->getSize());
2671 uint64_t SymbolTableLinkEditAtom::getSize() const
2673 return fWriter
.fSymbolTableCount
* macho_nlist::size
;
2676 void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2678 writer
.write(0, fWriter
.fSymbolTable
, this->getSize());
2681 uint64_t ExternalRelocationsLinkEditAtom::getSize() const
2683 return fWriter
.fExternalRelocs
.size() * macho_relocation_info::size
;
2686 void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2688 writer
.write(0, &fWriter
.fExternalRelocs
[0], this->getSize());
2693 uint64_t IndirectTableLinkEditAtom::getSize() const
2695 return fWriter
.fIndirectSymbolTable
.size() * sizeof(uint32_t);
2698 void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2700 uint64_t size
= this->getSize();
2701 uint8_t buffer
[size
];
2702 bzero(buffer
, size
);
2703 const uint32_t indirectTableSize
= fWriter
.fIndirectSymbolTable
.size();
2704 uint32_t* indirectTable
= (uint32_t*)buffer
;
2705 for (uint32_t i
=0; i
< indirectTableSize
; ++i
) {
2706 Writer::IndirectEntry
& entry
= fWriter
.fIndirectSymbolTable
[i
];
2707 if ( entry
.indirectIndex
< indirectTableSize
) {
2708 ENDIAN_WRITE32(indirectTable
[entry
.indirectIndex
], entry
.symbolIndex
);
2711 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize
, entry
.indirectIndex
);
2714 writer
.write(0, buffer
, size
);
2719 StringsLinkEditAtom::StringsLinkEditAtom(Writer
& writer
)
2720 : LinkEditAtom(writer
), fCurrentBuffer(NULL
), fCurrentBufferUsed(0)
2722 fCurrentBuffer
= new char[kBufferSize
];
2723 // burn first byte of string pool (so zero is never a valid string offset)
2724 fCurrentBuffer
[fCurrentBufferUsed
++] = ' ';
2725 // make offset 1 always point to an empty string
2726 fCurrentBuffer
[fCurrentBufferUsed
++] = '\0';
2729 uint64_t StringsLinkEditAtom::getSize() const
2731 return kBufferSize
* fFullBuffers
.size() + fCurrentBufferUsed
;
2734 void StringsLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2736 uint64_t offset
= 0;
2737 for (unsigned int i
=0; i
< fFullBuffers
.size(); ++i
) {
2738 writer
.write(offset
, fFullBuffers
[i
], kBufferSize
);
2739 offset
+= kBufferSize
;
2741 writer
.write(offset
, fCurrentBuffer
, fCurrentBufferUsed
);
2744 int32_t StringsLinkEditAtom::add(const char* name
)
2746 int lenNeeded
= strlen(name
)+1;
2747 while ( lenNeeded
+ fCurrentBufferUsed
>= kBufferSize
) {
2748 // first part of string fits in current buffer
2749 int firstLen
= kBufferSize
- fCurrentBufferUsed
;
2750 memcpy(&fCurrentBuffer
[fCurrentBufferUsed
], name
, firstLen
);
2751 // alloc next buffer
2752 fFullBuffers
.push_back(fCurrentBuffer
);
2753 fCurrentBuffer
= new char[kBufferSize
];
2754 fCurrentBufferUsed
= 0;
2755 // advance name to second part
2757 lenNeeded
-= firstLen
;
2759 //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed);
2760 // string all fits in current buffer
2761 strcpy(&fCurrentBuffer
[fCurrentBufferUsed
], name
);
2762 int32_t offset
= kBufferSize
* fFullBuffers
.size() + fCurrentBufferUsed
;
2763 fCurrentBufferUsed
+= lenNeeded
;
2767 // returns the index of an empty string
2768 int32_t StringsLinkEditAtom::emptyString()
2773 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
2774 BranchIslandAtom::BranchIslandAtom(Writer
& writer
, const char* name
, int islandRegion
, ObjectFile::Atom
& target
, uint32_t targetOffset
)
2775 : WriterAtom(writer
, fgTextSegment
), fTarget(target
), fTargetOffset(targetOffset
)
2777 char* buf
= new char[strlen(name
)+32];
2778 if ( targetOffset
== 0 ) {
2779 if ( islandRegion
== 0 )
2780 sprintf(buf
, "%s$island", name
);
2782 sprintf(buf
, "%s$island_%d", name
, islandRegion
);
2785 sprintf(buf
, "%s_plus_%d$island_%d", name
, targetOffset
, islandRegion
);
2791 void BranchIslandAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2793 int64_t displacement
= fTarget
.getAddress() + fTargetOffset
- this->getAddress();
2794 uint8_t instruction
[4];
2795 int32_t branchInstruction
= 0x48000000 | ((uint32_t)displacement
& 0x03FFFFFC);
2796 OSWriteBigInt32(&instruction
, 0, branchInstruction
);
2797 writer
.write(0, &instruction
, 4);