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