2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 namespace ExecutableFileMachO
{
28 class Writer
: public ExecutableFile::Writer
31 Writer(const char* path
, Options
& options
, std::vector
<ExecutableFile::DyLibUsed
>& dynamicLibraries
);
34 virtual const char* getPath();
35 virtual std::vector
<class ObjectFile::Atom
*>& getAtoms();
36 virtual std::vector
<class ObjectFile::Atom
*>* getJustInTimeAtomsFor(const char* name
);
37 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo();
39 virtual class ObjectFile::Atom
* getUndefinedProxyAtom(const char* name
);
40 virtual void write(std::vector
<class ObjectFile::Atom
*>& atoms
, class ObjectFile::Atom
* entryPointAtom
);
43 void assignFileOffsets();
44 void partitionIntoSections();
45 void adjustLoadCommandsAndPadding();
46 void createDynamicLinkerCommand();
47 void createDylibCommands();
50 void collectExportedAndImportedAndLocalAtoms();
51 void setNlistRange(std::vector
<class ObjectFile::Atom
*>& atoms
, uint32_t startIndex
, uint32_t count
);
52 void buildSymbolTable();
53 void setExportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
);
54 void setImportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
);
55 void setLocalNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
);
56 uint64_t getAtomLoadAddress(const ObjectFile::Atom
* atom
);
57 uint8_t ordinalForLibrary(ObjectFile::Reader
* file
);
58 bool shouldExport(ObjectFile::Atom
& atom
);
60 void adjustLinkEditSections();
61 void buildObjectFileFixups();
62 void buildExecutableFixups();
63 uint32_t symbolIndex(ObjectFile::Atom
& atom
);
64 uint32_t addRelocs(ObjectFile::Atom
* atom
, ObjectFile::Reference
* ref
);
65 unsigned int collectStabs();
66 macho_uintptr_t
valueForStab(const ObjectFile::StabsInfo
& stab
, const ObjectFile::Atom
* atom
);
67 void addStabs(uint32_t startIndex
, uint32_t count
);
70 class SectionInfo
: public ObjectFile::Section
{
73 void setIndex(unsigned int index
) { fIndex
=index
; }
74 std::vector
<ObjectFile::Atom
*> fAtoms
;
75 char fSegmentName
[20];
76 char fSectionName
[20];
80 uint32_t fRelocOffset
;
81 uint32_t fIndirectSymbolOffset
;
83 bool fAllLazyPointers
;
84 bool fAllNonLazyPointers
;
93 std::vector
<class SectionInfo
*> fSections
;
95 uint32_t fInitProtection
;
96 uint32_t fMaxProtection
;
99 uint64_t fBaseAddress
;
104 struct DirectLibrary
{
105 class ObjectFile::Reader
* fLibrary
;
110 struct IndirectEntry
{
111 uint32_t indirectIndex
;
112 uint32_t symbolIndex
;
116 ObjectFile::Atom
* fAtom
;
117 ObjectFile::Reader
* fReader
;
118 unsigned int fOrderInReader
;
119 std::vector
<ObjectFile::StabsInfo
>* fStabs
;
122 static bool stabChunkCompare(const StabChunks
& lhs
, const StabChunks
& rhs
);
124 friend class WriterAtom
;
125 friend class PageZeroAtom
;
126 friend class CustomStackAtom
;
127 friend class MachHeaderAtom
;
128 friend class SegmentLoadCommandsAtom
;
129 friend class SymbolTableLoadCommandsAtom
;
130 friend class ThreadsLoadCommandsAtom
;
131 friend class DylibIDLoadCommandsAtom
;
132 friend class RoutinesLoadCommandsAtom
;
133 friend class DyldLoadCommandsAtom
;
134 friend class LinkEditAtom
;
135 friend class LocalRelocationsLinkEditAtom
;
136 friend class ExternalRelocationsLinkEditAtom
;
137 friend class SymbolTableLinkEditAtom
;
138 friend class IndirectTableLinkEditAtom
;
139 friend class StringsLinkEditAtom
;
141 const char* fFilePath
;
144 std::vector
<class ObjectFile::Atom
*>* fAllAtoms
;
145 class SectionInfo
* fLoadCommandsSection
;
146 class SegmentInfo
* fLoadCommandsSegment
;
147 class SegmentLoadCommandsAtom
* fSegmentCommands
;
148 class SymbolTableLoadCommandsAtom
* fSymbolTableCommands
;
149 class LoadCommandsPaddingAtom
* fHeaderPadding
;
150 std::vector
<class ObjectFile::Atom
*> fWriterSynthesizedAtoms
;
151 std::vector
<SegmentInfo
*> fSegmentInfos
;
152 class ObjectFile::Atom
* fEntryPoint
;
153 std::vector
<DirectLibrary
> fDirectLibraries
;
154 std::map
<class ObjectFile::Reader
*, uint32_t> fLibraryToOrdinal
;
155 std::vector
<StabChunks
> fStabChunks
;
156 std::vector
<class ObjectFile::Atom
*> fExportedAtoms
;
157 std::vector
<class ObjectFile::Atom
*> fImportedAtoms
;
158 std::vector
<class ObjectFile::Atom
*> fLocalSymbolAtoms
;
159 LocalRelocationsLinkEditAtom
* fLocalRelocationsAtom
;
160 ExternalRelocationsLinkEditAtom
* fExternalRelocationsAtom
;
161 SymbolTableLinkEditAtom
* fSymbolTableAtom
;
162 IndirectTableLinkEditAtom
* fIndirectTableAtom
;
163 StringsLinkEditAtom
* fStringsAtom
;
164 macho_nlist
* fSymbolTable
;
166 //uint32_t fStringPoolUsed;
167 //uint32_t fStringPoolSize;
168 std::vector
<macho_relocation_info
> fInternalRelocs
;
169 std::vector
<macho_relocation_info
> fExternalRelocs
;
170 std::vector
<IndirectEntry
> fIndirectSymbolTable
;
171 uint32_t fSymbolTableCount
;
172 uint32_t fSymbolTableStabsCount
;
173 uint32_t fSymbolTableStabsStartIndex
;
174 uint32_t fSymbolTableLocalCount
;
175 uint32_t fSymbolTableLocalStartIndex
;
176 uint32_t fSymbolTableExportCount
;
177 uint32_t fSymbolTableExportStartIndex
;
178 uint32_t fSymbolTableImportCount
;
179 uint32_t fSymbolTableImportStartIndex
;
180 bool fEmitVirtualSections
;
181 bool fHasWeakExports
;
182 bool fReferencesWeakImports
;
186 class WriterAtom
: public ObjectFile::Atom
191 enum Kind
{ zeropage
, machHeaderApp
, machHeaderDylib
, machHeaderBundle
, machHeaderObject
, loadCommands
, undefinedProxy
};
192 WriterAtom(Writer
& writer
, class WriterAtom::Segment
& segment
) : fWriter(writer
), fSegment(segment
) {}
194 virtual ObjectFile::Reader
* getFile() const { return &fWriter
; }
195 virtual const char* getName() const { return NULL
; }
196 virtual const char* getDisplayName() const { return this->getName(); }
197 virtual Scope
getScope() const { return ObjectFile::Atom::scopeTranslationUnit
; }
198 virtual bool isTentativeDefinition() const { return false; }
199 virtual bool isWeakDefinition() const { return false; }
200 virtual bool isCoalesableByName() const { return false; }
201 virtual bool isCoalesableByValue() const { return false; }
202 virtual bool isZeroFill() const { return false; }
203 virtual bool dontDeadStrip() const { return true; }
204 virtual bool dontStripName() const { return false; }
205 virtual bool isImportProxy() const { return false; }
206 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return fgEmptyReferenceList
; }
207 virtual bool mustRemainInSection() const { return true; }
208 virtual ObjectFile::Segment
& getSegment() const { return fSegment
; }
209 virtual bool requiresFollowOnAtom() const { return false; }
210 virtual ObjectFile::Atom
& getFollowOnAtom() const { return *((ObjectFile::Atom
*)NULL
); }
211 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo() const { return NULL
; }
212 virtual uint8_t getAlignment() const { return 2; }
213 virtual WeakImportSetting
getImportWeakness() const { return Atom::kWeakUnset
; }
214 virtual void copyRawContent(uint8_t buffer
[]) const { throw "don't use copyRawContent"; }
215 virtual void setScope(Scope
) { }
216 virtual void setImportWeakness(bool weakImport
) { }
220 virtual ~WriterAtom() {}
222 class Segment
: public ObjectFile::Segment
225 Segment(const char* name
, bool readable
, bool writable
, bool executable
)
226 : fName(name
), fReadable(readable
), fWritable(writable
), fExecutable(executable
) {}
227 virtual const char* getName() const { return fName
; }
228 virtual bool isContentReadable() const { return fReadable
; }
229 virtual bool isContentWritable() const { return fWritable
; }
230 virtual bool isContentExecutable() const { return fExecutable
; }
233 const bool fReadable
;
234 const bool fWritable
;
235 const bool fExecutable
;
238 static std::vector
<ObjectFile::Reference
*> fgEmptyReferenceList
;
239 static Segment fgTextSegment
;
240 static Segment fgPageZeroSegment
;
241 static Segment fgLinkEditSegment
;
242 static Segment fgStackSegment
;
250 WriterAtom::Segment
WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false);
251 WriterAtom::Segment
WriterAtom::fgTextSegment("__TEXT", true, false, true);
252 WriterAtom::Segment
WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false);
253 WriterAtom::Segment
WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false);
254 std::vector
<ObjectFile::Reference
*> WriterAtom::fgEmptyReferenceList
;
256 class PageZeroAtom
: public WriterAtom
259 PageZeroAtom(Writer
& writer
) : WriterAtom(writer
, fgPageZeroSegment
) {}
260 virtual const char* getDisplayName() const { return "page zero content"; }
261 virtual bool isZeroFill() const { return true; }
262 virtual uint64_t getSize() const { return fWriter
.fOptions
.zeroPageSize(); }
263 virtual const char* getSectionName() const { return "._zeropage"; }
264 virtual uint8_t getAlignment() const { return 12; }
265 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
268 class MachHeaderAtom
: public WriterAtom
271 MachHeaderAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
272 virtual const char* getName() const;
273 virtual const char* getDisplayName() const;
274 virtual Scope
getScope() const;
275 virtual bool dontStripName() const;
276 virtual uint64_t getSize() const;
277 virtual uint8_t getAlignment() const { return 12; }
278 virtual const char* getSectionName() const { return "._mach_header"; }
279 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
282 class CustomStackAtom
: public WriterAtom
285 CustomStackAtom(Writer
& writer
);
286 virtual const char* getDisplayName() const { return "custom stack content"; }
287 virtual bool isZeroFill() const { return true; }
288 virtual uint64_t getSize() const { return fWriter
.fOptions
.customStackSize(); }
289 virtual const char* getSectionName() const { return "._stack"; }
290 virtual uint8_t getAlignment() const { return 12; }
291 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
294 class SegmentLoadCommandsAtom
: public WriterAtom
297 SegmentLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
), fCommandCount(0), fSize(0) { writer
.fSegmentCommands
= this; }
298 virtual const char* getDisplayName() const { return "segment load commands"; }
299 virtual uint64_t getSize() const { return fSize
; }
300 virtual uint8_t getAlignment() const { return 2; }
301 virtual const char* getSectionName() const { return "._load_commands"; }
302 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
306 unsigned int commandCount() { return fCommandCount
; }
307 void assignFileOffsets();
309 unsigned int fCommandCount
;
313 class SymbolTableLoadCommandsAtom
: public WriterAtom
316 SymbolTableLoadCommandsAtom(Writer
&);
317 virtual const char* getDisplayName() const { return "symbol table load commands"; }
318 virtual uint64_t getSize() const;
319 virtual uint8_t getAlignment() const { return 2; }
320 virtual const char* getSectionName() const { return "._load_commands"; }
321 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
324 macho_symtab_command fSymbolTable
;
325 macho_dysymtab_command fDynamicSymbolTable
;
328 class ThreadsLoadCommandsAtom
: public WriterAtom
331 ThreadsLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
332 virtual const char* getDisplayName() const { return "thread load commands"; }
333 virtual uint64_t getSize() const;
334 virtual uint8_t getAlignment() const { return 2; }
335 virtual const char* getSectionName() const { return "._load_commands"; }
336 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
339 uint32_t fBufferSize
;
342 class DyldLoadCommandsAtom
: public WriterAtom
345 DyldLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
346 virtual const char* getDisplayName() const { return "dyld load command"; }
347 virtual uint64_t getSize() const;
348 virtual uint8_t getAlignment() const { return 2; }
349 virtual const char* getSectionName() const { return "._load_commands"; }
350 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
353 class DylibLoadCommandsAtom
: public WriterAtom
356 DylibLoadCommandsAtom(Writer
& writer
, ExecutableFile::DyLibUsed
& info
) : WriterAtom(writer
, fgTextSegment
), fInfo(info
) {}
357 virtual const char* getDisplayName() const { return "dylib load command"; }
358 virtual uint64_t getSize() const;
359 virtual uint8_t getAlignment() const { return 2; }
360 virtual const char* getSectionName() const { return "._load_commands"; }
361 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
363 ExecutableFile::DyLibUsed
& fInfo
;
366 class DylibIDLoadCommandsAtom
: public WriterAtom
369 DylibIDLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
370 virtual const char* getDisplayName() const { return "dylib ID load command"; }
371 virtual uint64_t getSize() const;
372 virtual uint8_t getAlignment() const { return 2; }
373 virtual const char* getSectionName() const { return "._load_commands"; }
374 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
377 class RoutinesLoadCommandsAtom
: public WriterAtom
380 RoutinesLoadCommandsAtom(Writer
& writer
) : WriterAtom(writer
, fgTextSegment
) {}
381 virtual const char* getDisplayName() const { return "routines load command"; }
382 virtual uint64_t getSize() const;
383 virtual uint8_t getAlignment() const { return 2; }
384 virtual const char* getSectionName() const { return "._load_commands"; }
385 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
388 class SubUmbrellaLoadCommandsAtom
: public WriterAtom
391 SubUmbrellaLoadCommandsAtom(Writer
& writer
, const char* name
) : WriterAtom(writer
, fgTextSegment
), fName(name
) {}
392 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
393 virtual uint64_t getSize() const;
394 virtual uint8_t getAlignment() const { return 2; }
395 virtual const char* getSectionName() const { return "._load_commands"; }
396 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
401 class SubLibraryLoadCommandsAtom
: public WriterAtom
404 SubLibraryLoadCommandsAtom(Writer
& writer
, const char* nameStart
, int nameLen
)
405 : WriterAtom(writer
, fgTextSegment
), fNameStart(nameStart
), fNameLength(nameLen
) {}
406 virtual const char* getDisplayName() const { return "sub-library load command"; }
407 virtual uint64_t getSize() const;
408 virtual uint8_t getAlignment() const { return 2; }
409 virtual const char* getSectionName() const { return "._load_commands"; }
410 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
412 const char* fNameStart
;
416 class UmbrellaLoadCommandsAtom
: public WriterAtom
419 UmbrellaLoadCommandsAtom(Writer
& writer
, const char* name
)
420 : WriterAtom(writer
, fgTextSegment
), fName(name
) {}
421 virtual const char* getDisplayName() const { return "umbrella load command"; }
422 virtual uint64_t getSize() const;
423 virtual uint8_t getAlignment() const { return 2; }
424 virtual const char* getSectionName() const { return "._load_commands"; }
425 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
430 class LoadCommandsPaddingAtom
: public WriterAtom
433 LoadCommandsPaddingAtom(Writer
& writer
)
434 : WriterAtom(writer
, fgTextSegment
), fSize(0) {}
435 virtual const char* getDisplayName() const { return "header padding"; }
436 virtual uint64_t getSize() const;
437 virtual uint8_t getAlignment() const { return 2; }
438 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
439 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
441 void setSize(uint64_t newSize
) { fSize
= newSize
; }
446 class LinkEditAtom
: public WriterAtom
449 LinkEditAtom(Writer
& writer
) : WriterAtom(writer
, fgLinkEditSegment
) {}
450 uint64_t getFileOffset() const;
453 class LocalRelocationsLinkEditAtom
: public LinkEditAtom
456 LocalRelocationsLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
457 virtual const char* getDisplayName() const { return "local relocations"; }
458 virtual uint64_t getSize() const;
459 virtual uint8_t getAlignment() const { return 3; }
460 virtual const char* getSectionName() const { return "._local_relocs"; }
461 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
464 class SymbolTableLinkEditAtom
: public LinkEditAtom
467 SymbolTableLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
468 virtual const char* getDisplayName() const { return "symbol table"; }
469 virtual uint64_t getSize() const;
470 virtual uint8_t getAlignment() const { return 2; }
471 virtual const char* getSectionName() const { return "._symbol_table"; }
472 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
475 class ExternalRelocationsLinkEditAtom
: public LinkEditAtom
478 ExternalRelocationsLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
479 virtual const char* getDisplayName() const { return "external relocations"; }
480 virtual uint64_t getSize() const;
481 virtual uint8_t getAlignment() const { return 3; }
482 virtual const char* getSectionName() const { return "._extern_relocs"; }
483 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
486 class IndirectTableLinkEditAtom
: public LinkEditAtom
489 IndirectTableLinkEditAtom(Writer
& writer
) : LinkEditAtom(writer
) { }
490 virtual const char* getDisplayName() const { return "indirect symbol table"; }
491 virtual uint64_t getSize() const;
492 virtual uint8_t getAlignment() const { return 2; }
493 virtual const char* getSectionName() const { return "._indirect_syms"; }
494 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
497 class StringsLinkEditAtom
: public LinkEditAtom
500 StringsLinkEditAtom(Writer
& writer
);
501 virtual const char* getDisplayName() const { return "string pool"; }
502 virtual uint64_t getSize() const;
503 virtual uint8_t getAlignment() const { return 2; }
504 virtual const char* getSectionName() const { return "._string_pool"; }
505 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const;
507 int32_t add(const char* name
);
508 int32_t emptyString();
511 enum { kBufferSize
= 0x01000000 };
513 std::vector
<char*> fFullBuffers
;
514 char* fCurrentBuffer
;
515 uint32_t fCurrentBufferUsed
;
520 class UndefinedSymbolProxyAtom
: public WriterAtom
523 UndefinedSymbolProxyAtom(Writer
& writer
, const char* name
) : WriterAtom(writer
, fgLinkEditSegment
), fName(name
), fWeakImportSetting(Atom::kWeakUnset
) {}
524 virtual const char* getName() const { return fName
; }
525 virtual Scope
getScope() const { return ObjectFile::Atom::scopeGlobal
; }
526 virtual uint64_t getSize() const { return 0; }
527 virtual bool isWeakDefinition() const { return true; }
528 virtual bool isImportProxy() const { return true; }
529 virtual const char* getSectionName() const { return "._imports"; }
530 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
531 virtual WeakImportSetting
getImportWeakness() const { return fWeakImportSetting
; }
532 virtual void setImportWeakness(bool weakImport
) { fWeakImportSetting
= weakImport
? kWeakImport
: kNonWeakImport
; }
535 WeakImportSetting fWeakImportSetting
;
542 bool operator()(ObjectFile::Atom
* left
, ObjectFile::Atom
* right
)
544 return (strcmp(left
->getName(), right
->getName()) < 0);
549 ExecutableFile::Writer
* MakeWriter(const char* path
, Options
& options
, std::vector
<ExecutableFile::DyLibUsed
>& dynamicLibraries
)
551 return new Writer(path
, options
, dynamicLibraries
);
554 Writer::SectionInfo::SectionInfo()
555 : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
556 fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
558 fSegmentName
[0] = '\0';
559 fSectionName
[0] = '\0';
562 Writer::SegmentInfo::SegmentInfo()
563 : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0)
569 Writer::Writer(const char* path
, Options
& options
, std::vector
<ExecutableFile::DyLibUsed
>& dynamicLibraries
)
570 : ExecutableFile::Writer(dynamicLibraries
), fFilePath(strdup(path
)), fOptions(options
), fLoadCommandsSection(NULL
),
571 fLoadCommandsSegment(NULL
),
572 //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0),
573 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
575 int permissions
= 0777;
576 if ( fOptions
.outputKind() == Options::kObjectFile
)
578 // Calling unlink first assures the file is gone so that open creates it with correct permissions
579 // It also handles the case where fFilePath file is not writeable but its directory is
580 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
581 (void)unlink(fFilePath
);
582 fFileDescriptor
= open(fFilePath
, O_CREAT
| O_WRONLY
| O_TRUNC
, permissions
);
583 if ( fFileDescriptor
== -1 ) {
584 throw "can't open file for writing";
587 switch ( fOptions
.outputKind() ) {
588 case Options::kDynamicExecutable
:
589 case Options::kStaticExecutable
:
590 fWriterSynthesizedAtoms
.push_back(new PageZeroAtom(*this));
591 fWriterSynthesizedAtoms
.push_back(new MachHeaderAtom(*this));
592 fWriterSynthesizedAtoms
.push_back(new SegmentLoadCommandsAtom(*this));
593 fWriterSynthesizedAtoms
.push_back(new SymbolTableLoadCommandsAtom(*this));
594 if ( fOptions
.outputKind() == Options::kDynamicExecutable
)
595 fWriterSynthesizedAtoms
.push_back(new DyldLoadCommandsAtom(*this));
596 fWriterSynthesizedAtoms
.push_back(new ThreadsLoadCommandsAtom(*this));
597 if ( fOptions
.hasCustomStack() )
598 fWriterSynthesizedAtoms
.push_back(new CustomStackAtom(*this));
599 fWriterSynthesizedAtoms
.push_back(fHeaderPadding
= new LoadCommandsPaddingAtom(*this));
600 fWriterSynthesizedAtoms
.push_back(fLocalRelocationsAtom
= new LocalRelocationsLinkEditAtom(*this));
601 fWriterSynthesizedAtoms
.push_back(fSymbolTableAtom
= new SymbolTableLinkEditAtom(*this));
602 fWriterSynthesizedAtoms
.push_back(fExternalRelocationsAtom
= new ExternalRelocationsLinkEditAtom(*this));
603 fWriterSynthesizedAtoms
.push_back(fIndirectTableAtom
= new IndirectTableLinkEditAtom(*this));
604 fWriterSynthesizedAtoms
.push_back(fStringsAtom
= new StringsLinkEditAtom(*this));
606 case Options::kDynamicLibrary
:
607 case Options::kDynamicBundle
:
608 case Options::kObjectFile
:
609 fWriterSynthesizedAtoms
.push_back(new MachHeaderAtom(*this));
610 fWriterSynthesizedAtoms
.push_back(new SegmentLoadCommandsAtom(*this));
611 if ( fOptions
.outputKind() == Options::kDynamicLibrary
) {
612 fWriterSynthesizedAtoms
.push_back(new DylibIDLoadCommandsAtom(*this));
613 if ( fOptions
.initFunctionName() != NULL
)
614 fWriterSynthesizedAtoms
.push_back(new RoutinesLoadCommandsAtom(*this));
616 fWriterSynthesizedAtoms
.push_back(new SymbolTableLoadCommandsAtom(*this));
617 fWriterSynthesizedAtoms
.push_back(fHeaderPadding
= new LoadCommandsPaddingAtom(*this));
618 fWriterSynthesizedAtoms
.push_back(fLocalRelocationsAtom
= new LocalRelocationsLinkEditAtom(*this));
619 fWriterSynthesizedAtoms
.push_back(fSymbolTableAtom
= new SymbolTableLinkEditAtom(*this));
620 fWriterSynthesizedAtoms
.push_back(fExternalRelocationsAtom
= new ExternalRelocationsLinkEditAtom(*this));
621 fWriterSynthesizedAtoms
.push_back(fIndirectTableAtom
= new IndirectTableLinkEditAtom(*this));
622 fWriterSynthesizedAtoms
.push_back(fStringsAtom
= new StringsLinkEditAtom(*this));
625 fWriterSynthesizedAtoms
.push_back(new MachHeaderAtom(*this));
626 fWriterSynthesizedAtoms
.push_back(new SegmentLoadCommandsAtom(*this));
627 fWriterSynthesizedAtoms
.push_back(new SymbolTableLoadCommandsAtom(*this));
628 fWriterSynthesizedAtoms
.push_back(new DyldLoadCommandsAtom(*this));
629 fWriterSynthesizedAtoms
.push_back(new ThreadsLoadCommandsAtom(*this));
630 fWriterSynthesizedAtoms
.push_back(fHeaderPadding
= new LoadCommandsPaddingAtom(*this));
631 fWriterSynthesizedAtoms
.push_back(fLocalRelocationsAtom
= new LocalRelocationsLinkEditAtom(*this));
632 fWriterSynthesizedAtoms
.push_back(fSymbolTableAtom
= new SymbolTableLinkEditAtom(*this));
633 fWriterSynthesizedAtoms
.push_back(fExternalRelocationsAtom
= new ExternalRelocationsLinkEditAtom(*this));
634 fWriterSynthesizedAtoms
.push_back(fIndirectTableAtom
= new IndirectTableLinkEditAtom(*this));
635 fWriterSynthesizedAtoms
.push_back(fStringsAtom
= new StringsLinkEditAtom(*this));
639 // add extra commmands
641 switch ( fOptions
.outputKind() ) {
642 case Options::kDynamicExecutable
:
643 case Options::kDynamicLibrary
:
644 case Options::kDynamicBundle
:
646 // add dylib load command atoms for all dynamic libraries
647 const unsigned int libCount
= dynamicLibraries
.size();
648 for (unsigned int i
=0; i
< libCount
; ++i
) {
649 ExecutableFile::DyLibUsed
& dylibInfo
= dynamicLibraries
[i
];
650 if ( dylibInfo
.indirect
) {
651 // find ordinal of direct reader
652 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
) {
654 for (std::map
<class ObjectFile::Reader
*, uint32_t>::iterator it
= fLibraryToOrdinal
.begin(); it
!= fLibraryToOrdinal
.end(); ++it
) {
655 if ( it
->first
== dylibInfo
.directReader
) {
656 //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
657 fLibraryToOrdinal
[dylibInfo
.reader
] = it
->second
;
663 fprintf(stderr
, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo
.reader
->getPath(), dylibInfo
.directReader
!= NULL
? dylibInfo
.directReader
->getPath() : NULL
);
667 // see if a DylibLoadCommandsAtom has already been created for this install path
668 bool newDylib
= true;
669 const char* dylibInstallPath
= dylibInfo
.reader
->getInstallPath();
670 if ( dylibInfo
.options
.fInstallPathOverride
!= NULL
)
671 dylibInstallPath
= dylibInfo
.options
.fInstallPathOverride
;
672 for (unsigned int seenLib
=0; seenLib
< i
; ++seenLib
) {
673 ExecutableFile::DyLibUsed
& seenDylibInfo
= dynamicLibraries
[seenLib
];
674 if ( !seenDylibInfo
.indirect
) {
675 const char* seenDylibInstallPath
= seenDylibInfo
.reader
->getInstallPath();
676 if ( seenDylibInfo
.options
.fInstallPathOverride
!= NULL
)
677 seenDylibInstallPath
= dylibInfo
.options
.fInstallPathOverride
;
678 if ( strcmp(seenDylibInstallPath
, dylibInstallPath
) == 0 ) {
679 fLibraryToOrdinal
[dylibInfo
.reader
] = fLibraryToOrdinal
[seenDylibInfo
.reader
];
687 // assign new ordinal and check for other paired load commands
688 fLibraryToOrdinal
[dylibInfo
.reader
] = ordinal
++;
689 fWriterSynthesizedAtoms
.push_back(new DylibLoadCommandsAtom(*this, dylibInfo
));
690 if ( dylibInfo
.options
.fReExport
) {
691 // this dylib also needs a sub_x load command
692 bool isFrameworkReExport
= false;
693 const char* lastSlash
= strrchr(dylibInstallPath
, '/');
694 if ( lastSlash
!= NULL
) {
695 char frameworkName
[strlen(lastSlash
)+20];
696 sprintf(frameworkName
, "/%s.framework/", &lastSlash
[1]);
697 isFrameworkReExport
= (strstr(dylibInstallPath
, frameworkName
) != NULL
);
699 if ( isFrameworkReExport
) {
700 // needs a LC_SUB_UMBRELLA command
701 fWriterSynthesizedAtoms
.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash
[1]));
704 // needs a LC_SUB_LIBRARY command
705 const char* nameStart
= &lastSlash
[1];
706 if ( lastSlash
== NULL
)
707 nameStart
= dylibInstallPath
;
708 int len
= strlen(nameStart
);
709 const char* dot
= strchr(nameStart
, '.');
711 len
= dot
- nameStart
;
712 fWriterSynthesizedAtoms
.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart
, len
));
718 // add umbrella command if needed
719 if ( fOptions
.umbrellaName() != NULL
) {
720 fWriterSynthesizedAtoms
.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions
.umbrellaName()));
724 case Options::kStaticExecutable
:
725 case Options::kObjectFile
:
730 //fprintf(stderr, "ordinals table:\n");
731 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
732 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
738 if ( fFilePath
!= NULL
)
739 free((void*)fFilePath
);
740 if ( fSymbolTable
!= NULL
)
741 delete [] fSymbolTable
;
742 //if ( fStringPool != NULL )
743 // delete [] fStringPool;
746 const char* Writer::getPath()
752 std::vector
<class ObjectFile::Atom
*>& Writer::getAtoms()
754 return fWriterSynthesizedAtoms
;
757 std::vector
<class ObjectFile::Atom
*>* Writer::getJustInTimeAtomsFor(const char* name
)
762 std::vector
<ObjectFile::StabsInfo
>* Writer::getStabsDebugInfo()
767 ObjectFile::Atom
* Writer::getUndefinedProxyAtom(const char* name
)
769 if ( (fOptions
.outputKind() == Options::kObjectFile
)
770 || (fOptions
.undefinedTreatment() != Options::kUndefinedError
) )
771 return new UndefinedSymbolProxyAtom(*this, name
);
776 uint8_t Writer::ordinalForLibrary(ObjectFile::Reader
* lib
)
778 // flat namespace images use zero for all ordinals
779 if ( fOptions
.nameSpace() != Options::kTwoLevelNameSpace
)
782 // is an UndefinedSymbolProxyAtom
784 if ( fOptions
.nameSpace() == Options::kTwoLevelNameSpace
)
785 return DYNAMIC_LOOKUP_ORDINAL
;
787 std::map
<class ObjectFile::Reader
*, uint32_t>::iterator pos
= fLibraryToOrdinal
.find(lib
);
788 if ( pos
!= fLibraryToOrdinal
.end() )
791 throw "can't find ordinal for imported symbol";
795 void Writer::write(std::vector
<class ObjectFile::Atom
*>& atoms
, class ObjectFile::Atom
* entryPointAtom
)
798 fEntryPoint
= entryPointAtom
;
800 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
801 partitionIntoSections();
803 // segment load command can now be sized and padding can be set
804 adjustLoadCommandsAndPadding();
806 // assign each section a file offset
809 // build symbol table and relocations
816 void Writer::buildLinkEdit()
818 this->collectExportedAndImportedAndLocalAtoms();
819 this->buildSymbolTable();
821 this->adjustLinkEditSections();
826 uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom
* atom
)
828 return atom
->getAddress();
829 // SectionInfo* info = (SectionInfo*)atom->getSection();
830 // return info->getBaseAddress() + atom->getSectionOffset();
833 void Writer::setExportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
)
836 entry
->set_n_type(N_EXT
| N_SECT
);
837 if ( (atom
->getScope() == ObjectFile::Atom::scopeLinkageUnit
) && fOptions
.keepPrivateExterns() && (fOptions
.outputKind() == Options::kObjectFile
) )
838 entry
->set_n_type(N_EXT
| N_SECT
| N_PEXT
);
840 // set n_sect (section number of implementation )
841 uint8_t sectionIndex
= atom
->getSection()->getIndex();
842 entry
->set_n_sect(sectionIndex
);
844 // the __mh_execute_header is magic and must be an absolute symbol
845 if ( (fOptions
.outputKind() == Options::kDynamicExecutable
) && (sectionIndex
==0) && atom
->dontStripName())
846 entry
->set_n_type(N_EXT
| N_ABS
);
850 if ( atom
->dontStripName() )
851 desc
|= REFERENCED_DYNAMICALLY
;
852 if ( atom
->isWeakDefinition() && (strcmp(atom
->getSectionName(), "__common") != 0) ) {
854 fHasWeakExports
= true;
856 entry
->set_n_desc(desc
);
858 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
859 entry
->set_n_value(this->getAtomLoadAddress(atom
));
862 void Writer::setImportNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
)
865 entry
->set_n_type(N_UNDF
| N_EXT
);
868 entry
->set_n_sect(0);
871 if ( fOptions
.outputKind() != Options::kObjectFile
) {
872 // set n_desc ( high byte is library ordinal, low byte is reference type )
873 desc
= REFERENCE_FLAG_UNDEFINED_LAZY
; // FIXME
875 uint8_t ordinal
= this->ordinalForLibrary(atom
->getFile());
876 SET_LIBRARY_ORDINAL(desc
, ordinal
);
878 catch (const char* msg
) {
879 throwf("%s %s from %s", msg
, atom
->getDisplayName(), atom
->getFile()->getPath());
882 if ( atom
->dontStripName() )
883 desc
|= REFERENCED_DYNAMICALLY
;
884 // an import proxy is always weak (overridden by definition in .o files)
885 // so we ask its reader if the exported symbol in its dylib is weak
886 if ( ( fOptions
.outputKind() != Options::kObjectFile
) && atom
->getFile()->isDefinitionWeak(*atom
) ) {
887 desc
|= N_REF_TO_WEAK
;
888 fReferencesWeakImports
= true;
890 // set weak_import attribute
891 if ( atom
->getImportWeakness() == ObjectFile::Atom::kWeakImport
)
893 entry
->set_n_desc(desc
);
895 // set n_value, zero for import proxy and size for tentative definition
896 entry
->set_n_value(atom
->getSize());
899 void Writer::setLocalNlist(const ObjectFile::Atom
* atom
, macho_nlist
* entry
)
902 uint8_t type
= N_SECT
;
903 if ( atom
->getScope() == ObjectFile::Atom::scopeLinkageUnit
)
905 entry
->set_n_type(type
);
907 // set n_sect (section number of implementation )
908 uint8_t sectIndex
= atom
->getSection()->getIndex();
909 if ( sectIndex
== 0 ) {
910 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
911 if ( strcmp(atom
->getSectionName(), "._mach_header") == 0 )
914 entry
->set_n_sect(sectIndex
);
918 if ( atom
->isWeakDefinition() && (strcmp(atom
->getSectionName(), "__common") != 0) ) // commons on not weak
920 entry
->set_n_desc(desc
);
922 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
923 entry
->set_n_value(this->getAtomLoadAddress(atom
));
927 void Writer::setNlistRange(std::vector
<class ObjectFile::Atom
*>& atoms
, uint32_t startIndex
, uint32_t count
)
929 macho_nlist
* entry
= &fSymbolTable
[startIndex
];
930 for (uint32_t i
=0; i
< count
; ++i
, ++entry
) {
931 ObjectFile::Atom
* atom
= atoms
[i
];
932 entry
->set_n_strx(this->fStringsAtom
->add(atom
->getName()));
933 if ( &atoms
== &fExportedAtoms
) {
934 this->setExportNlist(atom
, entry
);
936 else if ( &atoms
== &fImportedAtoms
) {
937 this->setImportNlist(atom
, entry
);
940 this->setLocalNlist(atom
, entry
);
945 void Writer::buildSymbolTable()
947 fSymbolTableStabsStartIndex
= 0;
948 fSymbolTableStabsCount
= this->collectStabs();
949 fSymbolTableLocalStartIndex
= fSymbolTableStabsStartIndex
+ fSymbolTableStabsCount
;
950 fSymbolTableLocalCount
= fLocalSymbolAtoms
.size();
951 fSymbolTableExportStartIndex
= fSymbolTableLocalStartIndex
+ fSymbolTableLocalCount
;
952 fSymbolTableExportCount
= fExportedAtoms
.size();
953 fSymbolTableImportStartIndex
= fSymbolTableExportStartIndex
+ fSymbolTableExportCount
;
954 fSymbolTableImportCount
= fImportedAtoms
.size();
956 // allocate symbol table
957 fSymbolTableCount
= fSymbolTableStabsCount
+ fSymbolTableLocalCount
+ fSymbolTableExportCount
+ fSymbolTableImportCount
;
958 fSymbolTable
= new macho_nlist
[fSymbolTableCount
];
960 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
961 setNlistRange(fLocalSymbolAtoms
, fSymbolTableLocalStartIndex
, fSymbolTableLocalCount
);
962 setNlistRange(fExportedAtoms
, fSymbolTableExportStartIndex
, fSymbolTableExportCount
);
963 setNlistRange(fImportedAtoms
, fSymbolTableImportStartIndex
, fSymbolTableImportCount
);
964 addStabs(fSymbolTableStabsStartIndex
, fSymbolTableStabsCount
);
969 bool Writer::shouldExport(ObjectFile::Atom
& atom
)
971 switch ( atom
.getScope() ) {
972 case ObjectFile::Atom::scopeGlobal
:
974 case ObjectFile::Atom::scopeLinkageUnit
:
975 return ( fOptions
.keepPrivateExterns() && (fOptions
.outputKind() == Options::kObjectFile
) );
981 void Writer::collectExportedAndImportedAndLocalAtoms()
983 const int atomCount
= fAllAtoms
->size();
984 for (int i
=0; i
< atomCount
; ++i
) {
985 ObjectFile::Atom
* atom
= (*fAllAtoms
)[i
];
986 // only named atoms go in symbol table
987 if ( atom
->getName() != NULL
) {
988 // put atom into correct bucket: imports, exports, locals
989 //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
990 if ( atom
->isImportProxy() || ((fOptions
.outputKind() == Options::kObjectFile
) && (strcmp(atom
->getSectionName(), "__common") == 0)) )
991 fImportedAtoms
.push_back(atom
);
992 else if ( this->shouldExport(*atom
) )
993 fExportedAtoms
.push_back(atom
);
994 else if ( !fOptions
.stripLocalSymbols() )
995 fLocalSymbolAtoms
.push_back(atom
);
999 // sort exported atoms by name
1000 std::sort(fExportedAtoms
.begin(), fExportedAtoms
.end(), ExportSorter());
1004 bool Writer::stabChunkCompare(const struct StabChunks
& lhs
, const struct StabChunks
& rhs
)
1006 if ( lhs
.fReader
!= rhs
.fReader
) {
1007 return lhs
.fReader
< rhs
.fReader
;
1009 return lhs
.fOrderInReader
< rhs
.fOrderInReader
;
1012 unsigned int Writer::collectStabs()
1014 unsigned int count
= 0;
1016 // collect all stabs chunks
1017 std::set
<ObjectFile::Reader
*> seenReaders
;
1018 const int atomCount
= fAllAtoms
->size();
1019 for (int i
=0; i
< atomCount
; ++i
) {
1020 ObjectFile::Atom
* atom
= (*fAllAtoms
)[i
];
1021 ObjectFile::Reader
* atomsReader
= atom
->getFile();
1022 if ( (atomsReader
!= NULL
) && (seenReaders
.count(atomsReader
) == 0) ) {
1023 seenReaders
.insert(atomsReader
);
1024 std::vector
<ObjectFile::StabsInfo
>* readerStabs
= atomsReader
->getStabsDebugInfo();
1025 if ( readerStabs
!= NULL
) {
1028 chunk
.fReader
= atomsReader
;
1029 chunk
.fOrderInReader
= 0;
1030 chunk
.fStabs
= readerStabs
;
1031 fStabChunks
.push_back(chunk
);
1032 count
+= readerStabs
->size() + 1; // extra one is for trailing N_SO
1035 std::vector
<ObjectFile::StabsInfo
>* atomStabs
= atom
->getStabsDebugInfo();
1036 if ( atomStabs
!= NULL
) {
1039 chunk
.fReader
= atomsReader
;
1040 chunk
.fOrderInReader
= atom
->getSortOrder();
1041 chunk
.fStabs
= atomStabs
;
1042 fStabChunks
.push_back(chunk
);
1043 count
+= atomStabs
->size();
1047 // sort by order in original .o file
1048 std::sort(fStabChunks
.begin(), fStabChunks
.end(), stabChunkCompare
);
1053 macho_uintptr_t
Writer::valueForStab(const ObjectFile::StabsInfo
& stab
, const ObjectFile::Atom
* atom
)
1055 switch ( stab
.type
) {
1057 if ( stab
.other
== 0 )
1059 // end of function N_FUN has size (not address) so should not be adjusted
1068 // all these stab types need their value changed from an offset in the atom to an address
1070 return getAtomLoadAddress(atom
) + stab
.atomOffset
;
1072 return stab
.atomOffset
;
1076 void Writer::addStabs(uint32_t startIndex
, uint32_t count
)
1078 macho_nlist
* entry
= &fSymbolTable
[startIndex
];
1079 const int chunkCount
= fStabChunks
.size();
1080 for (int i
=0; i
< chunkCount
; ++i
) {
1081 const StabChunks
& chunk
= fStabChunks
[i
];
1082 const int stabCount
= chunk
.fStabs
->size();
1083 for (int j
=0; j
< stabCount
; ++j
) {
1084 const ObjectFile::StabsInfo
& stab
= (*chunk
.fStabs
)[j
];
1085 entry
->set_n_type(stab
.type
);
1086 entry
->set_n_sect(stab
.other
);
1087 entry
->set_n_desc(stab
.desc
);
1088 entry
->set_n_value(valueForStab(stab
, chunk
.fAtom
));
1089 entry
->set_n_strx(this->fStringsAtom
->add(stab
.string
));
1092 if ( (i
== chunkCount
-1) || (fStabChunks
[i
+1].fReader
!= chunk
.fReader
) ) {
1093 // need to add empty SO at end of each file
1094 entry
->set_n_type(N_SO
);
1095 entry
->set_n_sect(1);
1096 entry
->set_n_desc(0);
1097 entry
->set_n_value(0);
1098 entry
->set_n_strx(this->fStringsAtom
->emptyString());
1107 uint32_t Writer::symbolIndex(ObjectFile::Atom
& atom
)
1110 const int importCount
= fImportedAtoms
.size();
1111 for (int i
=0; i
< importCount
; ++i
) {
1112 if ( &atom
== fImportedAtoms
[i
] )
1113 return i
+ fSymbolTableImportStartIndex
;
1117 const int localCount
= fLocalSymbolAtoms
.size();
1118 for (int i
=0; i
< localCount
; ++i
) {
1119 if ( &atom
== fLocalSymbolAtoms
[i
] )
1120 return i
+ fSymbolTableLocalStartIndex
;
1124 const int exportCount
= fExportedAtoms
.size();
1125 for (int i
=0; i
< exportCount
; ++i
) {
1126 if ( &atom
== fExportedAtoms
[i
] )
1127 return i
+ fSymbolTableExportStartIndex
;
1130 fprintf(stderr
, "symbolIndex(%s)\n", atom
.getDisplayName());
1131 fprintf(stderr
, "from %s\n", atom
.getFile()->getPath());
1132 throw "atom not found";
1136 void Writer::buildFixups()
1138 if ( fOptions
.outputKind() == Options::kObjectFile
)
1139 this->buildObjectFileFixups();
1141 this->buildExecutableFixups();
1144 uint32_t Writer::addRelocs(ObjectFile::Atom
* atom
, ObjectFile::Reference
* ref
)
1146 ObjectFile::Atom
& target
= ref
->getTarget();
1147 bool isExtern
= target
.isImportProxy() || ( strcmp(target
.getSectionName(), "__common") == 0 );
1148 uint32_t symbolIndex
= 0;
1150 symbolIndex
= this->symbolIndex(target
);
1151 uint32_t sectionNum
= target
.getSection()->getIndex();
1152 uint32_t address
= atom
->getSectionOffset()+ref
->getFixUpOffset();
1153 macho_relocation_info reloc1
;
1154 macho_relocation_info reloc2
;
1155 macho_scattered_relocation_info
* sreloc1
= (macho_scattered_relocation_info
*)&reloc1
;
1156 macho_scattered_relocation_info
* sreloc2
= (macho_scattered_relocation_info
*)&reloc2
;
1158 switch ( ref
->getKind() ) {
1159 case ObjectFile::Reference::noFixUp
:
1162 case ObjectFile::Reference::pointer
:
1163 reloc1
.set_r_address(address
);
1165 reloc1
.set_r_symbolnum(symbolIndex
);
1167 reloc1
.set_r_symbolnum(sectionNum
);
1168 reloc1
.set_r_pcrel(false);
1169 reloc1
.set_r_length(macho_relocation_info::pointer_length
);
1170 reloc1
.set_r_extern(isExtern
);
1171 reloc1
.set_r_type(GENERIC_RELOC_VANILLA
);
1172 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1175 case ObjectFile::Reference::ppcFixupBranch24
:
1176 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1177 reloc1
.set_r_address(address
);
1179 reloc1
.set_r_symbolnum(symbolIndex
);
1181 reloc1
.set_r_symbolnum(sectionNum
);
1182 reloc1
.set_r_pcrel(true);
1183 reloc1
.set_r_length(2);
1184 reloc1
.set_r_type(PPC_RELOC_BR24
);
1185 reloc1
.set_r_extern(isExtern
);
1188 sreloc1
->set_r_scattered(true);
1189 sreloc1
->set_r_pcrel(true);
1190 sreloc1
->set_r_length(2);
1191 sreloc1
->set_r_type(PPC_RELOC_BR24
);
1192 sreloc1
->set_r_address(address
);
1193 sreloc1
->set_r_value(target
.getAddress());
1195 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1198 case ObjectFile::Reference::ppcFixupBranch14
:
1199 reloc1
.set_r_address(address
);
1200 reloc1
.set_r_symbolnum(sectionNum
);
1201 reloc1
.set_r_pcrel(true);
1202 reloc1
.set_r_length(2);
1203 reloc1
.set_r_extern(false);
1204 reloc1
.set_r_type(PPC_RELOC_BR14
);
1205 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1208 case ObjectFile::Reference::ppcFixupPicBaseLow14
:
1209 case ObjectFile::Reference::ppcFixupPicBaseLow16
:
1211 macho_uintptr_t fromAddr
= atom
->getAddress() + ref
->getFromTargetOffset();
1212 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1213 uint32_t overflow
= 0;
1214 if ( ((toAddr
-fromAddr
) & 0x00008000) != 0 )
1216 sreloc1
->set_r_scattered(true);
1217 sreloc1
->set_r_pcrel(false);
1218 sreloc1
->set_r_length(2);
1219 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16
)
1220 sreloc1
->set_r_type(PPC_RELOC_LO16_SECTDIFF
);
1222 sreloc1
->set_r_type(PPC_RELOC_LO14_SECTDIFF
);
1223 sreloc1
->set_r_address(address
);
1224 sreloc1
->set_r_value(target
.getAddress());
1225 sreloc2
->set_r_scattered(true);
1226 sreloc2
->set_r_pcrel(false);
1227 sreloc2
->set_r_length(2);
1228 sreloc2
->set_r_type(PPC_RELOC_PAIR
);
1229 sreloc2
->set_r_address(((toAddr
-fromAddr
) >> 16));
1230 sreloc2
->set_r_value(fromAddr
);
1231 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1232 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1236 case ObjectFile::Reference::ppcFixupPicBaseHigh16
:
1238 macho_uintptr_t fromAddr
= atom
->getAddress() + ref
->getFromTargetOffset();
1239 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1240 sreloc1
->set_r_scattered(true);
1241 sreloc1
->set_r_pcrel(false);
1242 sreloc1
->set_r_length(2);
1243 sreloc1
->set_r_type(PPC_RELOC_HA16_SECTDIFF
);
1244 sreloc1
->set_r_address(address
);
1245 sreloc1
->set_r_value(target
.getAddress());
1246 sreloc2
->set_r_scattered(true);
1247 sreloc2
->set_r_pcrel(false);
1248 sreloc2
->set_r_length(2);
1249 sreloc2
->set_r_type(PPC_RELOC_PAIR
);
1250 sreloc2
->set_r_address((toAddr
-fromAddr
) & 0xFFFF);
1251 sreloc2
->set_r_value(fromAddr
);
1252 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1253 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1257 case ObjectFile::Reference::ppcFixupAbsLow14
:
1258 case ObjectFile::Reference::ppcFixupAbsLow16
:
1260 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1261 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1262 reloc1
.set_r_address(address
);
1264 reloc1
.set_r_symbolnum(symbolIndex
);
1266 reloc1
.set_r_symbolnum(sectionNum
);
1267 reloc1
.set_r_pcrel(false);
1268 reloc1
.set_r_length(2);
1269 reloc1
.set_r_extern(isExtern
);
1270 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupAbsLow16
)
1271 reloc1
.set_r_type(PPC_RELOC_LO16
);
1273 reloc1
.set_r_type(PPC_RELOC_LO14
);
1276 sreloc1
->set_r_scattered(true);
1277 sreloc1
->set_r_pcrel(false);
1278 sreloc1
->set_r_length(2);
1279 if ( ref
->getKind() == ObjectFile::Reference::ppcFixupAbsLow16
)
1280 sreloc1
->set_r_type(PPC_RELOC_LO16
);
1282 sreloc1
->set_r_type(PPC_RELOC_LO14
);
1283 sreloc1
->set_r_address(address
);
1284 sreloc1
->set_r_value(target
.getAddress());
1287 reloc2
.set_r_address(ref
->getTargetOffset() >> 16);
1289 reloc2
.set_r_address(toAddr
>> 16);
1290 reloc2
.set_r_symbolnum(0);
1291 reloc2
.set_r_pcrel(false);
1292 reloc2
.set_r_length(2);
1293 reloc2
.set_r_extern(false);
1294 reloc2
.set_r_type(PPC_RELOC_PAIR
);
1295 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1296 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1300 case ObjectFile::Reference::ppcFixupAbsHigh16
:
1302 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1303 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1304 reloc1
.set_r_address(address
);
1306 reloc1
.set_r_symbolnum(symbolIndex
);
1308 reloc1
.set_r_symbolnum(sectionNum
);
1309 reloc1
.set_r_pcrel(false);
1310 reloc1
.set_r_length(2);
1311 reloc1
.set_r_extern(isExtern
);
1312 reloc1
.set_r_type(PPC_RELOC_HI16
);
1315 sreloc1
->set_r_scattered(true);
1316 sreloc1
->set_r_pcrel(false);
1317 sreloc1
->set_r_length(2);
1318 sreloc1
->set_r_type(PPC_RELOC_HI16
);
1319 sreloc1
->set_r_address(address
);
1320 sreloc1
->set_r_value(target
.getAddress());
1323 reloc2
.set_r_address(ref
->getTargetOffset() & 0xFFFF);
1325 reloc2
.set_r_address(toAddr
& 0xFFFF);
1326 reloc2
.set_r_symbolnum(0);
1327 reloc2
.set_r_pcrel(false);
1328 reloc2
.set_r_length(2);
1329 reloc2
.set_r_extern(false);
1330 reloc2
.set_r_type(PPC_RELOC_PAIR
);
1331 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1332 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1336 case ObjectFile::Reference::ppcFixupAbsHigh16AddLow
:
1338 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1339 uint32_t overflow
= 0;
1340 if ( (toAddr
& 0x00008000) != 0 )
1342 if ( (ref
->getTargetOffset() == 0) || isExtern
) {
1343 reloc1
.set_r_address(address
);
1345 reloc1
.set_r_symbolnum(symbolIndex
);
1347 reloc1
.set_r_symbolnum(sectionNum
);
1348 reloc1
.set_r_pcrel(false);
1349 reloc1
.set_r_length(2);
1350 reloc1
.set_r_extern(isExtern
);
1351 reloc1
.set_r_type(PPC_RELOC_HA16
);
1354 sreloc1
->set_r_scattered(true);
1355 sreloc1
->set_r_pcrel(false);
1356 sreloc1
->set_r_length(2);
1357 sreloc1
->set_r_type(PPC_RELOC_HA16
);
1358 sreloc1
->set_r_address(address
);
1359 sreloc1
->set_r_value(target
.getAddress());
1362 reloc2
.set_r_address(ref
->getTargetOffset() & 0xFFFF);
1364 reloc2
.set_r_address(toAddr
& 0xFFFF);
1365 reloc2
.set_r_symbolnum(0);
1366 reloc2
.set_r_pcrel(false);
1367 reloc2
.set_r_length(2);
1368 reloc2
.set_r_extern(false);
1369 reloc2
.set_r_type(PPC_RELOC_PAIR
);
1370 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1371 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1375 case ObjectFile::Reference::pointer32Difference
:
1376 case ObjectFile::Reference::pointer64Difference
:
1378 macho_uintptr_t toAddr
= target
.getAddress() + ref
->getTargetOffset();
1379 macho_uintptr_t fromAddr
= ref
->getFromTarget().getAddress() + ref
->getFromTargetOffset();
1380 sreloc1
->set_r_scattered(true);
1381 sreloc1
->set_r_pcrel(false);
1382 if ( ref
->getKind() == ObjectFile::Reference::pointer64Difference
)
1383 sreloc1
->set_r_length(3);
1385 sreloc1
->set_r_length(2);
1386 if ( ref
->getTargetOffset() != 0 )
1387 sreloc1
->set_r_type(PPC_RELOC_LOCAL_SECTDIFF
);
1389 sreloc1
->set_r_type(PPC_RELOC_SECTDIFF
);
1390 sreloc1
->set_r_address(address
);
1391 sreloc1
->set_r_value(toAddr
);
1392 sreloc2
->set_r_scattered(true);
1393 sreloc2
->set_r_pcrel(false);
1394 sreloc2
->set_r_length(macho_relocation_info::pointer_length
);
1395 sreloc2
->set_r_type(PPC_RELOC_PAIR
);
1396 sreloc2
->set_r_address(0);
1397 sreloc2
->set_r_value(fromAddr
);
1398 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc2
);
1399 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1403 case ObjectFile::Reference::x86FixupBranch32
:
1404 reloc1
.set_r_address(address
);
1405 reloc1
.set_r_symbolnum(sectionNum
);
1406 reloc1
.set_r_pcrel(true);
1407 reloc1
.set_r_length(2);
1408 reloc1
.set_r_extern(false);
1409 reloc1
.set_r_type(GENERIC_RELOC_VANILLA
);
1410 fInternalRelocs
.insert(fInternalRelocs
.begin(), reloc1
);
1418 void Writer::buildObjectFileFixups()
1420 uint32_t relocIndex
= 0;
1421 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1422 const int segCount
= segmentInfos
.size();
1423 for(int i
=0; i
< segCount
; ++i
) {
1424 SegmentInfo
* curSegment
= segmentInfos
[i
];
1425 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1426 const int sectionCount
= sectionInfos
.size();
1427 for(int j
=0; j
< sectionCount
; ++j
) {
1428 SectionInfo
* curSection
= sectionInfos
[j
];
1429 std::vector
<ObjectFile::Atom
*>& sectionAtoms
= curSection
->fAtoms
;
1430 if ( ! curSection
->fAllZeroFill
) {
1431 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
)
1432 curSection
->fIndirectSymbolOffset
= fIndirectSymbolTable
.size();
1433 curSection
->fRelocOffset
= relocIndex
;
1434 const int atomCount
= sectionAtoms
.size();
1435 for (int k
=0; k
< atomCount
; ++k
) {
1436 ObjectFile::Atom
* atom
= sectionAtoms
[k
];
1437 std::vector
<ObjectFile::Reference
*>& refs
= atom
->getReferences();
1438 const int refCount
= refs
.size();
1439 for (int l
=0; l
< refCount
; ++l
) {
1440 ObjectFile::Reference
* ref
= refs
[l
];
1441 relocIndex
+= this->addRelocs(atom
, ref
);
1442 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
) {
1443 uint32_t offsetInSection
= atom
->getSectionOffset();
1444 uint32_t indexInSection
= offsetInSection
/ sizeof(macho_uintptr_t
);
1445 uint32_t undefinedSymbolIndex
= this->symbolIndex(ref
->getTarget());
1446 uint32_t indirectTableIndex
= indexInSection
+ curSection
->fIndirectSymbolOffset
;
1447 IndirectEntry entry
= { indirectTableIndex
, undefinedSymbolIndex
};
1448 //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
1449 fIndirectSymbolTable
.push_back(entry
);
1453 curSection
->fRelocCount
= relocIndex
- curSection
->fRelocOffset
;
1458 // now reverse reloc entries
1459 for(int i
=0; i
< segCount
; ++i
) {
1460 SegmentInfo
* curSegment
= segmentInfos
[i
];
1461 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1462 const int sectionCount
= sectionInfos
.size();
1463 for(int j
=0; j
< sectionCount
; ++j
) {
1464 SectionInfo
* curSection
= sectionInfos
[j
];
1465 curSection
->fRelocOffset
= relocIndex
- curSection
->fRelocOffset
- curSection
->fRelocCount
;
1472 void Writer::buildExecutableFixups()
1474 const bool slideable
= (fOptions
.outputKind() != Options::kDynamicExecutable
) && (fOptions
.outputKind() != Options::kStaticExecutable
);
1475 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1476 const int segCount
= segmentInfos
.size();
1477 for(int i
=0; i
< segCount
; ++i
) {
1478 SegmentInfo
* curSegment
= segmentInfos
[i
];
1479 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1480 const int sectionCount
= sectionInfos
.size();
1481 for(int j
=0; j
< sectionCount
; ++j
) {
1482 SectionInfo
* curSection
= sectionInfos
[j
];
1483 std::vector
<ObjectFile::Atom
*>& sectionAtoms
= curSection
->fAtoms
;
1484 if ( ! curSection
->fAllZeroFill
) {
1485 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
)
1486 curSection
->fIndirectSymbolOffset
= fIndirectSymbolTable
.size();
1487 const int atomCount
= sectionAtoms
.size();
1488 for (int k
=0; k
< atomCount
; ++k
) {
1489 ObjectFile::Atom
* atom
= sectionAtoms
[k
];
1490 std::vector
<ObjectFile::Reference
*>& refs
= atom
->getReferences();
1491 const int refCount
= refs
.size();
1492 //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
1494 for (int l
=0; l
< refCount
; ++l
) {
1495 ObjectFile::Reference
* ref
= refs
[l
];
1496 // only care about references that need dyld fixups
1497 if ( ref
->requiresRuntimeFixUp() ) {
1498 if ( ! atom
->getSegment().isContentWritable() )
1499 throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom
->getDisplayName(), atom
->getFile()->getPath(), ref
->getTarget().getDisplayName());
1500 if ( curSection
->fAllNonLazyPointers
|| curSection
->fAllLazyPointers
) {
1501 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
1502 if ( atom
->getSize() != sizeof(macho_uintptr_t
) ) {
1503 printf("oversize pointer atom %s from file %s\n", atom
->getDisplayName(), atom
->getFile()->getPath());
1505 uint32_t offsetInSection
= atom
->getSectionOffset();
1506 uint32_t indexInSection
= offsetInSection
/ sizeof(macho_uintptr_t
);
1507 uint32_t undefinedSymbolIndex
= INDIRECT_SYMBOL_LOCAL
;
1508 //printf("indirect pointer atom %s section offset = %d\n", atom->getDisplayName(), offsetInSection);
1509 if ( ref
->getTarget().isImportProxy()
1510 || ref
->getTarget().isWeakDefinition()
1511 || (fOptions
.interposable() && fOptions
.shouldExport(ref
->getTarget().getName()))
1512 || (fOptions
.nameSpace() == Options::kFlatNameSpace
)
1513 || (fOptions
.nameSpace() == Options::kForceFlatNameSpace
) ) {
1514 undefinedSymbolIndex
= this->symbolIndex(ref
->getTarget());
1516 uint32_t indirectTableIndex
= indexInSection
+ curSection
->fIndirectSymbolOffset
;
1517 IndirectEntry entry
= { indirectTableIndex
, undefinedSymbolIndex
};
1518 //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
1519 fIndirectSymbolTable
.push_back(entry
);
1520 if ( slideable
&& curSection
->fAllLazyPointers
) {
1521 // if this is a dylib/bundle, need PBLAPTR internal relocation to fix up binding handler if image slides
1522 macho_relocation_info pblaReloc
;
1523 macho_scattered_relocation_info
* pblaSReloc
= (macho_scattered_relocation_info
*)&pblaReloc
;
1524 pblaSReloc
->set_r_scattered(true);
1525 pblaSReloc
->set_r_pcrel(false);
1526 pblaSReloc
->set_r_length(macho_relocation_info::pointer_length
);
1527 pblaSReloc
->set_r_type(PPC_RELOC_PB_LA_PTR
);
1528 pblaSReloc
->set_r_address(atom
->getAddress()-fOptions
.baseAddress());
1529 pblaSReloc
->set_r_value(ref
->getFromTarget().getAddress()); // helper is stored in "from" address
1530 fInternalRelocs
.push_back(pblaReloc
);
1533 else if ( ref
->getTarget().isImportProxy() ) {
1534 // if import is to antoher dylib, this is encoded as an external relocation
1535 macho_relocation_info externalReloc
;
1536 externalReloc
.set_r_address(atom
->getAddress()+ref
->getFixUpOffset()-fOptions
.baseAddress());
1537 externalReloc
.set_r_symbolnum(this->symbolIndex(ref
->getTarget()));
1538 externalReloc
.set_r_pcrel(false);
1539 externalReloc
.set_r_length(macho_relocation_info::pointer_length
);
1540 externalReloc
.set_r_extern(true);
1541 externalReloc
.set_r_type(GENERIC_RELOC_VANILLA
);
1542 fExternalRelocs
.push_back(externalReloc
);
1544 else if ( slideable
) {
1545 // if this is a dylib/bundle, need fix-up encoded as an internal relocation
1546 macho_relocation_info internalReloc
;
1547 SectionInfo
* sectInfo
= (SectionInfo
*)ref
->getTarget().getSection();
1548 uint32_t sectionNum
= sectInfo
->getIndex();
1549 // special case _mh_dylib_header and friends which are not in any real section
1550 if ( (sectionNum
==0) && sectInfo
->fVirtualSection
&& (strcmp(sectInfo
->fSectionName
, "._mach_header") == 0) )
1552 internalReloc
.set_r_address(atom
->getAddress()+ref
->getFixUpOffset()-fOptions
.baseAddress());
1553 internalReloc
.set_r_symbolnum(sectionNum
);
1554 internalReloc
.set_r_pcrel(false);
1555 internalReloc
.set_r_length(macho_relocation_info::pointer_length
);
1556 internalReloc
.set_r_extern(false);
1557 internalReloc
.set_r_type(GENERIC_RELOC_VANILLA
);
1558 fInternalRelocs
.push_back(internalReloc
);
1568 class ContentWriter
: public ObjectFile::ContentWriter
1571 ContentWriter(int fd
, uint64_t fileOffset
) : fFileDescriptor(fd
), fFileOffset(fileOffset
) {}
1572 virtual void write(uint64_t atomOffset
, const void* buffer
, uint64_t size
) {
1573 ::pwrite(fFileDescriptor
, buffer
, size
, fFileOffset
+atomOffset
);
1576 int fFileDescriptor
;
1577 uint64_t fFileOffset
;
1581 void Writer::writeAtoms()
1583 const bool requireAllFixUps
= (fOptions
.outputKind() != Options::kObjectFile
);
1585 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1586 const int segCount
= segmentInfos
.size();
1587 for(int i
=0; i
< segCount
; ++i
) {
1588 SegmentInfo
* curSegment
= segmentInfos
[i
];
1589 bool isText
= ((curSegment
->fInitProtection
& VM_PROT_EXECUTE
) != 0);
1590 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1591 const int sectionCount
= sectionInfos
.size();
1592 for(int j
=0; j
< sectionCount
; ++j
) {
1593 SectionInfo
* curSection
= sectionInfos
[j
];
1594 std::vector
<ObjectFile::Atom
*>& sectionAtoms
= curSection
->fAtoms
;
1595 //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
1596 if ( ! curSection
->fAllZeroFill
) {
1597 const int atomCount
= sectionAtoms
.size();
1598 uint32_t end
= curSection
->fFileOffset
;
1599 for (int k
=0; k
< atomCount
; ++k
) {
1600 ObjectFile::Atom
* atom
= sectionAtoms
[k
];
1601 if ( !atom
->isImportProxy() ) {
1602 uint32_t offset
= curSection
->fFileOffset
+ atom
->getSectionOffset();
1603 if ( isText
&& (offset
!= end
) ) {
1604 // fill gaps with no-ops
1605 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1607 OSWriteBigInt32(&ppcNop
, 0, 0x60000000);
1608 for (uint32_t p
=end
; p
< offset
; p
+= 4)
1609 ::pwrite(fFileDescriptor
, &ppcNop
, 4, p
);
1610 #else defined(ARCH_I386)
1611 uint8_t x86Nop
= 0x90;
1612 for (uint32_t p
=end
; p
< offset
; ++p
)
1613 ::pwrite(fFileDescriptor
, &x86Nop
, 1, p
);
1616 ContentWriter
writer(fFileDescriptor
, offset
);
1617 atom
->writeContent(requireAllFixUps
, writer
);
1618 end
= offset
+atom
->getSize();
1619 //printf("wrote 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
1628 void Writer::partitionIntoSections()
1630 const bool oneSegmentCommand
= (fOptions
.outputKind() == Options::kObjectFile
);
1632 // for every atom, set its sectionInfo object and section offset
1633 // build up fSegmentInfos along the way
1634 ObjectFile::Section
* curSection
= NULL
;
1635 SectionInfo
* currentSectionInfo
= NULL
;
1636 SegmentInfo
* currentSegmentInfo
= NULL
;
1637 unsigned int sectionIndex
= 1;
1638 for (unsigned int i
=0; i
< fAllAtoms
->size(); ++i
) {
1639 ObjectFile::Atom
* atom
= (*fAllAtoms
)[i
];
1640 if ( atom
->getSection() != curSection
) {
1641 if ( oneSegmentCommand
) {
1642 if ( currentSegmentInfo
== NULL
) {
1643 currentSegmentInfo
= new SegmentInfo();
1644 currentSegmentInfo
->fInitProtection
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1645 currentSegmentInfo
->fMaxProtection
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1646 this->fSegmentInfos
.push_back(currentSegmentInfo
);
1648 currentSectionInfo
= new SectionInfo();
1649 strcpy(currentSectionInfo
->fSectionName
, atom
->getSectionName());
1650 strcpy(currentSectionInfo
->fSegmentName
, atom
->getSegment().getName());
1651 currentSectionInfo
->fAlignment
= atom
->getAlignment();
1652 currentSectionInfo
->fAllZeroFill
= atom
->isZeroFill();
1653 currentSectionInfo
->fVirtualSection
= ( currentSectionInfo
->fSectionName
[0] == '.');
1654 if ( !currentSectionInfo
->fVirtualSection
|| fEmitVirtualSections
)
1655 currentSectionInfo
->setIndex(sectionIndex
++);
1656 currentSegmentInfo
->fSections
.push_back(currentSectionInfo
);
1659 if ( (currentSegmentInfo
== NULL
) || (strcmp(currentSegmentInfo
->fName
, atom
->getSegment().getName()) != 0) ) {
1660 currentSegmentInfo
= new SegmentInfo();
1661 strcpy(currentSegmentInfo
->fName
, atom
->getSegment().getName());
1662 uint32_t initprot
= 0;
1663 if ( atom
->getSegment().isContentReadable() )
1664 initprot
|= VM_PROT_READ
;
1665 if ( atom
->getSegment().isContentWritable() )
1666 initprot
|= VM_PROT_WRITE
;
1667 if ( atom
->getSegment().isContentExecutable() )
1668 initprot
|= VM_PROT_EXECUTE
;
1669 currentSegmentInfo
->fInitProtection
= initprot
;
1670 if ( initprot
== 0 )
1671 currentSegmentInfo
->fMaxProtection
= 0; // pagezero should have maxprot==initprot==0
1673 currentSegmentInfo
->fMaxProtection
= VM_PROT_READ
| VM_PROT_WRITE
| VM_PROT_EXECUTE
;
1674 currentSegmentInfo
->fBaseAddress
= atom
->getSegment().getBaseAddress();
1675 this->fSegmentInfos
.push_back(currentSegmentInfo
);
1677 currentSectionInfo
= new SectionInfo();
1678 strcpy(currentSectionInfo
->fSectionName
, atom
->getSectionName());
1679 strcpy(currentSectionInfo
->fSegmentName
, atom
->getSegment().getName());
1680 currentSectionInfo
->fAlignment
= atom
->getAlignment();
1681 // check for -sectalign override
1682 std::vector
<Options::SectionAlignment
>& alignmentOverrides
= fOptions
.sectionAlignments();
1683 for(std::vector
<Options::SectionAlignment
>::iterator it
=alignmentOverrides
.begin(); it
!= alignmentOverrides
.end(); ++it
) {
1684 if ( (strcmp(it
->segmentName
, currentSectionInfo
->fSegmentName
) == 0) && (strcmp(it
->sectionName
, currentSectionInfo
->fSectionName
) == 0) )
1685 currentSectionInfo
->fAlignment
= it
->alignment
;
1687 currentSectionInfo
->fAllZeroFill
= atom
->isZeroFill();
1688 currentSectionInfo
->fVirtualSection
= ( currentSectionInfo
->fSectionName
[0] == '.');
1689 if ( !currentSectionInfo
->fVirtualSection
|| fEmitVirtualSections
)
1690 currentSectionInfo
->setIndex(sectionIndex
++);
1691 currentSegmentInfo
->fSections
.push_back(currentSectionInfo
);
1693 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__TEXT") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "._load_commands") == 0) ) {
1694 fLoadCommandsSection
= currentSectionInfo
;
1695 fLoadCommandsSegment
= currentSegmentInfo
;
1697 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__DATA") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "__la_symbol_ptr") == 0) )
1698 currentSectionInfo
->fAllLazyPointers
= true;
1699 if ( (strcmp(currentSectionInfo
->fSegmentName
, "__DATA") == 0) && (strcmp(currentSectionInfo
->fSectionName
, "__nl_symbol_ptr") == 0) )
1700 currentSectionInfo
->fAllNonLazyPointers
= true;
1701 curSection
= atom
->getSection();
1703 // any non-zero fill atoms make whole section marked not-zero-fill
1704 if ( currentSectionInfo
->fAllZeroFill
&& ! atom
->isZeroFill() )
1705 currentSectionInfo
->fAllZeroFill
= false;
1706 // change section object to be Writer's SectionInfo object
1707 atom
->setSection(currentSectionInfo
);
1708 // section alignment is that of a contained atom with the greatest alignment
1709 uint8_t atomAlign
= atom
->getAlignment();
1710 if ( currentSectionInfo
->fAlignment
< atomAlign
)
1711 currentSectionInfo
->fAlignment
= atomAlign
;
1712 // calculate section offset for this atom
1713 uint64_t offset
= currentSectionInfo
->fSize
;
1714 uint64_t alignment
= 1 << atomAlign
;
1715 offset
= ( (offset
+alignment
-1) & (-alignment
) );
1716 atom
->setSectionOffset(offset
);
1717 currentSectionInfo
->fSize
= offset
+ atom
->getSize();
1718 // add atom to section vector
1719 currentSectionInfo
->fAtoms
.push_back(atom
);
1724 void Writer::adjustLoadCommandsAndPadding()
1726 fSegmentCommands
->computeSize();
1728 // recompute load command section offsets
1729 uint64_t offset
= 0;
1730 std::vector
<class ObjectFile::Atom
*>& loadCommandAtoms
= fLoadCommandsSection
->fAtoms
;
1731 const unsigned int atomCount
= loadCommandAtoms
.size();
1732 for (unsigned int i
=0; i
< atomCount
; ++i
) {
1733 ObjectFile::Atom
* atom
= loadCommandAtoms
[i
];
1734 uint64_t alignment
= 1 << atom
->getAlignment();
1735 offset
= ( (offset
+alignment
-1) & (-alignment
) );
1736 atom
->setSectionOffset(offset
);
1737 offset
+= atom
->getSize();
1738 fLoadCommandsSection
->fSize
= offset
;
1741 std::vector
<SectionInfo
*>& sectionInfos
= fLoadCommandsSegment
->fSections
;
1742 const int sectionCount
= sectionInfos
.size();
1743 uint64_t paddingSize
= 0;
1744 if ( fOptions
.outputKind() == Options::kDyld
) {
1745 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
1746 uint32_t totalSizeOfHeaderAndLoadCommands
= 0;
1747 for(int j
=0; j
< sectionCount
; ++j
) {
1748 SectionInfo
* curSection
= sectionInfos
[j
];
1749 totalSizeOfHeaderAndLoadCommands
+= curSection
->fSize
;
1750 if ( strcmp(curSection
->fSectionName
, fHeaderPadding
->getSectionName()) == 0 )
1753 paddingSize
= 4096 - (totalSizeOfHeaderAndLoadCommands
% 4096);
1756 // calculate max padding to keep segment size same, but all free space at end of load commands
1757 uint64_t totalSize
= 0;
1758 uint64_t worstCaseAlignmentPadding
= 0;
1759 for(int j
=0; j
< sectionCount
; ++j
) {
1760 SectionInfo
* curSection
= sectionInfos
[j
];
1761 totalSize
+= curSection
->fSize
;
1762 if ( j
!= 0 ) // don't count aligment of mach_header which is page-aligned
1763 worstCaseAlignmentPadding
+= (1 << curSection
->fAlignment
) - 1;
1765 uint64_t segmentSize
= ((totalSize
+worstCaseAlignmentPadding
+4095) & (-4096));
1766 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
1767 paddingSize
= segmentSize
- totalSize
;
1769 // if command line requires more padding than this
1770 if ( paddingSize
< fOptions
.minimumHeaderPad() ) {
1771 int extraPages
= (fOptions
.minimumHeaderPad() - paddingSize
+ 4095)/4096;
1772 paddingSize
+= extraPages
* 4096;
1776 // adjust atom size and update section size
1777 fHeaderPadding
->setSize(paddingSize
);
1778 for(int j
=0; j
< sectionCount
; ++j
) {
1779 SectionInfo
* curSection
= sectionInfos
[j
];
1780 if ( strcmp(curSection
->fSectionName
, fHeaderPadding
->getSectionName()) == 0 )
1781 curSection
->fSize
= paddingSize
;
1785 // assign file offsets and logical address to all segments
1786 void Writer::assignFileOffsets()
1788 bool haveFixedSegments
= false;
1789 uint64_t fileOffset
= 0;
1790 uint64_t nextContiguousAddress
= fOptions
.baseAddress();
1791 std::vector
<SegmentInfo
*>& segmentInfos
= fSegmentInfos
;
1792 const int segCount
= segmentInfos
.size();
1793 for(int i
=0; i
< segCount
; ++i
) {
1794 SegmentInfo
* curSegment
= segmentInfos
[i
];
1795 fileOffset
= (fileOffset
+4095) & (-4096);
1796 curSegment
->fFileOffset
= fileOffset
;
1797 if ( curSegment
->fBaseAddress
== 0 ) {
1798 // segment has uses next address
1799 curSegment
->fBaseAddress
= nextContiguousAddress
;
1802 // segment has fixed address
1803 haveFixedSegments
= true;
1805 uint64_t address
= curSegment
->fBaseAddress
;
1806 std::vector
<SectionInfo
*>& sectionInfos
= curSegment
->fSections
;
1807 const int sectionCount
= sectionInfos
.size();
1808 for(int j
=0; j
< sectionCount
; ++j
) {
1809 SectionInfo
* curSection
= sectionInfos
[j
];
1810 uint64_t alignment
= 1 << curSection
->fAlignment
;
1811 fileOffset
= ( (fileOffset
+alignment
-1) & (-alignment
) );
1812 address
= ( (address
+alignment
-1) & (-alignment
) );
1813 curSection
->fFileOffset
= fileOffset
;
1814 curSection
->setBaseAddress(address
);
1815 //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address);
1816 curSegment
->fSize
= curSection
->getBaseAddress() + curSection
->fSize
- curSegment
->fBaseAddress
;
1817 if ( (fOptions
.outputKind() != Options::kObjectFile
) || ! curSection
->fVirtualSection
)
1818 address
+= curSection
->fSize
;
1819 if ( !curSection
->fAllZeroFill
) {
1820 curSegment
->fFileSize
= curSegment
->fSize
;
1821 fileOffset
+= curSection
->fSize
;
1824 if ( curSegment
->fBaseAddress
== nextContiguousAddress
)
1825 nextContiguousAddress
= (curSegment
->fBaseAddress
+curSegment
->fSize
+4095) & (-4096);
1828 // check for segment overlaps
1829 if ( haveFixedSegments
) {
1830 for(int i
=0; i
< segCount
; ++i
) {
1831 SegmentInfo
* segment1
= segmentInfos
[i
];
1832 for(int j
=0; j
< segCount
; ++j
) {
1834 SegmentInfo
* segment2
= segmentInfos
[j
];
1835 if ( segment1
->fBaseAddress
< segment2
->fBaseAddress
) {
1836 if ( (segment1
->fBaseAddress
+segment1
->fSize
) > segment2
->fBaseAddress
)
1837 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
1838 segment1
->fName
, segment1
->fBaseAddress
, segment1
->fSize
, segment2
->fName
, segment2
->fBaseAddress
, segment2
->fSize
);
1840 else if ( segment1
->fBaseAddress
> segment2
->fBaseAddress
) {
1841 if ( (segment2
->fBaseAddress
+segment2
->fSize
) > segment1
->fBaseAddress
)
1842 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
1843 segment1
->fName
, segment1
->fBaseAddress
, segment1
->fSize
, segment2
->fName
, segment2
->fBaseAddress
, segment2
->fSize
);
1846 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
1847 segment1
->fName
, segment1
->fBaseAddress
, segment1
->fSize
, segment2
->fName
, segment2
->fBaseAddress
, segment2
->fSize
);
1855 void Writer::adjustLinkEditSections()
1857 // link edit content is always in last segment
1858 SegmentInfo
* lastSeg
= fSegmentInfos
[fSegmentInfos
.size()-1];
1859 unsigned int firstLinkEditSectionIndex
= 0;
1860 while ( strcmp(lastSeg
->fSections
[firstLinkEditSectionIndex
]->fSegmentName
, "__LINKEDIT") != 0 )
1861 ++firstLinkEditSectionIndex
;
1863 const unsigned int sectionCount
= lastSeg
->fSections
.size();
1864 uint64_t fileOffset
= lastSeg
->fSections
[firstLinkEditSectionIndex
]->fFileOffset
;
1865 uint64_t address
= lastSeg
->fSections
[firstLinkEditSectionIndex
]->getBaseAddress();
1866 for (unsigned int i
=firstLinkEditSectionIndex
; i
< sectionCount
; ++i
) {
1867 std::vector
<class ObjectFile::Atom
*>& atoms
= lastSeg
->fSections
[i
]->fAtoms
;
1868 const unsigned int atomCount
= atoms
.size();
1869 uint64_t sectionOffset
= 0;
1870 lastSeg
->fSections
[i
]->fFileOffset
= fileOffset
;
1871 lastSeg
->fSections
[i
]->setBaseAddress(address
);
1872 for (unsigned int j
=0; j
< atomCount
; ++j
) {
1873 ObjectFile::Atom
* atom
= atoms
[j
];
1874 uint64_t alignment
= 1 << atom
->getAlignment();
1875 sectionOffset
= ( (sectionOffset
+alignment
-1) & (-alignment
) );
1876 atom
->setSectionOffset(sectionOffset
);
1877 sectionOffset
+= atom
->getSize();
1879 lastSeg
->fSections
[i
]->fSize
= sectionOffset
;
1880 fileOffset
+= sectionOffset
;
1881 address
+= sectionOffset
;
1883 if ( fOptions
.outputKind() == Options::kObjectFile
) {
1885 //lastSeg->fBaseAddress = 0;
1886 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
1887 //lastSeg->fFileOffset = 0;
1888 //lastSeg->fFileSize =
1891 lastSeg
->fFileSize
= fileOffset
- lastSeg
->fFileOffset
;
1892 lastSeg
->fSize
= address
- lastSeg
->fBaseAddress
;
1897 ObjectFile::Atom::Scope
MachHeaderAtom::getScope() const
1899 switch ( fWriter
.fOptions
.outputKind() ) {
1900 case Options::kDynamicExecutable
:
1901 case Options::kStaticExecutable
:
1902 return ObjectFile::Atom::scopeGlobal
;
1903 case Options::kDynamicLibrary
:
1904 case Options::kDynamicBundle
:
1905 case Options::kDyld
:
1906 case Options::kObjectFile
:
1907 return ObjectFile::Atom::scopeLinkageUnit
;
1909 throw "unknown header type";
1912 bool MachHeaderAtom::dontStripName() const
1914 switch ( fWriter
.fOptions
.outputKind() ) {
1915 case Options::kDynamicExecutable
:
1916 case Options::kStaticExecutable
:
1918 case Options::kDynamicLibrary
:
1919 case Options::kDynamicBundle
:
1920 case Options::kDyld
:
1921 case Options::kObjectFile
:
1924 throw "unknown header type";
1927 const char* MachHeaderAtom::getName() const
1929 switch ( fWriter
.fOptions
.outputKind() ) {
1930 case Options::kDynamicExecutable
:
1931 case Options::kStaticExecutable
:
1932 return "__mh_execute_header";
1933 case Options::kDynamicLibrary
:
1934 return "__mh_dylib_header";
1935 case Options::kDynamicBundle
:
1936 return "__mh_bundle_header";
1937 case Options::kObjectFile
:
1939 case Options::kDyld
:
1940 return "__mh_dylinker_header";
1942 throw "unknown header type";
1945 const char* MachHeaderAtom::getDisplayName() const
1947 switch ( fWriter
.fOptions
.outputKind() ) {
1948 case Options::kDynamicExecutable
:
1949 case Options::kStaticExecutable
:
1950 case Options::kDynamicLibrary
:
1951 case Options::kDynamicBundle
:
1952 case Options::kDyld
:
1953 return this->getName();
1954 case Options::kObjectFile
:
1955 return "mach header";
1957 throw "unknown header type";
1960 uint64_t MachHeaderAtom::getSize() const
1962 return macho_header::size
;
1965 void MachHeaderAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
1970 uint32_t fileType
= 0;
1971 switch ( fWriter
.fOptions
.outputKind() ) {
1972 case Options::kDynamicExecutable
:
1973 case Options::kStaticExecutable
:
1974 fileType
= MH_EXECUTE
;
1976 case Options::kDynamicLibrary
:
1977 fileType
= MH_DYLIB
;
1979 case Options::kDynamicBundle
:
1980 fileType
= MH_BUNDLE
;
1982 case Options::kObjectFile
:
1983 fileType
= MH_OBJECT
;
1985 case Options::kDyld
:
1986 fileType
= MH_DYLINKER
;
1992 if ( fWriter
.fOptions
.outputKind() == Options::kObjectFile
) {
1993 flags
= MH_SUBSECTIONS_VIA_SYMBOLS
;
1996 flags
= MH_DYLDLINK
;
1997 if ( fWriter
.fOptions
.bindAtLoad() )
1998 flags
|= MH_BINDATLOAD
;
1999 switch ( fWriter
.fOptions
.nameSpace() ) {
2000 case Options::kTwoLevelNameSpace
:
2001 flags
|= MH_TWOLEVEL
| MH_NOUNDEFS
;
2003 case Options::kFlatNameSpace
:
2005 case Options::kForceFlatNameSpace
:
2006 flags
|= MH_FORCE_FLAT
;
2009 if ( fWriter
.fHasWeakExports
)
2010 flags
|= MH_WEAK_DEFINES
;
2011 if ( fWriter
.fReferencesWeakImports
|| fWriter
.fHasWeakExports
)
2012 flags
|= MH_BINDS_TO_WEAK
;
2015 // get commands info
2016 uint32_t commandsSize
= 0;
2017 uint32_t commandsCount
= 0;
2019 std::vector
<class ObjectFile::Atom
*>& loadCommandAtoms
= fWriter
.fLoadCommandsSection
->fAtoms
;
2020 const unsigned int atomCount
= loadCommandAtoms
.size();
2021 for (unsigned int i
=0; i
< atomCount
; ++i
) {
2022 ObjectFile::Atom
* atom
= loadCommandAtoms
[i
];
2023 commandsSize
+= atom
->getSize();
2024 // segment and symbol table atoms can contain more than one load command
2025 if ( atom
== fWriter
.fSegmentCommands
)
2026 commandsCount
+= fWriter
.fSegmentCommands
->commandCount();
2027 else if ( atom
== fWriter
.fSymbolTableCommands
)
2033 // fill out mach_header
2034 mh
.set_magic(macho_header::magic_value
);
2035 mh
.set_cputype(fWriter
.fOptions
.architecture());
2036 mh
.set_cpusubtype(0);
2037 mh
.set_filetype(fileType
);
2038 mh
.set_ncmds(commandsCount
);
2039 mh
.set_sizeofcmds(commandsSize
);
2040 mh
.set_flags(flags
);
2044 writer
.write(0, &mh
, macho_header::size
);
2048 CustomStackAtom::CustomStackAtom(Writer
& writer
)
2049 : WriterAtom(writer
, fgStackSegment
)
2051 #if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
2052 // stack grows down for these architectures
2053 fgStackSegment
.setBaseAddress(writer
.fOptions
.customStackAddr() - writer
.fOptions
.customStackSize());
2055 #error unknown architecture
2060 void SegmentLoadCommandsAtom::computeSize()
2063 std::vector
<Writer::SegmentInfo
*>& segmentInfos
= fWriter
.fSegmentInfos
;
2064 const int segCount
= segmentInfos
.size();
2065 for(int i
=0; i
< segCount
; ++i
) {
2066 size
+= macho_segment_command::size
;
2067 std::vector
<Writer::SectionInfo
*>& sectionInfos
= segmentInfos
[i
]->fSections
;
2068 const int sectionCount
= sectionInfos
.size();
2069 for(int j
=0; j
< sectionCount
; ++j
) {
2070 if ( fWriter
.fEmitVirtualSections
|| ! sectionInfos
[j
]->fVirtualSection
)
2071 size
+= macho_section::content_size
;
2075 fCommandCount
= segCount
;
2080 void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2082 uint64_t size
= this->getSize();
2083 uint8_t buffer
[size
];
2084 const bool oneSegment
=( fWriter
.fOptions
.outputKind() == Options::kObjectFile
);
2085 bzero(buffer
, fSize
);
2086 uint8_t* p
= buffer
;
2087 std::vector
<Writer::SegmentInfo
*>& segmentInfos
= fWriter
.fSegmentInfos
;
2088 const int segCount
= segmentInfos
.size();
2089 for(int i
=0; i
< segCount
; ++i
) {
2090 Writer::SegmentInfo
* segInfo
= segmentInfos
[i
];
2091 const int sectionCount
= segInfo
->fSections
.size();
2092 macho_segment_command
* cmd
= (macho_segment_command
*)p
;
2093 cmd
->set_cmd(macho_segment_command::command
);
2094 cmd
->set_segname(segInfo
->fName
);
2095 cmd
->set_vmaddr(segInfo
->fBaseAddress
);
2096 cmd
->set_vmsize(segInfo
->fSize
);
2097 cmd
->set_fileoff(segInfo
->fFileOffset
);
2098 cmd
->set_filesize(segInfo
->fFileSize
);
2099 cmd
->set_maxprot(segInfo
->fMaxProtection
);
2100 cmd
->set_initprot(segInfo
->fInitProtection
);
2101 // add sections array
2102 macho_section
* const sections
= (macho_section
*)&p
[macho_segment_command::size
];
2103 unsigned int sectionsEmitted
= 0;
2104 for (int j
=0; j
< sectionCount
; ++j
) {
2105 Writer::SectionInfo
* sectInfo
= segInfo
->fSections
[j
];
2106 if ( fWriter
.fEmitVirtualSections
|| !sectInfo
->fVirtualSection
) {
2107 macho_section
* sect
= §ions
[sectionsEmitted
++];
2109 // .o files have weird segment range
2110 if ( sectionsEmitted
== 1 ) {
2111 cmd
->set_vmaddr(sectInfo
->getBaseAddress());
2112 cmd
->set_fileoff(sectInfo
->fFileOffset
);
2113 cmd
->set_filesize(segInfo
->fFileSize
-sectInfo
->fFileOffset
);
2115 cmd
->set_vmsize(sectInfo
->getBaseAddress() + sectInfo
->fSize
);
2117 sect
->set_sectname(sectInfo
->fSectionName
);
2118 sect
->set_segname(sectInfo
->fSegmentName
);
2119 sect
->set_addr(sectInfo
->getBaseAddress());
2120 sect
->set_size(sectInfo
->fSize
);
2121 sect
->set_offset(sectInfo
->fFileOffset
);
2122 sect
->set_align(sectInfo
->fAlignment
);
2123 if ( sectInfo
->fRelocCount
!= 0 ) {
2124 sect
->set_reloff(sectInfo
->fRelocOffset
* macho_relocation_info::size
+ fWriter
.fLocalRelocationsAtom
->getFileOffset());
2125 sect
->set_nreloc(sectInfo
->fRelocCount
);
2127 if ( sectInfo
->fAllZeroFill
) {
2128 sect
->set_flags(S_ZEROFILL
);
2130 else if ( sectInfo
->fAllLazyPointers
) {
2131 sect
->set_flags(S_LAZY_SYMBOL_POINTERS
);
2132 sect
->set_reserved1(sectInfo
->fIndirectSymbolOffset
);
2134 else if ( sectInfo
->fAllNonLazyPointers
) {
2135 sect
->set_flags(S_NON_LAZY_SYMBOL_POINTERS
);
2136 sect
->set_reserved1(sectInfo
->fIndirectSymbolOffset
);
2138 else if ( (strcmp(sectInfo
->fSectionName
, "__mod_init_func") == 0) && (strcmp(sectInfo
->fSegmentName
, "__DATA") == 0) ) {
2139 sect
->set_flags(S_MOD_INIT_FUNC_POINTERS
);
2141 else if ( (strcmp(sectInfo
->fSectionName
, "__mod_term_func") == 0) && (strcmp(sectInfo
->fSegmentName
, "__DATA") == 0) ) {
2142 sect
->set_flags(S_MOD_TERM_FUNC_POINTERS
);
2146 p
= &p
[macho_segment_command::size
+ sectionsEmitted
*macho_section::content_size
];
2147 cmd
->set_cmdsize(macho_segment_command::size
+ sectionsEmitted
*macho_section::content_size
);
2148 cmd
->set_nsects(sectionsEmitted
);
2150 writer
.write(0, buffer
, size
);
2154 SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer
& writer
)
2155 : WriterAtom(writer
, fgTextSegment
)
2157 bzero(&fSymbolTable
, macho_symtab_command::size
);
2158 bzero(&fDynamicSymbolTable
, macho_dysymtab_command::size
);
2159 writer
.fSymbolTableCommands
= this;
2162 uint64_t SymbolTableLoadCommandsAtom::getSize() const
2164 return macho_symtab_command::size
+ macho_dysymtab_command::size
;
2167 void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2169 // build LC_DYSYMTAB command
2170 macho_symtab_command symbolTableCmd
;
2171 bzero(&symbolTableCmd
, macho_symtab_command::size
);
2172 symbolTableCmd
.set_cmd(LC_SYMTAB
);
2173 symbolTableCmd
.set_cmdsize(macho_symtab_command::size
);
2174 symbolTableCmd
.set_nsyms(fWriter
.fSymbolTableCount
);
2175 symbolTableCmd
.set_symoff(fWriter
.fSymbolTableAtom
->getFileOffset());
2176 symbolTableCmd
.set_stroff(fWriter
.fStringsAtom
->getFileOffset());
2177 symbolTableCmd
.set_strsize(fWriter
.fStringsAtom
->getSize());
2178 writer
.write(0, &symbolTableCmd
, macho_symtab_command::size
);
2180 // build LC_DYSYMTAB command
2181 macho_dysymtab_command dynamicSymbolTableCmd
;
2182 bzero(&dynamicSymbolTableCmd
, macho_dysymtab_command::size
);
2183 dynamicSymbolTableCmd
.set_cmd(LC_DYSYMTAB
);
2184 dynamicSymbolTableCmd
.set_cmdsize(macho_dysymtab_command::size
);
2185 dynamicSymbolTableCmd
.set_ilocalsym(fWriter
.fSymbolTableStabsStartIndex
);
2186 dynamicSymbolTableCmd
.set_nlocalsym(fWriter
.fSymbolTableStabsCount
+ fWriter
.fSymbolTableLocalCount
);
2187 dynamicSymbolTableCmd
.set_iextdefsym(fWriter
.fSymbolTableExportStartIndex
);
2188 dynamicSymbolTableCmd
.set_nextdefsym(fWriter
.fSymbolTableExportCount
);
2189 dynamicSymbolTableCmd
.set_iundefsym(fWriter
.fSymbolTableImportStartIndex
);
2190 dynamicSymbolTableCmd
.set_nundefsym(fWriter
.fSymbolTableImportCount
);
2191 dynamicSymbolTableCmd
.set_indirectsymoff(fWriter
.fIndirectTableAtom
->getFileOffset());
2192 dynamicSymbolTableCmd
.set_nindirectsyms(fWriter
.fIndirectSymbolTable
.size());
2193 if ( fWriter
.fOptions
.outputKind() != Options::kObjectFile
) {
2194 dynamicSymbolTableCmd
.set_extreloff((fWriter
.fExternalRelocs
.size()==0) ? 0 : fWriter
.fExternalRelocationsAtom
->getFileOffset());
2195 dynamicSymbolTableCmd
.set_nextrel(fWriter
.fExternalRelocs
.size());
2196 dynamicSymbolTableCmd
.set_locreloff((fWriter
.fInternalRelocs
.size()==0) ? 0 : fWriter
.fLocalRelocationsAtom
->getFileOffset());
2197 dynamicSymbolTableCmd
.set_nlocrel(fWriter
.fInternalRelocs
.size());
2199 writer
.write(macho_symtab_command::size
, &dynamicSymbolTableCmd
, macho_dysymtab_command::size
);
2202 uint64_t DyldLoadCommandsAtom::getSize() const
2204 uint32_t len
= macho_dylinker_command::name_offset
+ strlen("/usr/lib/dyld");
2205 len
= (len
+7) & (-8); // 8-byte align
2209 void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2211 uint64_t size
= this->getSize();
2212 uint8_t buffer
[size
];
2213 macho_dylinker_command
* cmd
= (macho_dylinker_command
*)buffer
;
2214 if ( fWriter
.fOptions
.outputKind() == Options::kDyld
)
2215 cmd
->set_cmd(LC_ID_DYLINKER
);
2217 cmd
->set_cmd(LC_LOAD_DYLINKER
);
2218 cmd
->set_cmdsize(this->getSize());
2219 cmd
->set_name_offset();
2220 strcpy((char*)&buffer
[macho_dylinker_command::name_offset
], "/usr/lib/dyld");
2221 writer
.write(0, buffer
, size
);
2226 uint64_t DylibLoadCommandsAtom::getSize() const
2228 const char* path
= fInfo
.reader
->getInstallPath();
2229 if ( fInfo
.options
.fInstallPathOverride
!= NULL
)
2230 path
= fInfo
.options
.fInstallPathOverride
;
2231 uint32_t len
= macho_dylib_command::name_offset
+ strlen(path
);
2232 len
= (len
+7) & (-8); // 8-byte align
2236 void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2238 uint64_t size
= this->getSize();
2239 uint8_t buffer
[size
];
2240 bzero(buffer
, size
);
2241 const char* path
= fInfo
.reader
->getInstallPath();
2242 if ( fInfo
.options
.fInstallPathOverride
!= NULL
)
2243 path
= fInfo
.options
.fInstallPathOverride
;
2244 macho_dylib_command
* cmd
= (macho_dylib_command
*)buffer
;
2245 if ( fInfo
.options
.fWeakImport
)
2246 cmd
->set_cmd(LC_LOAD_WEAK_DYLIB
);
2248 cmd
->set_cmd(LC_LOAD_DYLIB
);
2249 cmd
->set_cmdsize(this->getSize());
2250 cmd
->set_timestamp(fInfo
.reader
->getTimestamp());
2251 cmd
->set_current_version(fInfo
.reader
->getCurrentVersion());
2252 cmd
->set_compatibility_version(fInfo
.reader
->getCompatibilityVersion());
2253 cmd
->set_name_offset();
2254 strcpy((char*)&buffer
[macho_dylib_command::name_offset
], path
);
2255 writer
.write(0, buffer
, size
);
2260 uint64_t DylibIDLoadCommandsAtom::getSize() const
2262 uint32_t len
= macho_dylib_command::name_offset
+ strlen(fWriter
.fOptions
.installPath());
2263 len
= (len
+7) & (-8); // 8-byte align
2267 void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2269 struct timeval currentTime
= { 0 , 0 };
2270 gettimeofday(¤tTime
, NULL
);
2271 time_t timestamp
= currentTime
.tv_sec
;
2272 uint64_t size
= this->getSize();
2273 uint8_t buffer
[size
];
2274 bzero(buffer
, size
);
2275 macho_dylib_command
* cmd
= (macho_dylib_command
*)buffer
;
2276 cmd
->set_cmd(LC_ID_DYLIB
);
2277 cmd
->set_cmdsize(this->getSize());
2278 cmd
->set_name_offset();
2279 cmd
->set_timestamp(timestamp
);
2280 cmd
->set_current_version(fWriter
.fOptions
.currentVersion());
2281 cmd
->set_compatibility_version(fWriter
.fOptions
.compatibilityVersion());
2282 strcpy((char*)&buffer
[macho_dylib_command::name_offset
], fWriter
.fOptions
.installPath());
2283 writer
.write(0, buffer
, size
);
2287 uint64_t RoutinesLoadCommandsAtom::getSize() const
2289 return macho_routines_command::size
;
2292 void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2294 uint64_t initAddr
= fWriter
.getAtomLoadAddress(fWriter
.fEntryPoint
);
2295 uint8_t buffer
[macho_routines_command::size
];
2296 bzero(buffer
, macho_routines_command::size
);
2297 macho_routines_command
* cmd
= (macho_routines_command
*)buffer
;
2298 cmd
->set_cmd(macho_routines_command::command
);
2299 cmd
->set_cmdsize(this->getSize());
2300 cmd
->set_init_address(initAddr
);
2301 writer
.write(0, buffer
, macho_routines_command::size
);
2305 uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
2307 uint32_t len
= macho_sub_umbrella_command::name_offset
+ strlen(fName
);
2308 len
= (len
+7) & (-8); // 8-byte align
2312 void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2314 uint64_t size
= this->getSize();
2315 uint8_t buffer
[size
];
2316 bzero(buffer
, size
);
2317 macho_sub_umbrella_command
* cmd
= (macho_sub_umbrella_command
*)buffer
;
2318 cmd
->set_cmd(LC_SUB_UMBRELLA
);
2319 cmd
->set_cmdsize(this->getSize());
2320 cmd
->set_name_offset();
2321 strcpy((char*)&buffer
[macho_sub_umbrella_command::name_offset
], fName
);
2322 writer
.write(0, buffer
, size
);
2326 uint64_t SubLibraryLoadCommandsAtom::getSize() const
2328 uint32_t len
= macho_sub_library_command::name_offset
+ fNameLength
+ 1;
2329 len
= (len
+7) & (-8); // 8-byte align
2333 void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2335 uint64_t size
= this->getSize();
2336 uint8_t buffer
[size
];
2337 bzero(buffer
, size
);
2338 macho_sub_library_command
* cmd
= (macho_sub_library_command
*)buffer
;
2339 cmd
->set_cmd(LC_SUB_LIBRARY
);
2340 cmd
->set_cmdsize(this->getSize());
2341 cmd
->set_name_offset();
2342 strncpy((char*)&buffer
[macho_sub_library_command::name_offset
], fNameStart
, fNameLength
);
2343 buffer
[macho_sub_library_command::name_offset
+fNameLength
] = '\0';
2344 writer
.write(0, buffer
, size
);
2347 uint64_t UmbrellaLoadCommandsAtom::getSize() const
2349 uint32_t len
= macho_sub_framework_command::name_offset
+ strlen(fName
);
2350 len
= (len
+7) & (-8); // 8-byte align
2354 void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2356 uint64_t size
= this->getSize();
2357 uint8_t buffer
[size
];
2358 bzero(buffer
, size
);
2359 macho_sub_framework_command
* cmd
= (macho_sub_framework_command
*)buffer
;
2360 cmd
->set_cmd(LC_SUB_FRAMEWORK
);
2361 cmd
->set_cmdsize(this->getSize());
2362 cmd
->set_name_offset();
2363 strcpy((char*)&buffer
[macho_sub_framework_command::name_offset
], fName
);
2364 writer
.write(0, buffer
, size
);
2367 uint64_t ThreadsLoadCommandsAtom::getSize() const
2369 #if defined(ARCH_PPC)
2370 uint32_t stateSize
= 40; // PPC_THREAD_STATE_COUNT;
2371 #elif defined(ARCH_PPC64)
2372 uint32_t stateSize
= 76; // PPC_THREAD_STATE64_COUNT;
2373 #elif defined(ARCH_I386)
2374 uint32_t stateSize
= 16; // i386_THREAD_STATE_COUNT;
2376 #error unknown architecture
2378 return macho_thread_command::size
+ stateSize
*4;
2381 void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2383 uint64_t size
= this->getSize();
2384 uint8_t buffer
[size
];
2385 uint64_t start
= fWriter
.getAtomLoadAddress(fWriter
.fEntryPoint
);
2386 bzero(buffer
, size
);
2387 macho_thread_command
* cmd
= (macho_thread_command
*)buffer
;
2388 cmd
->set_cmd(LC_UNIXTHREAD
);
2389 cmd
->set_cmdsize(size
);
2390 #if defined(ARCH_PPC)
2391 cmd
->set_flavor(1); // PPC_THREAD_STATE
2392 cmd
->set_count(40); // PPC_THREAD_STATE_COUNT;
2393 cmd
->set_threadState32(0, start
);
2394 if ( fWriter
.fOptions
.hasCustomStack() )
2395 cmd
->set_threadState32(3, fWriter
.fOptions
.customStackAddr()); // r1
2396 #elif defined(ARCH_PPC64)
2397 cmd
->set_flavor(5); // PPC_THREAD_STATE64
2398 cmd
->set_count(76); // PPC_THREAD_STATE64_COUNT;
2399 cmd
->set_threadState64(0, start
);
2400 if ( fWriter
.fOptions
.hasCustomStack() )
2401 cmd
->set_threadState64(6, fWriter
.fOptions
.customStackAddr()); // r1
2402 #elif defined(ARCH_I386)
2403 cmd
->set_flavor(0xFFFFFFFF); // i386_THREAD_STATE
2404 cmd
->set_count(16); // i386_THREAD_STATE_COUNT;
2405 cmd
->set_threadState32(0, start
);
2406 if ( fWriter
.fOptions
.hasCustomStack() )
2407 cmd
->set_threadState32(15, fWriter
.fOptions
.customStackAddr()); // uesp
2409 #error unknown architecture
2411 writer
.write(0, buffer
, size
);
2416 uint64_t LoadCommandsPaddingAtom::getSize() const
2421 void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2423 uint8_t buffer
[fSize
];
2424 bzero(buffer
, fSize
);
2425 writer
.write(0, buffer
, fSize
);
2429 uint64_t LinkEditAtom::getFileOffset() const
2431 return ((Writer::SectionInfo
*)this->getSection())->fFileOffset
+ this->getSectionOffset();
2435 uint64_t LocalRelocationsLinkEditAtom::getSize() const
2437 return fWriter
.fInternalRelocs
.size() * macho_relocation_info::size
;
2440 void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2442 writer
.write(0, &fWriter
.fInternalRelocs
[0], this->getSize());
2447 uint64_t SymbolTableLinkEditAtom::getSize() const
2449 return fWriter
.fSymbolTableCount
* macho_nlist::size
;
2452 void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2454 writer
.write(0, fWriter
.fSymbolTable
, this->getSize());
2457 uint64_t ExternalRelocationsLinkEditAtom::getSize() const
2459 return fWriter
.fExternalRelocs
.size() * macho_relocation_info::size
;
2462 void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2464 writer
.write(0, &fWriter
.fExternalRelocs
[0], this->getSize());
2469 uint64_t IndirectTableLinkEditAtom::getSize() const
2471 return fWriter
.fIndirectSymbolTable
.size() * sizeof(uint32_t);
2474 void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2476 uint64_t size
= this->getSize();
2477 uint8_t buffer
[size
];
2478 bzero(buffer
, size
);
2479 const uint32_t indirectTableSize
= fWriter
.fIndirectSymbolTable
.size();
2480 uint32_t* indirectTable
= (uint32_t*)buffer
;
2481 for (uint32_t i
=0; i
< indirectTableSize
; ++i
) {
2482 Writer::IndirectEntry
& entry
= fWriter
.fIndirectSymbolTable
[i
];
2483 if ( entry
.indirectIndex
< indirectTableSize
) {
2484 ENDIAN_WRITE32(indirectTable
[entry
.indirectIndex
], entry
.symbolIndex
);
2487 throw "malformed indirect table";
2490 writer
.write(0, buffer
, size
);
2495 StringsLinkEditAtom::StringsLinkEditAtom(Writer
& writer
)
2496 : LinkEditAtom(writer
), fCurrentBuffer(NULL
), fCurrentBufferUsed(0)
2498 fCurrentBuffer
= new char[kBufferSize
];
2499 // burn first byte of string pool (so zero is never a valid string offset)
2500 fCurrentBuffer
[fCurrentBufferUsed
++] = ' ';
2501 // make offset 1 always point to an empty string
2502 fCurrentBuffer
[fCurrentBufferUsed
++] = '\0';
2505 uint64_t StringsLinkEditAtom::getSize() const
2507 return kBufferSize
* fFullBuffers
.size() + fCurrentBufferUsed
;
2510 void StringsLinkEditAtom::writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
& writer
) const
2512 uint64_t offset
= 0;
2513 for (unsigned int i
=0; i
< fFullBuffers
.size(); ++i
) {
2514 writer
.write(offset
, fFullBuffers
[i
], kBufferSize
);
2515 offset
+= kBufferSize
;
2517 writer
.write(offset
, fCurrentBuffer
, fCurrentBufferUsed
);
2520 int32_t StringsLinkEditAtom::add(const char* name
)
2522 int lenNeeded
= strlen(name
)+1;
2523 while ( lenNeeded
+ fCurrentBufferUsed
>= kBufferSize
) {
2524 // first part of string fits in current buffer
2525 int firstLen
= kBufferSize
- fCurrentBufferUsed
;
2526 memcpy(&fCurrentBuffer
[fCurrentBufferUsed
], name
, firstLen
);
2527 // alloc next buffer
2528 fFullBuffers
.push_back(fCurrentBuffer
);
2529 fCurrentBuffer
= new char[kBufferSize
];
2530 fCurrentBufferUsed
= 0;
2531 // advance name to second part
2533 lenNeeded
-= firstLen
;
2535 //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed);
2536 // string all fits in current buffer
2537 strcpy(&fCurrentBuffer
[fCurrentBufferUsed
], name
);
2538 int32_t offset
= kBufferSize
* fFullBuffers
.size() + fCurrentBufferUsed
;
2539 fCurrentBufferUsed
+= lenNeeded
;
2543 // returns the index of an empty string
2544 int32_t StringsLinkEditAtom::emptyString()