]> git.saurik.com Git - apple/ld64.git/blame - src/Writers/ExecutableFileMachO.cpp
ld64-26.0.81.tar.gz
[apple/ld64.git] / src / Writers / ExecutableFileMachO.cpp
CommitLineData
6e880c60
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
c2646906
A
3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26
27namespace ExecutableFileMachO {
28
29class Writer : public ExecutableFile::Writer
30{
31public:
32 Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
33 virtual ~Writer();
34
35 virtual const char* getPath();
36 virtual std::vector<class ObjectFile::Atom*>& getAtoms();
37 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
38 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
39
40 virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
41 virtual void write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom);
42
43private:
44 void assignFileOffsets();
45 void partitionIntoSections();
6e880c60 46 bool addBranchIslands();
c2646906
A
47 void adjustLoadCommandsAndPadding();
48 void createDynamicLinkerCommand();
49 void createDylibCommands();
50 void buildLinkEdit();
51 void writeAtoms();
52 void collectExportedAndImportedAndLocalAtoms();
53 void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
54 void buildSymbolTable();
55 void setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
56 void setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
57 void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
58 uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
59 uint8_t ordinalForLibrary(ObjectFile::Reader* file);
60 bool shouldExport(ObjectFile::Atom& atom);
61 void buildFixups();
62 void adjustLinkEditSections();
63 void buildObjectFileFixups();
64 void buildExecutableFixups();
65 uint32_t symbolIndex(ObjectFile::Atom& atom);
66 uint32_t addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
67 unsigned int collectStabs();
68 macho_uintptr_t valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom);
69 void addStabs(uint32_t startIndex, uint32_t count);
70
71
72 class SectionInfo : public ObjectFile::Section {
73 public:
74 SectionInfo();
75 void setIndex(unsigned int index) { fIndex=index; }
76 std::vector<ObjectFile::Atom*> fAtoms;
77 char fSegmentName[20];
78 char fSectionName[20];
79 uint64_t fFileOffset;
80 uint64_t fSize;
81 uint32_t fRelocCount;
82 uint32_t fRelocOffset;
83 uint32_t fIndirectSymbolOffset;
84 uint8_t fAlignment;
85 bool fAllLazyPointers;
86 bool fAllNonLazyPointers;
87 bool fAllZeroFill;
88 bool fVirtualSection;
89 };
90
91 class SegmentInfo
92 {
93 public:
94 SegmentInfo();
95 std::vector<class SectionInfo*> fSections;
96 char fName[20];
97 uint32_t fInitProtection;
98 uint32_t fMaxProtection;
99 uint64_t fFileOffset;
100 uint64_t fFileSize;
101 uint64_t fBaseAddress;
102 uint64_t fSize;
6e880c60 103 bool fFixedAddress;
c2646906
A
104 };
105
106
107 struct DirectLibrary {
108 class ObjectFile::Reader* fLibrary;
109 bool fWeak;
110 bool fReExport;
111 };
112
113 struct IndirectEntry {
114 uint32_t indirectIndex;
115 uint32_t symbolIndex;
116 };
117
118 struct StabChunks {
119 ObjectFile::Atom* fAtom;
120 ObjectFile::Reader* fReader;
6e880c60 121 unsigned int fReaderOrder;
c2646906
A
122 unsigned int fOrderInReader;
123 std::vector<ObjectFile::StabsInfo>* fStabs;
124 };
125
126 static bool stabChunkCompare(const StabChunks& lhs, const StabChunks& rhs);
127
128 friend class WriterAtom;
129 friend class PageZeroAtom;
130 friend class CustomStackAtom;
131 friend class MachHeaderAtom;
132 friend class SegmentLoadCommandsAtom;
133 friend class SymbolTableLoadCommandsAtom;
134 friend class ThreadsLoadCommandsAtom;
135 friend class DylibIDLoadCommandsAtom;
136 friend class RoutinesLoadCommandsAtom;
137 friend class DyldLoadCommandsAtom;
138 friend class LinkEditAtom;
139 friend class LocalRelocationsLinkEditAtom;
140 friend class ExternalRelocationsLinkEditAtom;
141 friend class SymbolTableLinkEditAtom;
142 friend class IndirectTableLinkEditAtom;
143 friend class StringsLinkEditAtom;
144
145 const char* fFilePath;
146 Options& fOptions;
147 int fFileDescriptor;
148 std::vector<class ObjectFile::Atom*>* fAllAtoms;
149 class SectionInfo* fLoadCommandsSection;
150 class SegmentInfo* fLoadCommandsSegment;
151 class SegmentLoadCommandsAtom* fSegmentCommands;
152 class SymbolTableLoadCommandsAtom* fSymbolTableCommands;
153 class LoadCommandsPaddingAtom* fHeaderPadding;
154 std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
155 std::vector<SegmentInfo*> fSegmentInfos;
156 class ObjectFile::Atom* fEntryPoint;
157 std::vector<DirectLibrary> fDirectLibraries;
158 std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
159 std::vector<StabChunks> fStabChunks;
160 std::vector<class ObjectFile::Atom*> fExportedAtoms;
161 std::vector<class ObjectFile::Atom*> fImportedAtoms;
162 std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
163 LocalRelocationsLinkEditAtom* fLocalRelocationsAtom;
164 ExternalRelocationsLinkEditAtom* fExternalRelocationsAtom;
165 SymbolTableLinkEditAtom* fSymbolTableAtom;
166 IndirectTableLinkEditAtom* fIndirectTableAtom;
167 StringsLinkEditAtom* fStringsAtom;
168 macho_nlist* fSymbolTable;
169 //char* fStringPool;
170 //uint32_t fStringPoolUsed;
171 //uint32_t fStringPoolSize;
172 std::vector<macho_relocation_info> fInternalRelocs;
173 std::vector<macho_relocation_info> fExternalRelocs;
174 std::vector<IndirectEntry> fIndirectSymbolTable;
175 uint32_t fSymbolTableCount;
176 uint32_t fSymbolTableStabsCount;
177 uint32_t fSymbolTableStabsStartIndex;
178 uint32_t fSymbolTableLocalCount;
179 uint32_t fSymbolTableLocalStartIndex;
180 uint32_t fSymbolTableExportCount;
181 uint32_t fSymbolTableExportStartIndex;
182 uint32_t fSymbolTableImportCount;
183 uint32_t fSymbolTableImportStartIndex;
184 bool fEmitVirtualSections;
185 bool fHasWeakExports;
186 bool fReferencesWeakImports;
187};
188
189
190class WriterAtom : public ObjectFile::Atom
191{
192protected:
193 class Segment;
194public:
195 enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
196 WriterAtom(Writer& writer, class WriterAtom::Segment& segment) : fWriter(writer), fSegment(segment) {}
197
198 virtual ObjectFile::Reader* getFile() const { return &fWriter; }
199 virtual const char* getName() const { return NULL; }
200 virtual const char* getDisplayName() const { return this->getName(); }
201 virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
202 virtual bool isTentativeDefinition() const { return false; }
203 virtual bool isWeakDefinition() const { return false; }
204 virtual bool isCoalesableByName() const { return false; }
205 virtual bool isCoalesableByValue() const { return false; }
206 virtual bool isZeroFill() const { return false; }
207 virtual bool dontDeadStrip() const { return true; }
208 virtual bool dontStripName() const { return false; }
209 virtual bool isImportProxy() const { return false; }
210 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
211 virtual bool mustRemainInSection() const { return true; }
212 virtual ObjectFile::Segment& getSegment() const { return fSegment; }
213 virtual bool requiresFollowOnAtom() const { return false; }
214 virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
215 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
216 virtual uint8_t getAlignment() const { return 2; }
217 virtual WeakImportSetting getImportWeakness() const { return Atom::kWeakUnset; }
218 virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
219 virtual void setScope(Scope) { }
220 virtual void setImportWeakness(bool weakImport) { }
221
222
223protected:
224 virtual ~WriterAtom() {}
225
226 class Segment : public ObjectFile::Segment
227 {
228 public:
6e880c60
A
229 Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
230 : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
c2646906
A
231 virtual const char* getName() const { return fName; }
232 virtual bool isContentReadable() const { return fReadable; }
233 virtual bool isContentWritable() const { return fWritable; }
234 virtual bool isContentExecutable() const { return fExecutable; }
6e880c60 235 virtual bool hasFixedAddress() const { return fFixedAddress; }
c2646906
A
236 private:
237 const char* fName;
238 const bool fReadable;
239 const bool fWritable;
240 const bool fExecutable;
6e880c60 241 const bool fFixedAddress;
c2646906
A
242 };
243
244 static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
245 static Segment fgTextSegment;
246 static Segment fgPageZeroSegment;
247 static Segment fgLinkEditSegment;
248 static Segment fgStackSegment;
249
250
251 Writer& fWriter;
252 Segment& fSegment;
253};
254
255
6e880c60
A
256WriterAtom::Segment WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
257WriterAtom::Segment WriterAtom::fgTextSegment("__TEXT", true, false, true, false);
258WriterAtom::Segment WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
259WriterAtom::Segment WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false, true);
c2646906
A
260std::vector<ObjectFile::Reference*> WriterAtom::fgEmptyReferenceList;
261
262class PageZeroAtom : public WriterAtom
263{
264public:
265 PageZeroAtom(Writer& writer) : WriterAtom(writer, fgPageZeroSegment) {}
266 virtual const char* getDisplayName() const { return "page zero content"; }
267 virtual bool isZeroFill() const { return true; }
268 virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); }
269 virtual const char* getSectionName() const { return "._zeropage"; }
270 virtual uint8_t getAlignment() const { return 12; }
271 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
272};
273
274class MachHeaderAtom : public WriterAtom
275{
276public:
277 MachHeaderAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
278 virtual const char* getName() const;
279 virtual const char* getDisplayName() const;
280 virtual Scope getScope() const;
281 virtual bool dontStripName() const;
282 virtual uint64_t getSize() const;
283 virtual uint8_t getAlignment() const { return 12; }
284 virtual const char* getSectionName() const { return "._mach_header"; }
285 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
286};
287
288class CustomStackAtom : public WriterAtom
289{
290public:
291 CustomStackAtom(Writer& writer);
292 virtual const char* getDisplayName() const { return "custom stack content"; }
293 virtual bool isZeroFill() const { return true; }
294 virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
295 virtual const char* getSectionName() const { return "._stack"; }
296 virtual uint8_t getAlignment() const { return 12; }
297 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
298};
299
300class SegmentLoadCommandsAtom : public WriterAtom
301{
302public:
303 SegmentLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment), fCommandCount(0), fSize(0) { writer.fSegmentCommands = this; }
304 virtual const char* getDisplayName() const { return "segment load commands"; }
305 virtual uint64_t getSize() const { return fSize; }
306 virtual uint8_t getAlignment() const { return 2; }
307 virtual const char* getSectionName() const { return "._load_commands"; }
308 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
309
310 void computeSize();
311 void setup();
312 unsigned int commandCount() { return fCommandCount; }
313 void assignFileOffsets();
314private:
315 unsigned int fCommandCount;
316 uint32_t fSize;
317};
318
319class SymbolTableLoadCommandsAtom : public WriterAtom
320{
321public:
322 SymbolTableLoadCommandsAtom(Writer&);
323 virtual const char* getDisplayName() const { return "symbol table load commands"; }
324 virtual uint64_t getSize() const;
325 virtual uint8_t getAlignment() const { return 2; }
326 virtual const char* getSectionName() const { return "._load_commands"; }
327 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
328
329private:
330 macho_symtab_command fSymbolTable;
331 macho_dysymtab_command fDynamicSymbolTable;
332};
333
334class ThreadsLoadCommandsAtom : public WriterAtom
335{
336public:
337 ThreadsLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
338 virtual const char* getDisplayName() const { return "thread load commands"; }
339 virtual uint64_t getSize() const;
340 virtual uint8_t getAlignment() const { return 2; }
341 virtual const char* getSectionName() const { return "._load_commands"; }
342 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
343private:
344 uint8_t* fBuffer;
345 uint32_t fBufferSize;
346};
347
348class DyldLoadCommandsAtom : public WriterAtom
349{
350public:
351 DyldLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
352 virtual const char* getDisplayName() const { return "dyld load command"; }
353 virtual uint64_t getSize() const;
354 virtual uint8_t getAlignment() const { return 2; }
355 virtual const char* getSectionName() const { return "._load_commands"; }
356 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
357};
358
359class DylibLoadCommandsAtom : public WriterAtom
360{
361public:
362 DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info) : WriterAtom(writer, fgTextSegment), fInfo(info) {}
363 virtual const char* getDisplayName() const { return "dylib load command"; }
364 virtual uint64_t getSize() const;
365 virtual uint8_t getAlignment() const { return 2; }
366 virtual const char* getSectionName() const { return "._load_commands"; }
367 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
368private:
369 ExecutableFile::DyLibUsed& fInfo;
370};
371
372class DylibIDLoadCommandsAtom : public WriterAtom
373{
374public:
375 DylibIDLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
376 virtual const char* getDisplayName() const { return "dylib ID load command"; }
377 virtual uint64_t getSize() const;
378 virtual uint8_t getAlignment() const { return 2; }
379 virtual const char* getSectionName() const { return "._load_commands"; }
380 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
381};
382
383class RoutinesLoadCommandsAtom : public WriterAtom
384{
385public:
386 RoutinesLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
387 virtual const char* getDisplayName() const { return "routines load command"; }
388 virtual uint64_t getSize() const;
389 virtual uint8_t getAlignment() const { return 2; }
390 virtual const char* getSectionName() const { return "._load_commands"; }
391 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
392};
393
394class SubUmbrellaLoadCommandsAtom : public WriterAtom
395{
396public:
397 SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name) : WriterAtom(writer, fgTextSegment), fName(name) {}
398 virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
399 virtual uint64_t getSize() const;
400 virtual uint8_t getAlignment() const { return 2; }
401 virtual const char* getSectionName() const { return "._load_commands"; }
402 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
403private:
404 const char* fName;
405};
406
407class SubLibraryLoadCommandsAtom : public WriterAtom
408{
409public:
410 SubLibraryLoadCommandsAtom(Writer& writer, const char* nameStart, int nameLen)
411 : WriterAtom(writer, fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
412 virtual const char* getDisplayName() const { return "sub-library load command"; }
413 virtual uint64_t getSize() const;
414 virtual uint8_t getAlignment() const { return 2; }
415 virtual const char* getSectionName() const { return "._load_commands"; }
416 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
417private:
418 const char* fNameStart;
419 int fNameLength;
420};
421
422class UmbrellaLoadCommandsAtom : public WriterAtom
423{
424public:
425 UmbrellaLoadCommandsAtom(Writer& writer, const char* name)
426 : WriterAtom(writer, fgTextSegment), fName(name) {}
427 virtual const char* getDisplayName() const { return "umbrella load command"; }
428 virtual uint64_t getSize() const;
429 virtual uint8_t getAlignment() const { return 2; }
430 virtual const char* getSectionName() const { return "._load_commands"; }
431 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
432private:
433 const char* fName;
434};
435
436class LoadCommandsPaddingAtom : public WriterAtom
437{
438public:
439 LoadCommandsPaddingAtom(Writer& writer)
440 : WriterAtom(writer, fgTextSegment), fSize(0) {}
441 virtual const char* getDisplayName() const { return "header padding"; }
442 virtual uint64_t getSize() const;
443 virtual uint8_t getAlignment() const { return 2; }
444 virtual const char* getSectionName() const { return "._load_cmds_pad"; }
445 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
446
447 void setSize(uint64_t newSize) { fSize = newSize; }
448private:
449 uint64_t fSize;
450};
451
452class LinkEditAtom : public WriterAtom
453{
454public:
455 LinkEditAtom(Writer& writer) : WriterAtom(writer, fgLinkEditSegment) {}
456 uint64_t getFileOffset() const;
457};
458
459class LocalRelocationsLinkEditAtom : public LinkEditAtom
460{
461public:
462 LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
463 virtual const char* getDisplayName() const { return "local relocations"; }
464 virtual uint64_t getSize() const;
465 virtual uint8_t getAlignment() const { return 3; }
466 virtual const char* getSectionName() const { return "._local_relocs"; }
467 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
468};
469
470class SymbolTableLinkEditAtom : public LinkEditAtom
471{
472public:
473 SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
474 virtual const char* getDisplayName() const { return "symbol table"; }
475 virtual uint64_t getSize() const;
476 virtual uint8_t getAlignment() const { return 2; }
477 virtual const char* getSectionName() const { return "._symbol_table"; }
478 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
479};
480
481class ExternalRelocationsLinkEditAtom : public LinkEditAtom
482{
483public:
484 ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
485 virtual const char* getDisplayName() const { return "external relocations"; }
486 virtual uint64_t getSize() const;
487 virtual uint8_t getAlignment() const { return 3; }
488 virtual const char* getSectionName() const { return "._extern_relocs"; }
489 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
490};
491
492class IndirectTableLinkEditAtom : public LinkEditAtom
493{
494public:
495 IndirectTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
496 virtual const char* getDisplayName() const { return "indirect symbol table"; }
497 virtual uint64_t getSize() const;
498 virtual uint8_t getAlignment() const { return 2; }
499 virtual const char* getSectionName() const { return "._indirect_syms"; }
500 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
501};
502
503class StringsLinkEditAtom : public LinkEditAtom
504{
505public:
506 StringsLinkEditAtom(Writer& writer);
507 virtual const char* getDisplayName() const { return "string pool"; }
508 virtual uint64_t getSize() const;
509 virtual uint8_t getAlignment() const { return 2; }
510 virtual const char* getSectionName() const { return "._string_pool"; }
511 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
512
513 int32_t add(const char* name);
514 int32_t emptyString();
515
516private:
517 enum { kBufferSize = 0x01000000 };
518
519 std::vector<char*> fFullBuffers;
520 char* fCurrentBuffer;
521 uint32_t fCurrentBufferUsed;
522};
523
524
525
526class UndefinedSymbolProxyAtom : public WriterAtom
527{
528public:
529 UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, fgLinkEditSegment), fName(name), fWeakImportSetting(Atom::kWeakUnset) {}
530 virtual const char* getName() const { return fName; }
531 virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
532 virtual uint64_t getSize() const { return 0; }
533 virtual bool isWeakDefinition() const { return true; }
534 virtual bool isImportProxy() const { return true; }
535 virtual const char* getSectionName() const { return "._imports"; }
536 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
537 virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; }
538 virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
539private:
540 const char* fName;
541 WeakImportSetting fWeakImportSetting;
542};
543
6e880c60
A
544#if defined(ARCH_PPC) || defined(ARCH_PPC64)
545class BranchIslandAtom : public WriterAtom
546{
547public:
548 BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
549 virtual const char* getName() const { return fName; }
550 virtual Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
551 virtual uint64_t getSize() const { return 4; }
552 virtual const char* getSectionName() const { return "__text"; }
553 virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
554private:
555 const char* fName;
556 ObjectFile::Atom& fTarget;
557 uint32_t fTargetOffset;
558};
559#endif
c2646906
A
560
561struct ExportSorter
562{
563 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
564 {
565 return (strcmp(left->getName(), right->getName()) < 0);
566 }
567};
568
569
570ExecutableFile::Writer* MakeWriter(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
571{
572 return new Writer(path, options, dynamicLibraries);
573}
574
575Writer::SectionInfo::SectionInfo()
576 : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
577 fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
578{
579 fSegmentName[0] = '\0';
580 fSectionName[0] = '\0';
581}
582
583Writer::SegmentInfo::SegmentInfo()
6e880c60 584 : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0), fFixedAddress(false)
c2646906
A
585{
586 fName[0] = '\0';
587}
588
589
590Writer::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
591 : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
592 fLoadCommandsSegment(NULL),
593 //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0),
594 fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
595{
596 int permissions = 0777;
597 if ( fOptions.outputKind() == Options::kObjectFile )
598 permissions = 0666;
599 // Calling unlink first assures the file is gone so that open creates it with correct permissions
600 // It also handles the case where fFilePath file is not writeable but its directory is
601 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
602 (void)unlink(fFilePath);
603 fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
604 if ( fFileDescriptor == -1 ) {
605 throw "can't open file for writing";
606 }
607
608 switch ( fOptions.outputKind() ) {
609 case Options::kDynamicExecutable:
610 case Options::kStaticExecutable:
611 fWriterSynthesizedAtoms.push_back(new PageZeroAtom(*this));
612 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
613 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
614 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
615 if ( fOptions.outputKind() == Options::kDynamicExecutable )
616 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
617 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
618 if ( fOptions.hasCustomStack() )
619 fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*this));
620 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
621 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
622 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
623 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
624 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
625 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
626 break;
627 case Options::kDynamicLibrary:
628 case Options::kDynamicBundle:
629 case Options::kObjectFile:
630 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
631 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
632 if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
633 fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom(*this));
634 if ( fOptions.initFunctionName() != NULL )
635 fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom(*this));
636 }
637 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
638 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
639 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
640 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
641 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
642 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
643 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
644 break;
645 case Options::kDyld:
646 fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
647 fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
648 fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
649 fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
650 fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
651 fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
652 fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
653 fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
654 fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
655 fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
656 fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
657 break;
658 }
659
660 // add extra commmands
661 uint8_t ordinal = 1;
662 switch ( fOptions.outputKind() ) {
663 case Options::kDynamicExecutable:
664 case Options::kDynamicLibrary:
665 case Options::kDynamicBundle:
666 {
667 // add dylib load command atoms for all dynamic libraries
668 const unsigned int libCount = dynamicLibraries.size();
669 for (unsigned int i=0; i < libCount; ++i) {
670 ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
671 if ( dylibInfo.indirect ) {
672 // find ordinal of direct reader
673 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
674 bool found = false;
675 for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
676 if ( it->first == dylibInfo.directReader ) {
677 //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
678 fLibraryToOrdinal[dylibInfo.reader] = it->second;
679 found = true;
680 break;
681 }
682 }
683 if ( ! found )
684 fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
685 }
686 }
687 else {
688 // see if a DylibLoadCommandsAtom has already been created for this install path
689 bool newDylib = true;
690 const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
691 if ( dylibInfo.options.fInstallPathOverride != NULL )
692 dylibInstallPath = dylibInfo.options.fInstallPathOverride;
693 for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
694 ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
695 if ( !seenDylibInfo.indirect ) {
696 const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
697 if ( seenDylibInfo.options.fInstallPathOverride != NULL )
698 seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
699 if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
700 fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
701 newDylib = false;
702 break;
703 }
704 }
705 }
706
707 if ( newDylib ) {
708 // assign new ordinal and check for other paired load commands
709 fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
710 fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom(*this, dylibInfo));
711 if ( dylibInfo.options.fReExport ) {
712 // this dylib also needs a sub_x load command
713 bool isFrameworkReExport = false;
714 const char* lastSlash = strrchr(dylibInstallPath, '/');
715 if ( lastSlash != NULL ) {
716 char frameworkName[strlen(lastSlash)+20];
717 sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
718 isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
719 }
720 if ( isFrameworkReExport ) {
721 // needs a LC_SUB_UMBRELLA command
722 fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash[1]));
723 }
724 else {
725 // needs a LC_SUB_LIBRARY command
726 const char* nameStart = &lastSlash[1];
727 if ( lastSlash == NULL )
728 nameStart = dylibInstallPath;
729 int len = strlen(nameStart);
730 const char* dot = strchr(nameStart, '.');
731 if ( dot != NULL )
732 len = dot - nameStart;
733 fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart, len));
734 }
735 }
736 }
737 }
738 }
739 // add umbrella command if needed
740 if ( fOptions.umbrellaName() != NULL ) {
741 fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions.umbrellaName()));
742 }
743 }
744 break;
745 case Options::kStaticExecutable:
746 case Options::kObjectFile:
747 case Options::kDyld:
748 break;
749 }
750
751 //fprintf(stderr, "ordinals table:\n");
752 //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
753 // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
754 //}
755}
756
757Writer::~Writer()
758{
759 if ( fFilePath != NULL )
760 free((void*)fFilePath);
761 if ( fSymbolTable != NULL )
762 delete [] fSymbolTable;
763 //if ( fStringPool != NULL )
764 // delete [] fStringPool;
765}
766
767const char* Writer::getPath()
768{
769 return fFilePath;
770}
771
772
773std::vector<class ObjectFile::Atom*>& Writer::getAtoms()
774{
775 return fWriterSynthesizedAtoms;
776}
777
778std::vector<class ObjectFile::Atom*>* Writer::getJustInTimeAtomsFor(const char* name)
779{
780 return NULL;
781}
782
783std::vector<ObjectFile::StabsInfo>* Writer::getStabsDebugInfo()
784{
785 return NULL;
786}
787
788ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name)
789{
790 if ( (fOptions.outputKind() == Options::kObjectFile)
791 || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
792 return new UndefinedSymbolProxyAtom(*this, name);
793 else
794 return NULL;
795}
796
797uint8_t Writer::ordinalForLibrary(ObjectFile::Reader* lib)
798{
799 // flat namespace images use zero for all ordinals
800 if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
801 return 0;
802
803 // is an UndefinedSymbolProxyAtom
804 if ( lib == this )
805 if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
806 return DYNAMIC_LOOKUP_ORDINAL;
807
808 std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
809 if ( pos != fLibraryToOrdinal.end() )
810 return pos->second;
811
812 throw "can't find ordinal for imported symbol";
813}
814
815
816void Writer::write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom)
817{
818 fAllAtoms = &atoms;
819 fEntryPoint = entryPointAtom;
820
821 // create SegmentInfo and SectionInfo objects and assign all atoms to a section
822 partitionIntoSections();
823
824 // segment load command can now be sized and padding can be set
825 adjustLoadCommandsAndPadding();
826
827 // assign each section a file offset
828 assignFileOffsets();
829
6e880c60
A
830 // if need to add branch islands, reassign file offsets
831 if ( addBranchIslands() )
832 assignFileOffsets();
833
c2646906
A
834 // build symbol table and relocations
835 buildLinkEdit();
836
837 // write everything
838 writeAtoms();
839}
840
841void Writer::buildLinkEdit()
842{
843 this->collectExportedAndImportedAndLocalAtoms();
844 this->buildSymbolTable();
845 this->buildFixups();
846 this->adjustLinkEditSections();
847}
848
849
850
851uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom)
852{
853 return atom->getAddress();
854// SectionInfo* info = (SectionInfo*)atom->getSection();
855// return info->getBaseAddress() + atom->getSectionOffset();
856}
857
858void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
859{
860 // set n_type
861 entry->set_n_type(N_EXT | N_SECT);
862 if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) )
863 entry->set_n_type(N_EXT | N_SECT | N_PEXT);
864
865 // set n_sect (section number of implementation )
866 uint8_t sectionIndex = atom->getSection()->getIndex();
867 entry->set_n_sect(sectionIndex);
868
869 // the __mh_execute_header is magic and must be an absolute symbol
870 if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0) && atom->dontStripName())
871 entry->set_n_type(N_EXT | N_ABS);
872
873 // set n_desc
874 uint16_t desc = 0;
875 if ( atom->dontStripName() )
876 desc |= REFERENCED_DYNAMICALLY;
877 if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) {
878 desc |= N_WEAK_DEF;
879 fHasWeakExports = true;
880 }
881 entry->set_n_desc(desc);
882
883 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
884 entry->set_n_value(this->getAtomLoadAddress(atom));
885}
886
887void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
888{
889 // set n_type
890 entry->set_n_type(N_UNDF | N_EXT);
891
892 // set n_sect
893 entry->set_n_sect(0);
894
895 uint16_t desc = 0;
896 if ( fOptions.outputKind() != Options::kObjectFile ) {
897 // set n_desc ( high byte is library ordinal, low byte is reference type )
898 desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
899 try {
900 uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
901 SET_LIBRARY_ORDINAL(desc, ordinal);
902 }
903 catch (const char* msg) {
904 throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
905 }
906 }
907 if ( atom->dontStripName() )
908 desc |= REFERENCED_DYNAMICALLY;
909 // an import proxy is always weak (overridden by definition in .o files)
910 // so we ask its reader if the exported symbol in its dylib is weak
911 if ( ( fOptions.outputKind() != Options::kObjectFile) && atom->getFile()->isDefinitionWeak(*atom) ) {
912 desc |= N_REF_TO_WEAK;
913 fReferencesWeakImports = true;
914 }
915 // set weak_import attribute
916 if ( atom->getImportWeakness() == ObjectFile::Atom::kWeakImport )
917 desc |= N_WEAK_REF;
918 entry->set_n_desc(desc);
919
920 // set n_value, zero for import proxy and size for tentative definition
921 entry->set_n_value(atom->getSize());
922}
923
924void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
925{
926 // set n_type
927 uint8_t type = N_SECT;
928 if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
929 type |= N_PEXT;
930 entry->set_n_type(type);
931
932 // set n_sect (section number of implementation )
933 uint8_t sectIndex = atom->getSection()->getIndex();
934 if ( sectIndex == 0 ) {
935 // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
936 if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
937 sectIndex = 1;
938 }
939 entry->set_n_sect(sectIndex);
940
941 // set n_desc
942 uint16_t desc = 0;
943 if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) // commons on not weak
944 desc |= N_WEAK_DEF;
945 entry->set_n_desc(desc);
946
947 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
948 entry->set_n_value(this->getAtomLoadAddress(atom));
949}
950
951
952void Writer::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
953{
954 macho_nlist* entry = &fSymbolTable[startIndex];
955 for (uint32_t i=0; i < count; ++i, ++entry) {
956 ObjectFile::Atom* atom = atoms[i];
957 entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
958 if ( &atoms == &fExportedAtoms ) {
959 this->setExportNlist(atom, entry);
960 }
961 else if ( &atoms == &fImportedAtoms ) {
962 this->setImportNlist(atom, entry);
963 }
964 else {
965 this->setLocalNlist(atom, entry);
966 }
967 }
968}
969
970void Writer::buildSymbolTable()
971{
972 fSymbolTableStabsStartIndex = 0;
973 fSymbolTableStabsCount = this->collectStabs();
974 fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
975 fSymbolTableLocalCount = fLocalSymbolAtoms.size();
976 fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
977 fSymbolTableExportCount = fExportedAtoms.size();
978 fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
979 fSymbolTableImportCount = fImportedAtoms.size();
980
981 // allocate symbol table
982 fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
983 fSymbolTable = new macho_nlist[fSymbolTableCount];
984
985 // fill in symbol table and string pool (do stabs last so strings are at end of pool)
986 setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount);
987 setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
988 setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
989 addStabs(fSymbolTableStabsStartIndex, fSymbolTableStabsCount);
990}
991
992
993
994bool Writer::shouldExport(ObjectFile::Atom& atom)
995{
996 switch ( atom.getScope() ) {
997 case ObjectFile::Atom::scopeGlobal:
998 return true;
999 case ObjectFile::Atom::scopeLinkageUnit:
1000 return ( fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) );
1001 default:
1002 return false;
1003 }
1004}
1005
1006void Writer::collectExportedAndImportedAndLocalAtoms()
1007{
1008 const int atomCount = fAllAtoms->size();
1009 for (int i=0; i < atomCount; ++i) {
1010 ObjectFile::Atom* atom = (*fAllAtoms)[i];
1011 // only named atoms go in symbol table
1012 if ( atom->getName() != NULL ) {
1013 // put atom into correct bucket: imports, exports, locals
1014 //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
1015 if ( atom->isImportProxy() || ((fOptions.outputKind() == Options::kObjectFile) && (strcmp(atom->getSectionName(), "__common") == 0)) )
1016 fImportedAtoms.push_back(atom);
1017 else if ( this->shouldExport(*atom) )
1018 fExportedAtoms.push_back(atom);
1019 else if ( !fOptions.stripLocalSymbols() )
1020 fLocalSymbolAtoms.push_back(atom);
1021 }
1022 }
1023
1024 // sort exported atoms by name
1025 std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
1026}
1027
1028
1029bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs)
1030{
1031 if ( lhs.fReader != rhs.fReader ) {
6e880c60 1032 return lhs.fReaderOrder < rhs.fReaderOrder;
c2646906
A
1033 }
1034 return lhs.fOrderInReader < rhs.fOrderInReader;
1035}
1036
1037unsigned int Writer::collectStabs()
1038{
1039 unsigned int count = 0;
1040
1041 // collect all stabs chunks
1042 std::set<ObjectFile::Reader*> seenReaders;
6e880c60 1043 std::map<ObjectFile::Reader*, unsigned int> readerOrdinals;
c2646906
A
1044 const int atomCount = fAllAtoms->size();
1045 for (int i=0; i < atomCount; ++i) {
1046 ObjectFile::Atom* atom = (*fAllAtoms)[i];
1047 ObjectFile::Reader* atomsReader = atom->getFile();
6e880c60
A
1048 unsigned int readerOrder = 0;
1049 if ( atomsReader != NULL ) {
1050 std::map<ObjectFile::Reader*, unsigned int>::iterator pos = readerOrdinals.find(atomsReader);
1051 if ( pos == readerOrdinals.end() ) {
1052 readerOrder = readerOrdinals.size();
1053 readerOrdinals[atomsReader] = readerOrder;
1054 std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
1055 if ( readerStabs != NULL ) {
1056 StabChunks chunk;
1057 chunk.fAtom = NULL;
1058 chunk.fReader = atomsReader;
1059 chunk.fReaderOrder = readerOrder;
1060 chunk.fOrderInReader = 0;
1061 chunk.fStabs = readerStabs;
1062 fStabChunks.push_back(chunk);
1063 count += readerStabs->size() + 1; // extra one is for trailing N_SO
1064 }
c2646906 1065 }
6e880c60
A
1066 else {
1067 readerOrder = pos->second;
1068 }
1069 }
c2646906
A
1070 std::vector<ObjectFile::StabsInfo>* atomStabs = atom->getStabsDebugInfo();
1071 if ( atomStabs != NULL ) {
1072 StabChunks chunk;
1073 chunk.fAtom = atom;
1074 chunk.fReader = atomsReader;
6e880c60 1075 chunk.fReaderOrder = readerOrder;
c2646906
A
1076 chunk.fOrderInReader = atom->getSortOrder();
1077 chunk.fStabs = atomStabs;
1078 fStabChunks.push_back(chunk);
1079 count += atomStabs->size();
1080 }
1081 }
1082
6e880c60 1083 // sort stabs: group by .o file
c2646906
A
1084 std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare);
1085
6e880c60
A
1086 //fprintf(stderr, "Sorted stabs:\n");
1087 //for (std::vector<StabChunks>::iterator it=fStabChunks.begin(); it != fStabChunks.end(); it++) {
1088 // ObjectFile::Atom* atom = (*it).fAtom;
1089 // if ( atom != NULL )
1090 // fprintf(stderr, "\t%s\n", (*it).fAtom->getDisplayName());
1091 // else
1092 // fprintf(stderr, "\t%s\n", (*it).fReader->getPath());
1093 //}
1094
c2646906
A
1095 return count;
1096}
1097
1098macho_uintptr_t Writer::valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom)
1099{
1100 switch ( stab.type ) {
1101 case N_FUN:
1102 if ( stab.other == 0 )
1103 break;
1104 // end of function N_FUN has size (not address) so should not be adjusted
1105 // fall through
1106 case N_BNSYM:
1107 case N_ENSYM:
1108 case N_LBRAC:
1109 case N_RBRAC:
1110 case N_SLINE:
1111 case N_STSYM:
1112 case N_LCSYM:
1113 // all these stab types need their value changed from an offset in the atom to an address
1114 if ( atom != NULL )
1115 return getAtomLoadAddress(atom) + stab.atomOffset;
1116 }
1117 return stab.atomOffset;
1118}
1119
1120
1121void Writer::addStabs(uint32_t startIndex, uint32_t count)
1122{
1123 macho_nlist* entry = &fSymbolTable[startIndex];
1124 const int chunkCount = fStabChunks.size();
1125 for (int i=0; i < chunkCount; ++i ) {
1126 const StabChunks& chunk = fStabChunks[i];
1127 const int stabCount = chunk.fStabs->size();
1128 for (int j=0; j < stabCount; ++j ) {
1129 const ObjectFile::StabsInfo& stab = (*chunk.fStabs)[j];
1130 entry->set_n_type(stab.type);
1131 entry->set_n_sect(stab.other);
1132 entry->set_n_desc(stab.desc);
1133 entry->set_n_value(valueForStab(stab, chunk.fAtom));
1134 entry->set_n_strx(this->fStringsAtom->add(stab.string));
1135 ++entry;
1136 }
1137 if ( (i == chunkCount-1) || (fStabChunks[i+1].fReader != chunk.fReader) ) {
1138 // need to add empty SO at end of each file
1139 entry->set_n_type(N_SO);
1140 entry->set_n_sect(1);
1141 entry->set_n_desc(0);
1142 entry->set_n_value(0);
1143 entry->set_n_strx(this->fStringsAtom->emptyString());
1144 ++entry;
1145 }
1146 }
1147}
1148
1149
1150
c2646906
A
1151uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
1152{
1153 // search imports
6e880c60
A
1154 int i = 0;
1155 for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
1156 if ( &atom == *it )
c2646906 1157 return i + fSymbolTableImportStartIndex;
6e880c60 1158 ++i;
c2646906
A
1159 }
1160
1161 // search locals
6e880c60
A
1162 i = 0;
1163 for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
1164 if ( &atom == *it )
c2646906 1165 return i + fSymbolTableLocalStartIndex;
6e880c60 1166 ++i;
c2646906
A
1167 }
1168
1169 // search exports
6e880c60
A
1170 i = 0;
1171 for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
1172 if ( &atom == *it )
c2646906 1173 return i + fSymbolTableExportStartIndex;
6e880c60 1174 ++i;
c2646906
A
1175 }
1176
1177 fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName());
1178 fprintf(stderr, "from %s\n", atom.getFile()->getPath());
1179 throw "atom not found";
1180}
1181
c2646906
A
1182void Writer::buildFixups()
1183{
1184 if ( fOptions.outputKind() == Options::kObjectFile )
1185 this->buildObjectFileFixups();
1186 else
1187 this->buildExecutableFixups();
1188}
1189
1190uint32_t Writer::addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
1191{
1192 ObjectFile::Atom& target = ref->getTarget();
1193 bool isExtern = target.isImportProxy() || ( strcmp(target.getSectionName(), "__common") == 0 );
1194 uint32_t symbolIndex = 0;
1195 if ( isExtern )
1196 symbolIndex = this->symbolIndex(target);
1197 uint32_t sectionNum = target.getSection()->getIndex();
1198 uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
1199 macho_relocation_info reloc1;
1200 macho_relocation_info reloc2;
1201 macho_scattered_relocation_info* sreloc1 = (macho_scattered_relocation_info*)&reloc1;
1202 macho_scattered_relocation_info* sreloc2 = (macho_scattered_relocation_info*)&reloc2;
1203
1204 switch ( ref->getKind() ) {
1205 case ObjectFile::Reference::noFixUp:
1206 return 0;
1207
1208 case ObjectFile::Reference::pointer:
1209 reloc1.set_r_address(address);
1210 if ( isExtern )
1211 reloc1.set_r_symbolnum(symbolIndex);
1212 else
1213 reloc1.set_r_symbolnum(sectionNum);
1214 reloc1.set_r_pcrel(false);
1215 reloc1.set_r_length(macho_relocation_info::pointer_length);
1216 reloc1.set_r_extern(isExtern);
1217 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1218 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1219 return 1;
1220
1221 case ObjectFile::Reference::ppcFixupBranch24:
1222 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1223 reloc1.set_r_address(address);
1224 if ( isExtern )
1225 reloc1.set_r_symbolnum(symbolIndex);
1226 else
1227 reloc1.set_r_symbolnum(sectionNum);
1228 reloc1.set_r_pcrel(true);
1229 reloc1.set_r_length(2);
1230 reloc1.set_r_type(PPC_RELOC_BR24);
1231 reloc1.set_r_extern(isExtern);
1232 }
1233 else {
1234 sreloc1->set_r_scattered(true);
1235 sreloc1->set_r_pcrel(true);
1236 sreloc1->set_r_length(2);
1237 sreloc1->set_r_type(PPC_RELOC_BR24);
1238 sreloc1->set_r_address(address);
1239 sreloc1->set_r_value(target.getAddress());
1240 }
1241 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1242 return 1;
1243
1244 case ObjectFile::Reference::ppcFixupBranch14:
1245 reloc1.set_r_address(address);
1246 reloc1.set_r_symbolnum(sectionNum);
1247 reloc1.set_r_pcrel(true);
1248 reloc1.set_r_length(2);
1249 reloc1.set_r_extern(false);
1250 reloc1.set_r_type(PPC_RELOC_BR14);
1251 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1252 return 1;
1253
1254 case ObjectFile::Reference::ppcFixupPicBaseLow14:
1255 case ObjectFile::Reference::ppcFixupPicBaseLow16:
1256 {
1257 macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
1258 macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
1259 uint32_t overflow = 0;
1260 if ( ((toAddr-fromAddr) & 0x00008000) != 0 )
1261 overflow = 1;
1262 sreloc1->set_r_scattered(true);
1263 sreloc1->set_r_pcrel(false);
1264 sreloc1->set_r_length(2);
1265 if ( ref->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16 )
1266 sreloc1->set_r_type(PPC_RELOC_LO16_SECTDIFF);
1267 else
1268 sreloc1->set_r_type(PPC_RELOC_LO14_SECTDIFF);
1269 sreloc1->set_r_address(address);
1270 sreloc1->set_r_value(target.getAddress());
1271 sreloc2->set_r_scattered(true);
1272 sreloc2->set_r_pcrel(false);
1273 sreloc2->set_r_length(2);
1274 sreloc2->set_r_type(PPC_RELOC_PAIR);
1275 sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
1276 sreloc2->set_r_value(fromAddr);
1277 fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
1278 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1279 return 2;
1280 }
1281
1282 case ObjectFile::Reference::ppcFixupPicBaseHigh16:
1283 {
1284 macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
1285 macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
1286 sreloc1->set_r_scattered(true);
1287 sreloc1->set_r_pcrel(false);
1288 sreloc1->set_r_length(2);
1289 sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
1290 sreloc1->set_r_address(address);
1291 sreloc1->set_r_value(target.getAddress());
1292 sreloc2->set_r_scattered(true);
1293 sreloc2->set_r_pcrel(false);
1294 sreloc2->set_r_length(2);
1295 sreloc2->set_r_type(PPC_RELOC_PAIR);
1296 sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
1297 sreloc2->set_r_value(fromAddr);
1298 fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
1299 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1300 return 2;
1301 }
1302
1303 case ObjectFile::Reference::ppcFixupAbsLow14:
1304 case ObjectFile::Reference::ppcFixupAbsLow16:
1305 {
1306 macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
1307 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1308 reloc1.set_r_address(address);
1309 if ( isExtern )
1310 reloc1.set_r_symbolnum(symbolIndex);
1311 else
1312 reloc1.set_r_symbolnum(sectionNum);
1313 reloc1.set_r_pcrel(false);
1314 reloc1.set_r_length(2);
1315 reloc1.set_r_extern(isExtern);
1316 if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
1317 reloc1.set_r_type(PPC_RELOC_LO16);
1318 else
1319 reloc1.set_r_type(PPC_RELOC_LO14);
1320 }
1321 else {
1322 sreloc1->set_r_scattered(true);
1323 sreloc1->set_r_pcrel(false);
1324 sreloc1->set_r_length(2);
1325 if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
1326 sreloc1->set_r_type(PPC_RELOC_LO16);
1327 else
1328 sreloc1->set_r_type(PPC_RELOC_LO14);
1329 sreloc1->set_r_address(address);
1330 sreloc1->set_r_value(target.getAddress());
1331 }
1332 if ( isExtern )
1333 reloc2.set_r_address(ref->getTargetOffset() >> 16);
1334 else
1335 reloc2.set_r_address(toAddr >> 16);
1336 reloc2.set_r_symbolnum(0);
1337 reloc2.set_r_pcrel(false);
1338 reloc2.set_r_length(2);
1339 reloc2.set_r_extern(false);
1340 reloc2.set_r_type(PPC_RELOC_PAIR);
1341 fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
1342 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1343 return 2;
1344 }
1345
1346 case ObjectFile::Reference::ppcFixupAbsHigh16:
1347 {
1348 macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
1349 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1350 reloc1.set_r_address(address);
1351 if ( isExtern )
1352 reloc1.set_r_symbolnum(symbolIndex);
1353 else
1354 reloc1.set_r_symbolnum(sectionNum);
1355 reloc1.set_r_pcrel(false);
1356 reloc1.set_r_length(2);
1357 reloc1.set_r_extern(isExtern);
1358 reloc1.set_r_type(PPC_RELOC_HI16);
1359 }
1360 else {
1361 sreloc1->set_r_scattered(true);
1362 sreloc1->set_r_pcrel(false);
1363 sreloc1->set_r_length(2);
1364 sreloc1->set_r_type(PPC_RELOC_HI16);
1365 sreloc1->set_r_address(address);
1366 sreloc1->set_r_value(target.getAddress());
1367 }
1368 if ( isExtern )
1369 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
1370 else
1371 reloc2.set_r_address(toAddr & 0xFFFF);
1372 reloc2.set_r_symbolnum(0);
1373 reloc2.set_r_pcrel(false);
1374 reloc2.set_r_length(2);
1375 reloc2.set_r_extern(false);
1376 reloc2.set_r_type(PPC_RELOC_PAIR);
1377 fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
1378 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1379 return 2;
1380 }
1381
1382 case ObjectFile::Reference::ppcFixupAbsHigh16AddLow:
1383 {
1384 macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
1385 uint32_t overflow = 0;
1386 if ( (toAddr & 0x00008000) != 0 )
1387 overflow = 0x10000;
1388 if ( (ref->getTargetOffset() == 0) || isExtern ) {
1389 reloc1.set_r_address(address);
1390 if ( isExtern )
1391 reloc1.set_r_symbolnum(symbolIndex);
1392 else
1393 reloc1.set_r_symbolnum(sectionNum);
1394 reloc1.set_r_pcrel(false);
1395 reloc1.set_r_length(2);
1396 reloc1.set_r_extern(isExtern);
1397 reloc1.set_r_type(PPC_RELOC_HA16);
1398 }
1399 else {
1400 sreloc1->set_r_scattered(true);
1401 sreloc1->set_r_pcrel(false);
1402 sreloc1->set_r_length(2);
1403 sreloc1->set_r_type(PPC_RELOC_HA16);
1404 sreloc1->set_r_address(address);
1405 sreloc1->set_r_value(target.getAddress());
1406 }
1407 if ( isExtern )
1408 reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
1409 else
1410 reloc2.set_r_address(toAddr & 0xFFFF);
1411 reloc2.set_r_symbolnum(0);
1412 reloc2.set_r_pcrel(false);
1413 reloc2.set_r_length(2);
1414 reloc2.set_r_extern(false);
1415 reloc2.set_r_type(PPC_RELOC_PAIR);
1416 fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
1417 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1418 return 2;
1419 }
1420
1421 case ObjectFile::Reference::pointer32Difference:
1422 case ObjectFile::Reference::pointer64Difference:
1423 {
1424 macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
1425 macho_uintptr_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
1426 sreloc1->set_r_scattered(true);
1427 sreloc1->set_r_pcrel(false);
1428 if ( ref->getKind() == ObjectFile::Reference::pointer64Difference )
1429 sreloc1->set_r_length(3);
1430 else
1431 sreloc1->set_r_length(2);
1432 if ( ref->getTargetOffset() != 0 )
1433 sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
1434 else
1435 sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
1436 sreloc1->set_r_address(address);
1437 sreloc1->set_r_value(toAddr);
1438 sreloc2->set_r_scattered(true);
1439 sreloc2->set_r_pcrel(false);
1440 sreloc2->set_r_length(macho_relocation_info::pointer_length);
1441 sreloc2->set_r_type(PPC_RELOC_PAIR);
1442 sreloc2->set_r_address(0);
1443 sreloc2->set_r_value(fromAddr);
1444 fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
1445 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1446 return 2;
1447 }
1448
1449 case ObjectFile::Reference::x86FixupBranch32:
1450 reloc1.set_r_address(address);
1451 reloc1.set_r_symbolnum(sectionNum);
1452 reloc1.set_r_pcrel(true);
1453 reloc1.set_r_length(2);
1454 reloc1.set_r_extern(false);
1455 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1456 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1457 return 1;
1458
1459 }
1460 return 0;
1461}
1462
1463
1464void Writer::buildObjectFileFixups()
1465{
1466 uint32_t relocIndex = 0;
1467 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
1468 const int segCount = segmentInfos.size();
1469 for(int i=0; i < segCount; ++i) {
1470 SegmentInfo* curSegment = segmentInfos[i];
1471 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
1472 const int sectionCount = sectionInfos.size();
1473 for(int j=0; j < sectionCount; ++j) {
1474 SectionInfo* curSection = sectionInfos[j];
1475 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
1476 if ( ! curSection->fAllZeroFill ) {
1477 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
1478 curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
1479 curSection->fRelocOffset = relocIndex;
1480 const int atomCount = sectionAtoms.size();
1481 for (int k=0; k < atomCount; ++k) {
1482 ObjectFile::Atom* atom = sectionAtoms[k];
1483 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
1484 const int refCount = refs.size();
1485 for (int l=0; l < refCount; ++l) {
1486 ObjectFile::Reference* ref = refs[l];
c2646906
A
1487 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
1488 uint32_t offsetInSection = atom->getSectionOffset();
1489 uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);
1490 uint32_t undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
1491 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
1492 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
1493 //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
1494 fIndirectSymbolTable.push_back(entry);
6e880c60
A
1495 if ( curSection->fAllLazyPointers ) {
1496 ObjectFile::Atom& target = ref->getTarget();
1497 ObjectFile::Atom& fromTarget = ref->getFromTarget();
1498 if ( &fromTarget == NULL ) {
1499 fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
1500 }
1501 else {
1502 bool isExtern = target.isImportProxy();
1503 uint32_t symbolIndex = 0;
1504 if ( isExtern )
1505 symbolIndex = this->symbolIndex(target);
1506 uint32_t sectionNum = target.getSection()->getIndex();
1507 uint32_t address = atom->getSectionOffset();
1508 macho_relocation_info reloc1;
1509 reloc1.set_r_address(address);
1510 if ( isExtern )
1511 reloc1.set_r_symbolnum(symbolIndex);
1512 else
1513 reloc1.set_r_symbolnum(sectionNum);
1514 reloc1.set_r_pcrel(false);
1515 reloc1.set_r_length(macho_relocation_info::pointer_length);
1516 reloc1.set_r_extern(isExtern);
1517 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1518 fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
1519 ++relocIndex;
1520 }
1521 }
1522 }
1523 else {
1524 relocIndex += this->addRelocs(atom, ref);
c2646906
A
1525 }
1526 }
1527 }
1528 curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
1529 }
1530 }
1531 }
1532
1533 // now reverse reloc entries
1534 for(int i=0; i < segCount; ++i) {
1535 SegmentInfo* curSegment = segmentInfos[i];
1536 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
1537 const int sectionCount = sectionInfos.size();
1538 for(int j=0; j < sectionCount; ++j) {
1539 SectionInfo* curSection = sectionInfos[j];
1540 curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
1541 }
1542 }
1543
1544}
1545
1546
1547void Writer::buildExecutableFixups()
1548{
1549 const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
1550 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
1551 const int segCount = segmentInfos.size();
1552 for(int i=0; i < segCount; ++i) {
1553 SegmentInfo* curSegment = segmentInfos[i];
1554 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
1555 const int sectionCount = sectionInfos.size();
1556 for(int j=0; j < sectionCount; ++j) {
1557 SectionInfo* curSection = sectionInfos[j];
1558 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
1559 if ( ! curSection->fAllZeroFill ) {
1560 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
1561 curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
1562 const int atomCount = sectionAtoms.size();
1563 for (int k=0; k < atomCount; ++k) {
1564 ObjectFile::Atom* atom = sectionAtoms[k];
1565 std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
1566 const int refCount = refs.size();
1567 //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
c2646906
A
1568 for (int l=0; l < refCount; ++l) {
1569 ObjectFile::Reference* ref = refs[l];
6e880c60
A
1570 if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
1571 // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
1572 if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
1573 printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
1574 }
1575 uint32_t offsetInSection = atom->getSectionOffset();
1576 uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);
1577 uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
1578 //fprintf(stderr,"indirect pointer atom %p %s section offset = %d\n", atom, atom->getDisplayName(), offsetInSection);
1579 if ( ref->getTarget().isImportProxy()
1580 || ref->getTarget().isWeakDefinition()
1581 || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
1582 || (fOptions.nameSpace() == Options::kFlatNameSpace)
1583 || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
1584 undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
1585 }
1586 uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
1587 IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
1588 //fprintf(stderr,"fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
1589 fIndirectSymbolTable.push_back(entry);
1590 if ( slideable && curSection->fAllLazyPointers ) {
1591 // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
1592 macho_relocation_info pblaReloc;
1593 SectionInfo* sectInfo = (SectionInfo*)ref->getFromTarget().getSection();
1594 uint32_t sectionNum = sectInfo->getIndex();
1595 pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
1596 pblaReloc.set_r_symbolnum(sectionNum);
1597 pblaReloc.set_r_pcrel(false);
1598 pblaReloc.set_r_length(macho_relocation_info::pointer_length);
1599 pblaReloc.set_r_extern(false);
1600 pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
1601 fInternalRelocs.push_back(pblaReloc);
1602 }
1603 }
1604 else if ( ref->requiresRuntimeFixUp(slideable) ) {
c2646906
A
1605 if ( ! atom->getSegment().isContentWritable() )
1606 throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName());
6e880c60 1607 if ( ref->getTarget().isImportProxy() ) {
c2646906
A
1608 // if import is to antoher dylib, this is encoded as an external relocation
1609 macho_relocation_info externalReloc;
1610 externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
1611 externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
1612 externalReloc.set_r_pcrel(false);
1613 externalReloc.set_r_length(macho_relocation_info::pointer_length);
1614 externalReloc.set_r_extern(true);
1615 externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
1616 fExternalRelocs.push_back(externalReloc);
1617 }
6e880c60 1618 else {
c2646906
A
1619 // if this is a dylib/bundle, need fix-up encoded as an internal relocation
1620 macho_relocation_info internalReloc;
1621 SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
1622 uint32_t sectionNum = sectInfo->getIndex();
1623 // special case _mh_dylib_header and friends which are not in any real section
1624 if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
1625 sectionNum = 1;
1626 internalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
1627 internalReloc.set_r_symbolnum(sectionNum);
1628 internalReloc.set_r_pcrel(false);
1629 internalReloc.set_r_length(macho_relocation_info::pointer_length);
1630 internalReloc.set_r_extern(false);
1631 internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
1632 fInternalRelocs.push_back(internalReloc);
1633 }
1634 }
1635 }
1636 }
1637 }
1638 }
1639 }
1640}
1641
1642class ContentWriter : public ObjectFile::ContentWriter
1643{
1644public:
1645 ContentWriter(int fd, uint64_t fileOffset) : fFileDescriptor(fd), fFileOffset(fileOffset) {}
1646 virtual void write(uint64_t atomOffset, const void* buffer, uint64_t size) {
1647 ::pwrite(fFileDescriptor, buffer, size, fFileOffset+atomOffset);
1648 }
1649private:
1650 int fFileDescriptor;
1651 uint64_t fFileOffset;
1652};
1653
1654
1655void Writer::writeAtoms()
1656{
1657 const bool requireAllFixUps = (fOptions.outputKind() != Options::kObjectFile);
1658
1659 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
1660 const int segCount = segmentInfos.size();
1661 for(int i=0; i < segCount; ++i) {
1662 SegmentInfo* curSegment = segmentInfos[i];
1663 bool isText = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
1664 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
1665 const int sectionCount = sectionInfos.size();
1666 for(int j=0; j < sectionCount; ++j) {
1667 SectionInfo* curSection = sectionInfos[j];
1668 std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
1669 //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
1670 if ( ! curSection->fAllZeroFill ) {
1671 const int atomCount = sectionAtoms.size();
1672 uint32_t end = curSection->fFileOffset;
1673 for (int k=0; k < atomCount; ++k) {
1674 ObjectFile::Atom* atom = sectionAtoms[k];
1675 if ( !atom->isImportProxy() ) {
1676 uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
1677 if ( isText && (offset != end) ) {
1678 // fill gaps with no-ops
1679 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
1680 uint32_t ppcNop;
1681 OSWriteBigInt32(&ppcNop, 0, 0x60000000);
1682 for (uint32_t p=end; p < offset; p += 4)
1683 ::pwrite(fFileDescriptor, &ppcNop, 4, p);
1684 #else defined(ARCH_I386)
1685 uint8_t x86Nop = 0x90;
1686 for (uint32_t p=end; p < offset; ++p)
1687 ::pwrite(fFileDescriptor, &x86Nop, 1, p);
1688 #endif
1689 }
6e880c60
A
1690 end = offset+atom->getSize();
1691 //fprintf(stderr, "writing 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
c2646906
A
1692 ContentWriter writer(fFileDescriptor, offset);
1693 atom->writeContent(requireAllFixUps, writer);
c2646906
A
1694 }
1695 }
1696 }
1697 }
1698 }
1699}
1700
1701
1702void Writer::partitionIntoSections()
1703{
1704 const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
1705
1706 // for every atom, set its sectionInfo object and section offset
1707 // build up fSegmentInfos along the way
1708 ObjectFile::Section* curSection = NULL;
1709 SectionInfo* currentSectionInfo = NULL;
1710 SegmentInfo* currentSegmentInfo = NULL;
1711 unsigned int sectionIndex = 1;
1712 for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
1713 ObjectFile::Atom* atom = (*fAllAtoms)[i];
1714 if ( atom->getSection() != curSection ) {
1715 if ( oneSegmentCommand ) {
1716 if ( currentSegmentInfo == NULL ) {
1717 currentSegmentInfo = new SegmentInfo();
1718 currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
1719 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
1720 this->fSegmentInfos.push_back(currentSegmentInfo);
1721 }
1722 currentSectionInfo = new SectionInfo();
1723 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
1724 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
1725 currentSectionInfo->fAlignment = atom->getAlignment();
1726 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
1727 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
1728 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
1729 currentSectionInfo->setIndex(sectionIndex++);
1730 currentSegmentInfo->fSections.push_back(currentSectionInfo);
1731 }
1732 else {
1733 if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
1734 currentSegmentInfo = new SegmentInfo();
1735 strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
1736 uint32_t initprot = 0;
1737 if ( atom->getSegment().isContentReadable() )
1738 initprot |= VM_PROT_READ;
1739 if ( atom->getSegment().isContentWritable() )
1740 initprot |= VM_PROT_WRITE;
1741 if ( atom->getSegment().isContentExecutable() )
1742 initprot |= VM_PROT_EXECUTE;
1743 currentSegmentInfo->fInitProtection = initprot;
1744 if ( initprot == 0 )
1745 currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0
1746 else
1747 currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
1748 currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
6e880c60 1749 currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
c2646906
A
1750 this->fSegmentInfos.push_back(currentSegmentInfo);
1751 }
1752 currentSectionInfo = new SectionInfo();
1753 strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
1754 strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
1755 currentSectionInfo->fAlignment = atom->getAlignment();
1756 // check for -sectalign override
1757 std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
1758 for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
1759 if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
1760 currentSectionInfo->fAlignment = it->alignment;
1761 }
1762 currentSectionInfo->fAllZeroFill = atom->isZeroFill();
1763 currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
1764 if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
1765 currentSectionInfo->setIndex(sectionIndex++);
1766 currentSegmentInfo->fSections.push_back(currentSectionInfo);
1767 }
1768 if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
1769 fLoadCommandsSection = currentSectionInfo;
1770 fLoadCommandsSegment = currentSegmentInfo;
1771 }
1772 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
1773 currentSectionInfo->fAllLazyPointers = true;
6e880c60
A
1774 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
1775 currentSectionInfo->fAllLazyPointers = true;
c2646906
A
1776 if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
1777 currentSectionInfo->fAllNonLazyPointers = true;
1778 curSection = atom->getSection();
1779 }
1780 // any non-zero fill atoms make whole section marked not-zero-fill
1781 if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
1782 currentSectionInfo->fAllZeroFill = false;
1783 // change section object to be Writer's SectionInfo object
1784 atom->setSection(currentSectionInfo);
1785 // section alignment is that of a contained atom with the greatest alignment
1786 uint8_t atomAlign = atom->getAlignment();
1787 if ( currentSectionInfo->fAlignment < atomAlign )
1788 currentSectionInfo->fAlignment = atomAlign;
1789 // calculate section offset for this atom
1790 uint64_t offset = currentSectionInfo->fSize;
1791 uint64_t alignment = 1 << atomAlign;
1792 offset = ( (offset+alignment-1) & (-alignment) );
1793 atom->setSectionOffset(offset);
1794 currentSectionInfo->fSize = offset + atom->getSize();
1795 // add atom to section vector
1796 currentSectionInfo->fAtoms.push_back(atom);
1797 }
1798}
1799
1800
6e880c60
A
1801struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
1802class TargetAndOffsetComparor
1803{
1804public:
1805 bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
1806 {
1807 if ( left.atom != right.atom )
1808 return ( left.atom < right.atom );
1809 return ( left.offset < right.offset );
1810 }
1811};
1812
1813//
1814// PowerPC can do PC relative branches as far as +/-16MB.
1815// If a branch target is >16MB then we insert one or more
1816// "branch islands" between the branch and its target that
1817// allows island hoping to the target.
1818//
1819// Branch Island Algorithm
1820//
1821// If the __TEXT segment < 16MB, then no branch islands needed
1822// Otherwise, every 15MB into the __TEXT segment is region is
1823// added which can contain branch islands. Every out of range
1824// bl instruction is checked. If it crosses a region, an island
1825// is added to that region with the same target and the bl is
1826// adjusted to target the island instead.
1827//
1828// In theory, if too many islands are added to one region, it
1829// could grow the __TEXT enough that other previously in-range
1830// bl branches could be pushed out of range. We reduce the
1831// probability this could happen by placing the ranges every
1832// 15MB which means the region would have to be 1MB (256K islands)
1833// before any branches could be pushed out of range.
1834//
1835bool Writer::addBranchIslands()
1836{
1837 bool result = false;
1838#if defined(ARCH_PPC) || defined(ARCH_PPC64)
1839 // Can only possibly need branch islands if __TEXT segment > 16M
1840 if ( fLoadCommandsSegment->fSize > 16000000 ) {
1841 const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section
1842 SectionInfo* textSection = NULL;
1843 for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
1844 if ( strcmp((*it)->fSectionName, "__text") == 0 )
1845 textSection = *it;
1846 }
1847 const int kIslandRegionsCount = textSection->fSize / kBetweenRegions;
1848 typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
1849 AtomToIsland regionsMap[kIslandRegionsCount];
1850 std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
1851 unsigned int islandCount = 0;
1852
1853 // create islands for branch references that are out of range
1854 for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
1855 ObjectFile::Atom* atom = *it;
1856 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
1857 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1858 ObjectFile::Reference* ref = *rit;
1859 if ( ref->getKind() == ObjectFile::Reference::ppcFixupBranch24 ) {
1860 ObjectFile::Atom& target = ref->getTarget();
1861 int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
1862 int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
1863 int64_t displacement = dstAddr - srcAddr;
1864 const int64_t kFifteenMegLimit = kBetweenRegions;
1865 if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
1866 for (int i=0; i < kIslandRegionsCount; ++i) {
1867 AtomToIsland* region=&regionsMap[i];
1868 int64_t islandRegionAddr = kBetweenRegions * (i+1);
1869 if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
1870 ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
1871 TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
1872 AtomToIsland::iterator pos = region->find(islandTarget);
1873 if ( pos == region->end() ) {
1874 BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
1875 (*region)[islandTarget] = island;
1876 regionsIslands[i].push_back(island);
1877 ++islandCount;
1878 ref->setTarget(*island, 0);
1879 }
1880 else {
1881 ref->setTarget(*(pos->second), 0);
1882 }
1883 }
1884 }
1885 }
1886 }
1887 }
1888 }
1889
1890 // insert islands into __text section and adjust section offsets
1891 if ( islandCount > 0 ) {
1892 std::vector<ObjectFile::Atom*> newAtomList;
1893 newAtomList.reserve(textSection->fAtoms.size()+islandCount);
1894 uint64_t islandRegionAddr = kBetweenRegions;
1895 int regionIndex = 0;
1896 uint64_t sectionOffset = 0;
1897 for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
1898 ObjectFile::Atom* atom = *it;
1899 newAtomList.push_back(atom);
1900 if ( atom->getAddress() > islandRegionAddr ) {
1901 std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
1902 for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
1903 ObjectFile::Atom* islandAtom = *rit;
1904 newAtomList.push_back(islandAtom);
1905 islandAtom->setSection(textSection);
1906 uint64_t alignment = 1 << (islandAtom->getAlignment());
1907 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
1908 islandAtom->setSectionOffset(sectionOffset);
1909 sectionOffset += islandAtom->getSize();
1910 }
1911 ++regionIndex;
1912 islandRegionAddr += kBetweenRegions;
1913 }
1914 uint64_t alignment = 1 << (atom->getAlignment());
1915 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
1916 atom->setSectionOffset(sectionOffset);
1917 sectionOffset += atom->getSize();
1918 }
1919 textSection->fAtoms = newAtomList;
1920 textSection->fSize = sectionOffset;
1921 result = true;
1922 }
1923
1924 }
1925#endif
1926 return result;
1927}
1928
1929
c2646906
A
1930void Writer::adjustLoadCommandsAndPadding()
1931{
1932 fSegmentCommands->computeSize();
1933
1934 // recompute load command section offsets
1935 uint64_t offset = 0;
1936 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
1937 const unsigned int atomCount = loadCommandAtoms.size();
1938 for (unsigned int i=0; i < atomCount; ++i) {
1939 ObjectFile::Atom* atom = loadCommandAtoms[i];
1940 uint64_t alignment = 1 << atom->getAlignment();
1941 offset = ( (offset+alignment-1) & (-alignment) );
1942 atom->setSectionOffset(offset);
1943 offset += atom->getSize();
1944 fLoadCommandsSection->fSize = offset;
1945 }
1946
1947 std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
1948 const int sectionCount = sectionInfos.size();
1949 uint64_t paddingSize = 0;
1950 if ( fOptions.outputKind() == Options::kDyld ) {
1951 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
1952 uint32_t totalSizeOfHeaderAndLoadCommands = 0;
1953 for(int j=0; j < sectionCount; ++j) {
1954 SectionInfo* curSection = sectionInfos[j];
1955 totalSizeOfHeaderAndLoadCommands += curSection->fSize;
1956 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
1957 break;
1958 }
1959 paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
1960 }
1961 else {
1962 // calculate max padding to keep segment size same, but all free space at end of load commands
1963 uint64_t totalSize = 0;
1964 uint64_t worstCaseAlignmentPadding = 0;
1965 for(int j=0; j < sectionCount; ++j) {
1966 SectionInfo* curSection = sectionInfos[j];
1967 totalSize += curSection->fSize;
1968 if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
1969 worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
1970 }
1971 uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
1972 // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
1973 paddingSize = segmentSize - totalSize;
1974
1975 // if command line requires more padding than this
1976 if ( paddingSize < fOptions.minimumHeaderPad() ) {
1977 int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
1978 paddingSize += extraPages * 4096;
1979 }
1980 }
1981
1982 // adjust atom size and update section size
1983 fHeaderPadding->setSize(paddingSize);
1984 for(int j=0; j < sectionCount; ++j) {
1985 SectionInfo* curSection = sectionInfos[j];
1986 if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
1987 curSection->fSize = paddingSize;
1988 }
1989}
1990
1991// assign file offsets and logical address to all segments
1992void Writer::assignFileOffsets()
1993{
1994 bool haveFixedSegments = false;
1995 uint64_t fileOffset = 0;
6e880c60
A
1996 uint64_t nextContiguousAddress = 0;
1997 bool baseAddressUsed = false;
c2646906
A
1998 std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
1999 const int segCount = segmentInfos.size();
2000 for(int i=0; i < segCount; ++i) {
2001 SegmentInfo* curSegment = segmentInfos[i];
2002 fileOffset = (fileOffset+4095) & (-4096);
2003 curSegment->fFileOffset = fileOffset;
6e880c60
A
2004 if ( curSegment->fFixedAddress ) {
2005 // segment has fixed address already set
2006 haveFixedSegments = true;
c2646906
A
2007 }
2008 else {
6e880c60
A
2009 // segment uses next address
2010 if ( !baseAddressUsed ) {
2011 baseAddressUsed = true;
2012 if ( fOptions.baseAddress() != 0 )
2013 nextContiguousAddress = fOptions.baseAddress();
2014 }
2015 curSegment->fBaseAddress = nextContiguousAddress;
c2646906
A
2016 }
2017 uint64_t address = curSegment->fBaseAddress;
2018 std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
2019 const int sectionCount = sectionInfos.size();
2020 for(int j=0; j < sectionCount; ++j) {
2021 SectionInfo* curSection = sectionInfos[j];
2022 uint64_t alignment = 1 << curSection->fAlignment;
2023 fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
2024 address = ( (address+alignment-1) & (-alignment) );
2025 curSection->fFileOffset = fileOffset;
2026 curSection->setBaseAddress(address);
2027 //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address);
2028 curSegment->fSize = curSection->getBaseAddress() + curSection->fSize - curSegment->fBaseAddress;
2029 if ( (fOptions.outputKind() != Options::kObjectFile) || ! curSection->fVirtualSection )
2030 address += curSection->fSize;
2031 if ( !curSection->fAllZeroFill ) {
2032 curSegment->fFileSize = curSegment->fSize;
2033 fileOffset += curSection->fSize;
2034 }
2035 }
6e880c60
A
2036 // page align segment size
2037 curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
2038 curSegment->fSize = (curSegment->fSize+4095) & (-4096);
c2646906
A
2039 if ( curSegment->fBaseAddress == nextContiguousAddress )
2040 nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
2041 }
2042
2043 // check for segment overlaps
2044 if ( haveFixedSegments ) {
2045 for(int i=0; i < segCount; ++i) {
2046 SegmentInfo* segment1 = segmentInfos[i];
2047 for(int j=0; j < segCount; ++j) {
2048 if ( i != j ) {
2049 SegmentInfo* segment2 = segmentInfos[j];
2050 if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
2051 if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
2052 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
2053 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
2054 }
2055 else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
2056 if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
2057 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
2058 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
2059 }
2060 else {
2061 throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
2062 segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
2063 }
2064 }
2065 }
2066 }
2067 }
2068}
2069
2070void Writer::adjustLinkEditSections()
2071{
2072 // link edit content is always in last segment
2073 SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
2074 unsigned int firstLinkEditSectionIndex = 0;
2075 while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
2076 ++firstLinkEditSectionIndex;
2077
2078 const unsigned int sectionCount = lastSeg->fSections.size();
2079 uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
2080 uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
2081 for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
2082 std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
2083 const unsigned int atomCount = atoms.size();
2084 uint64_t sectionOffset = 0;
2085 lastSeg->fSections[i]->fFileOffset = fileOffset;
2086 lastSeg->fSections[i]->setBaseAddress(address);
2087 for (unsigned int j=0; j < atomCount; ++j) {
2088 ObjectFile::Atom* atom = atoms[j];
2089 uint64_t alignment = 1 << atom->getAlignment();
2090 sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
2091 atom->setSectionOffset(sectionOffset);
2092 sectionOffset += atom->getSize();
2093 }
2094 lastSeg->fSections[i]->fSize = sectionOffset;
2095 fileOffset += sectionOffset;
2096 address += sectionOffset;
2097 }
2098 if ( fOptions.outputKind() == Options::kObjectFile ) {
c2646906
A
2099 //lastSeg->fBaseAddress = 0;
2100 //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
2101 //lastSeg->fFileOffset = 0;
2102 //lastSeg->fFileSize =
2103 }
2104 else {
2105 lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
6e880c60 2106 lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096);
c2646906
A
2107 }
2108}
2109
2110
2111ObjectFile::Atom::Scope MachHeaderAtom::getScope() const
2112{
2113 switch ( fWriter.fOptions.outputKind() ) {
2114 case Options::kDynamicExecutable:
2115 case Options::kStaticExecutable:
2116 return ObjectFile::Atom::scopeGlobal;
2117 case Options::kDynamicLibrary:
2118 case Options::kDynamicBundle:
2119 case Options::kDyld:
2120 case Options::kObjectFile:
2121 return ObjectFile::Atom::scopeLinkageUnit;
2122 }
2123 throw "unknown header type";
2124}
2125
2126bool MachHeaderAtom::dontStripName() const
2127{
2128 switch ( fWriter.fOptions.outputKind() ) {
2129 case Options::kDynamicExecutable:
2130 case Options::kStaticExecutable:
2131 return true;
2132 case Options::kDynamicLibrary:
2133 case Options::kDynamicBundle:
2134 case Options::kDyld:
2135 case Options::kObjectFile:
2136 return false;
2137 }
2138 throw "unknown header type";
2139}
2140
2141const char* MachHeaderAtom::getName() const
2142{
2143 switch ( fWriter.fOptions.outputKind() ) {
2144 case Options::kDynamicExecutable:
2145 case Options::kStaticExecutable:
2146 return "__mh_execute_header";
2147 case Options::kDynamicLibrary:
2148 return "__mh_dylib_header";
2149 case Options::kDynamicBundle:
2150 return "__mh_bundle_header";
2151 case Options::kObjectFile:
2152 return NULL;
2153 case Options::kDyld:
2154 return "__mh_dylinker_header";
2155 }
2156 throw "unknown header type";
2157}
2158
2159const char* MachHeaderAtom::getDisplayName() const
2160{
2161 switch ( fWriter.fOptions.outputKind() ) {
2162 case Options::kDynamicExecutable:
2163 case Options::kStaticExecutable:
2164 case Options::kDynamicLibrary:
2165 case Options::kDynamicBundle:
2166 case Options::kDyld:
2167 return this->getName();
2168 case Options::kObjectFile:
2169 return "mach header";
2170 }
2171 throw "unknown header type";
2172}
2173
2174uint64_t MachHeaderAtom::getSize() const
2175{
2176 return macho_header::size;
2177}
2178
2179void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2180{
2181 macho_header mh;
2182
2183 // get file type
2184 uint32_t fileType = 0;
2185 switch ( fWriter.fOptions.outputKind() ) {
2186 case Options::kDynamicExecutable:
2187 case Options::kStaticExecutable:
2188 fileType = MH_EXECUTE;
2189 break;
2190 case Options::kDynamicLibrary:
2191 fileType = MH_DYLIB;
2192 break;
2193 case Options::kDynamicBundle:
2194 fileType = MH_BUNDLE;
2195 break;
2196 case Options::kObjectFile:
2197 fileType = MH_OBJECT;
2198 break;
2199 case Options::kDyld:
2200 fileType = MH_DYLINKER;
2201 break;
2202 }
2203
2204 // get flags
2205 uint32_t flags = 0;
2206 if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
2207 flags = MH_SUBSECTIONS_VIA_SYMBOLS;
2208 }
2209 else {
2210 flags = MH_DYLDLINK;
2211 if ( fWriter.fOptions.bindAtLoad() )
2212 flags |= MH_BINDATLOAD;
2213 switch ( fWriter.fOptions.nameSpace() ) {
2214 case Options::kTwoLevelNameSpace:
2215 flags |= MH_TWOLEVEL | MH_NOUNDEFS;
2216 break;
2217 case Options::kFlatNameSpace:
2218 break;
2219 case Options::kForceFlatNameSpace:
2220 flags |= MH_FORCE_FLAT;
2221 break;
2222 }
2223 if ( fWriter.fHasWeakExports )
2224 flags |= MH_WEAK_DEFINES;
2225 if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
2226 flags |= MH_BINDS_TO_WEAK;
2227 }
2228
2229 // get commands info
2230 uint32_t commandsSize = 0;
2231 uint32_t commandsCount = 0;
2232
2233 std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
2234 const unsigned int atomCount = loadCommandAtoms.size();
2235 for (unsigned int i=0; i < atomCount; ++i) {
2236 ObjectFile::Atom* atom = loadCommandAtoms[i];
2237 commandsSize += atom->getSize();
2238 // segment and symbol table atoms can contain more than one load command
2239 if ( atom == fWriter.fSegmentCommands )
2240 commandsCount += fWriter.fSegmentCommands->commandCount();
2241 else if ( atom == fWriter.fSymbolTableCommands )
2242 commandsCount += 2;
2243 else
2244 ++commandsCount;
2245 }
2246
2247 // fill out mach_header
2248 mh.set_magic(macho_header::magic_value);
2249 mh.set_cputype(fWriter.fOptions.architecture());
6e880c60
A
2250#if defined(ARCH_PPC) || defined(ARCH_PPC64)
2251 mh.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
2252#elif defined(ARCH_I386)
2253 mh.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
2254#else
2255 #error unknown architecture
2256#endif
c2646906
A
2257 mh.set_filetype(fileType);
2258 mh.set_ncmds(commandsCount);
2259 mh.set_sizeofcmds(commandsSize);
2260 mh.set_flags(flags);
2261 mh.set_reserved();
2262
2263 // write it
2264 writer.write(0, &mh, macho_header::size);
2265}
2266
2267
2268CustomStackAtom::CustomStackAtom(Writer& writer)
2269 : WriterAtom(writer, fgStackSegment)
2270{
2271#if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
2272 // stack grows down for these architectures
2273 fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
2274#else
2275 #error unknown architecture
2276#endif
2277}
2278
2279
2280void SegmentLoadCommandsAtom::computeSize()
2281{
2282 uint64_t size = 0;
2283 std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
2284 const int segCount = segmentInfos.size();
2285 for(int i=0; i < segCount; ++i) {
2286 size += macho_segment_command::size;
2287 std::vector<Writer::SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
2288 const int sectionCount = sectionInfos.size();
2289 for(int j=0; j < sectionCount; ++j) {
2290 if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
2291 size += macho_section::content_size;
2292 }
2293 }
2294 fSize = size;
2295 fCommandCount = segCount;
2296}
2297
2298
2299
2300void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2301{
2302 uint64_t size = this->getSize();
2303 uint8_t buffer[size];
2304 const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
2305 bzero(buffer, fSize);
2306 uint8_t* p = buffer;
2307 std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
2308 const int segCount = segmentInfos.size();
2309 for(int i=0; i < segCount; ++i) {
2310 Writer::SegmentInfo* segInfo = segmentInfos[i];
2311 const int sectionCount = segInfo->fSections.size();
2312 macho_segment_command* cmd = (macho_segment_command*)p;
2313 cmd->set_cmd(macho_segment_command::command);
2314 cmd->set_segname(segInfo->fName);
2315 cmd->set_vmaddr(segInfo->fBaseAddress);
2316 cmd->set_vmsize(segInfo->fSize);
2317 cmd->set_fileoff(segInfo->fFileOffset);
2318 cmd->set_filesize(segInfo->fFileSize);
2319 cmd->set_maxprot(segInfo->fMaxProtection);
2320 cmd->set_initprot(segInfo->fInitProtection);
2321 // add sections array
2322 macho_section* const sections = (macho_section*)&p[macho_segment_command::size];
2323 unsigned int sectionsEmitted = 0;
2324 for (int j=0; j < sectionCount; ++j) {
2325 Writer::SectionInfo* sectInfo = segInfo->fSections[j];
2326 if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
2327 macho_section* sect = &sections[sectionsEmitted++];
2328 if ( oneSegment ) {
2329 // .o files have weird segment range
2330 if ( sectionsEmitted == 1 ) {
2331 cmd->set_vmaddr(sectInfo->getBaseAddress());
2332 cmd->set_fileoff(sectInfo->fFileOffset);
2333 cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset);
2334 }
2335 cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
2336 }
2337 sect->set_sectname(sectInfo->fSectionName);
2338 sect->set_segname(sectInfo->fSegmentName);
2339 sect->set_addr(sectInfo->getBaseAddress());
2340 sect->set_size(sectInfo->fSize);
2341 sect->set_offset(sectInfo->fFileOffset);
2342 sect->set_align(sectInfo->fAlignment);
2343 if ( sectInfo->fRelocCount != 0 ) {
2344 sect->set_reloff(sectInfo->fRelocOffset * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset());
2345 sect->set_nreloc(sectInfo->fRelocCount);
2346 }
2347 if ( sectInfo->fAllZeroFill ) {
2348 sect->set_flags(S_ZEROFILL);
2349 }
2350 else if ( sectInfo->fAllLazyPointers ) {
2351 sect->set_flags(S_LAZY_SYMBOL_POINTERS);
2352 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
2353 }
2354 else if ( sectInfo->fAllNonLazyPointers ) {
2355 sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
2356 sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
2357 }
2358 else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
2359 sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
2360 }
2361 else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
2362 sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
2363 }
6e880c60
A
2364 else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
2365 sect->set_flags(S_COALESCED);
2366 }
c2646906
A
2367 }
2368 }
2369 p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size];
2370 cmd->set_cmdsize(macho_segment_command::size + sectionsEmitted*macho_section::content_size);
2371 cmd->set_nsects(sectionsEmitted);
2372 }
2373 writer.write(0, buffer, size);
2374}
2375
2376
2377SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer)
2378 : WriterAtom(writer, fgTextSegment)
2379{
2380 bzero(&fSymbolTable, macho_symtab_command::size);
2381 bzero(&fDynamicSymbolTable, macho_dysymtab_command::size);
2382 writer.fSymbolTableCommands = this;
2383}
2384
2385uint64_t SymbolTableLoadCommandsAtom::getSize() const
2386{
2387 return macho_symtab_command::size + macho_dysymtab_command::size;
2388}
2389
2390void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2391{
2392 // build LC_DYSYMTAB command
2393 macho_symtab_command symbolTableCmd;
2394 bzero(&symbolTableCmd, macho_symtab_command::size);
2395 symbolTableCmd.set_cmd(LC_SYMTAB);
2396 symbolTableCmd.set_cmdsize(macho_symtab_command::size);
2397 symbolTableCmd.set_nsyms(fWriter.fSymbolTableCount);
2398 symbolTableCmd.set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
2399 symbolTableCmd.set_stroff(fWriter.fStringsAtom->getFileOffset());
2400 symbolTableCmd.set_strsize(fWriter.fStringsAtom->getSize());
2401 writer.write(0, &symbolTableCmd, macho_symtab_command::size);
2402
2403 // build LC_DYSYMTAB command
2404 macho_dysymtab_command dynamicSymbolTableCmd;
2405 bzero(&dynamicSymbolTableCmd, macho_dysymtab_command::size);
2406 dynamicSymbolTableCmd.set_cmd(LC_DYSYMTAB);
2407 dynamicSymbolTableCmd.set_cmdsize(macho_dysymtab_command::size);
2408 dynamicSymbolTableCmd.set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
2409 dynamicSymbolTableCmd.set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
2410 dynamicSymbolTableCmd.set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
2411 dynamicSymbolTableCmd.set_nextdefsym(fWriter.fSymbolTableExportCount);
2412 dynamicSymbolTableCmd.set_iundefsym(fWriter.fSymbolTableImportStartIndex);
2413 dynamicSymbolTableCmd.set_nundefsym(fWriter.fSymbolTableImportCount);
2414 dynamicSymbolTableCmd.set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
2415 dynamicSymbolTableCmd.set_nindirectsyms(fWriter.fIndirectSymbolTable.size());
2416 if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
2417 dynamicSymbolTableCmd.set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
2418 dynamicSymbolTableCmd.set_nextrel(fWriter.fExternalRelocs.size());
2419 dynamicSymbolTableCmd.set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
2420 dynamicSymbolTableCmd.set_nlocrel(fWriter.fInternalRelocs.size());
2421 }
2422 writer.write(macho_symtab_command::size, &dynamicSymbolTableCmd, macho_dysymtab_command::size);
2423}
2424
2425uint64_t DyldLoadCommandsAtom::getSize() const
2426{
2427 uint32_t len = macho_dylinker_command::name_offset + strlen("/usr/lib/dyld");
2428 len = (len+7) & (-8); // 8-byte align
2429 return len;
2430}
2431
2432void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2433{
2434 uint64_t size = this->getSize();
2435 uint8_t buffer[size];
6e880c60 2436 bzero(buffer, size);
c2646906
A
2437 macho_dylinker_command* cmd = (macho_dylinker_command*)buffer;
2438 if ( fWriter.fOptions.outputKind() == Options::kDyld )
2439 cmd->set_cmd(LC_ID_DYLINKER);
2440 else
2441 cmd->set_cmd(LC_LOAD_DYLINKER);
2442 cmd->set_cmdsize(this->getSize());
2443 cmd->set_name_offset();
2444 strcpy((char*)&buffer[macho_dylinker_command::name_offset], "/usr/lib/dyld");
2445 writer.write(0, buffer, size);
2446}
2447
2448
2449
2450uint64_t DylibLoadCommandsAtom::getSize() const
2451{
2452 const char* path = fInfo.reader->getInstallPath();
2453 if ( fInfo.options.fInstallPathOverride != NULL )
2454 path = fInfo.options.fInstallPathOverride;
2455 uint32_t len = macho_dylib_command::name_offset + strlen(path);
2456 len = (len+7) & (-8); // 8-byte align
2457 return len;
2458}
2459
2460void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2461{
2462 uint64_t size = this->getSize();
2463 uint8_t buffer[size];
2464 bzero(buffer, size);
2465 const char* path = fInfo.reader->getInstallPath();
2466 if ( fInfo.options.fInstallPathOverride != NULL )
2467 path = fInfo.options.fInstallPathOverride;
2468 macho_dylib_command* cmd = (macho_dylib_command*)buffer;
2469 if ( fInfo.options.fWeakImport )
2470 cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
2471 else
2472 cmd->set_cmd(LC_LOAD_DYLIB);
2473 cmd->set_cmdsize(this->getSize());
2474 cmd->set_timestamp(fInfo.reader->getTimestamp());
2475 cmd->set_current_version(fInfo.reader->getCurrentVersion());
2476 cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
2477 cmd->set_name_offset();
2478 strcpy((char*)&buffer[macho_dylib_command::name_offset], path);
2479 writer.write(0, buffer, size);
2480}
2481
2482
2483
2484uint64_t DylibIDLoadCommandsAtom::getSize() const
2485{
2486 uint32_t len = macho_dylib_command::name_offset + strlen(fWriter.fOptions.installPath());
2487 len = (len+7) & (-8); // 8-byte align
2488 return len;
2489}
2490
2491void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2492{
2493 struct timeval currentTime = { 0 , 0 };
2494 gettimeofday(&currentTime, NULL);
2495 time_t timestamp = currentTime.tv_sec;
2496 uint64_t size = this->getSize();
2497 uint8_t buffer[size];
2498 bzero(buffer, size);
2499 macho_dylib_command* cmd = (macho_dylib_command*)buffer;
2500 cmd->set_cmd(LC_ID_DYLIB);
2501 cmd->set_cmdsize(this->getSize());
2502 cmd->set_name_offset();
2503 cmd->set_timestamp(timestamp);
2504 cmd->set_current_version(fWriter.fOptions.currentVersion());
2505 cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
2506 strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath());
2507 writer.write(0, buffer, size);
2508}
2509
2510
2511uint64_t RoutinesLoadCommandsAtom::getSize() const
2512{
2513 return macho_routines_command::size;
2514}
2515
2516void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2517{
2518 uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
2519 uint8_t buffer[macho_routines_command::size];
2520 bzero(buffer, macho_routines_command::size);
2521 macho_routines_command* cmd = (macho_routines_command*)buffer;
2522 cmd->set_cmd(macho_routines_command::command);
2523 cmd->set_cmdsize(this->getSize());
2524 cmd->set_init_address(initAddr);
2525 writer.write(0, buffer, macho_routines_command::size);
2526}
2527
2528
2529uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
2530{
2531 uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName);
2532 len = (len+7) & (-8); // 8-byte align
2533 return len;
2534}
2535
2536void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2537{
2538 uint64_t size = this->getSize();
2539 uint8_t buffer[size];
2540 bzero(buffer, size);
2541 macho_sub_umbrella_command* cmd = (macho_sub_umbrella_command*)buffer;
2542 cmd->set_cmd(LC_SUB_UMBRELLA);
2543 cmd->set_cmdsize(this->getSize());
2544 cmd->set_name_offset();
2545 strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName);
2546 writer.write(0, buffer, size);
2547}
2548
2549
2550uint64_t SubLibraryLoadCommandsAtom::getSize() const
2551{
2552 uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1;
2553 len = (len+7) & (-8); // 8-byte align
2554 return len;
2555}
2556
2557void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2558{
2559 uint64_t size = this->getSize();
2560 uint8_t buffer[size];
2561 bzero(buffer, size);
2562 macho_sub_library_command* cmd = (macho_sub_library_command*)buffer;
2563 cmd->set_cmd(LC_SUB_LIBRARY);
2564 cmd->set_cmdsize(this->getSize());
2565 cmd->set_name_offset();
2566 strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength);
2567 buffer[macho_sub_library_command::name_offset+fNameLength] = '\0';
2568 writer.write(0, buffer, size);
2569}
2570
2571uint64_t UmbrellaLoadCommandsAtom::getSize() const
2572{
2573 uint32_t len = macho_sub_framework_command::name_offset + strlen(fName);
2574 len = (len+7) & (-8); // 8-byte align
2575 return len;
2576}
2577
2578void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2579{
2580 uint64_t size = this->getSize();
2581 uint8_t buffer[size];
2582 bzero(buffer, size);
2583 macho_sub_framework_command* cmd = (macho_sub_framework_command*)buffer;
2584 cmd->set_cmd(LC_SUB_FRAMEWORK);
2585 cmd->set_cmdsize(this->getSize());
2586 cmd->set_name_offset();
2587 strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName);
2588 writer.write(0, buffer, size);
2589}
2590
2591uint64_t ThreadsLoadCommandsAtom::getSize() const
2592{
2593#if defined(ARCH_PPC)
2594 uint32_t stateSize = 40; // PPC_THREAD_STATE_COUNT;
2595#elif defined(ARCH_PPC64)
2596 uint32_t stateSize = 76; // PPC_THREAD_STATE64_COUNT;
2597#elif defined(ARCH_I386)
2598 uint32_t stateSize = 16; // i386_THREAD_STATE_COUNT;
2599#else
2600 #error unknown architecture
2601#endif
2602 return macho_thread_command::size + stateSize*4;
2603}
2604
2605void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2606{
2607 uint64_t size = this->getSize();
2608 uint8_t buffer[size];
2609 uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
2610 bzero(buffer, size);
2611 macho_thread_command* cmd = (macho_thread_command*)buffer;
2612 cmd->set_cmd(LC_UNIXTHREAD);
2613 cmd->set_cmdsize(size);
2614#if defined(ARCH_PPC)
2615 cmd->set_flavor(1); // PPC_THREAD_STATE
2616 cmd->set_count(40); // PPC_THREAD_STATE_COUNT;
2617 cmd->set_threadState32(0, start);
2618 if ( fWriter.fOptions.hasCustomStack() )
2619 cmd->set_threadState32(3, fWriter.fOptions.customStackAddr()); // r1
2620#elif defined(ARCH_PPC64)
2621 cmd->set_flavor(5); // PPC_THREAD_STATE64
2622 cmd->set_count(76); // PPC_THREAD_STATE64_COUNT;
2623 cmd->set_threadState64(0, start);
2624 if ( fWriter.fOptions.hasCustomStack() )
2625 cmd->set_threadState64(6, fWriter.fOptions.customStackAddr()); // r1
2626#elif defined(ARCH_I386)
2627 cmd->set_flavor(0xFFFFFFFF); // i386_THREAD_STATE
2628 cmd->set_count(16); // i386_THREAD_STATE_COUNT;
2629 cmd->set_threadState32(0, start);
2630 if ( fWriter.fOptions.hasCustomStack() )
2631 cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); // uesp
2632#else
2633 #error unknown architecture
2634#endif
2635 writer.write(0, buffer, size);
2636}
2637
2638
2639
2640uint64_t LoadCommandsPaddingAtom::getSize() const
2641{
2642 return fSize;
2643}
2644
2645void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2646{
2647 uint8_t buffer[fSize];
2648 bzero(buffer, fSize);
2649 writer.write(0, buffer, fSize);
2650}
2651
2652
2653uint64_t LinkEditAtom::getFileOffset() const
2654{
2655 return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
2656}
2657
2658
2659uint64_t LocalRelocationsLinkEditAtom::getSize() const
2660{
2661 return fWriter.fInternalRelocs.size() * macho_relocation_info::size;
2662}
2663
2664void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2665{
2666 writer.write(0, &fWriter.fInternalRelocs[0], this->getSize());
2667}
2668
2669
2670
2671uint64_t SymbolTableLinkEditAtom::getSize() const
2672{
2673 return fWriter.fSymbolTableCount * macho_nlist::size;
2674}
2675
2676void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2677{
2678 writer.write(0, fWriter.fSymbolTable, this->getSize());
2679}
2680
2681uint64_t ExternalRelocationsLinkEditAtom::getSize() const
2682{
2683 return fWriter.fExternalRelocs.size() * macho_relocation_info::size;
2684}
2685
2686void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2687{
2688 writer.write(0, &fWriter.fExternalRelocs[0], this->getSize());
2689}
2690
2691
2692
2693uint64_t IndirectTableLinkEditAtom::getSize() const
2694{
2695 return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t);
2696}
2697
2698void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2699{
2700 uint64_t size = this->getSize();
2701 uint8_t buffer[size];
2702 bzero(buffer, size);
2703 const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size();
2704 uint32_t* indirectTable = (uint32_t*)buffer;
2705 for (uint32_t i=0; i < indirectTableSize; ++i) {
2706 Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i];
2707 if ( entry.indirectIndex < indirectTableSize ) {
2708 ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
2709 }
2710 else {
6e880c60 2711 throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, entry.indirectIndex);
c2646906
A
2712 }
2713 }
2714 writer.write(0, buffer, size);
2715}
2716
2717
2718
2719StringsLinkEditAtom::StringsLinkEditAtom(Writer& writer)
2720 : LinkEditAtom(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
2721{
2722 fCurrentBuffer = new char[kBufferSize];
2723 // burn first byte of string pool (so zero is never a valid string offset)
2724 fCurrentBuffer[fCurrentBufferUsed++] = ' ';
2725 // make offset 1 always point to an empty string
2726 fCurrentBuffer[fCurrentBufferUsed++] = '\0';
2727}
2728
2729uint64_t StringsLinkEditAtom::getSize() const
2730{
2731 return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
2732}
2733
2734void StringsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2735{
2736 uint64_t offset = 0;
2737 for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
2738 writer.write(offset, fFullBuffers[i], kBufferSize);
2739 offset += kBufferSize;
2740 }
2741 writer.write(offset, fCurrentBuffer, fCurrentBufferUsed);
2742}
2743
2744int32_t StringsLinkEditAtom::add(const char* name)
2745{
2746 int lenNeeded = strlen(name)+1;
2747 while ( lenNeeded + fCurrentBufferUsed >= kBufferSize ) {
2748 // first part of string fits in current buffer
2749 int firstLen = kBufferSize - fCurrentBufferUsed;
2750 memcpy(&fCurrentBuffer[fCurrentBufferUsed], name, firstLen);
2751 // alloc next buffer
2752 fFullBuffers.push_back(fCurrentBuffer);
2753 fCurrentBuffer = new char[kBufferSize];
2754 fCurrentBufferUsed = 0;
2755 // advance name to second part
2756 name += firstLen;
2757 lenNeeded -= firstLen;
2758 }
2759 //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed);
2760 // string all fits in current buffer
2761 strcpy(&fCurrentBuffer[fCurrentBufferUsed], name);
2762 int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
2763 fCurrentBufferUsed += lenNeeded;
2764 return offset;
2765}
2766
2767// returns the index of an empty string
2768int32_t StringsLinkEditAtom::emptyString()
2769{
2770 return 1;
2771}
2772
6e880c60
A
2773#if defined(ARCH_PPC) || defined(ARCH_PPC64)
2774BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
2775 : WriterAtom(writer, fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
2776{
2777 char* buf = new char[strlen(name)+32];
2778 if ( targetOffset == 0 ) {
2779 if ( islandRegion == 0 )
2780 sprintf(buf, "%s$island", name);
2781 else
2782 sprintf(buf, "%s$island_%d", name, islandRegion);
2783 }
2784 else {
2785 sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
2786 }
2787 fName = buf;
2788}
2789
2790
2791void BranchIslandAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
2792{
2793 int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
2794 uint8_t instruction[4];
2795 int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
2796 OSWriteBigInt32(&instruction, 0, branchInstruction);
2797 writer.write(0, &instruction, 4);
2798}
2799
2800
2801#endif
c2646906
A
2802
2803
2804};
2805
2806
2807