]> git.saurik.com Git - apple/ld64.git/blob - src/MachOReaderRelocatable.hpp
ea6f6de2c9597558a741947c8eee06385d75516d
[apple/ld64.git] / src / MachOReaderRelocatable.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #ifndef __OBJECT_FILE_MACH_O__
26 #define __OBJECT_FILE_MACH_O__
27
28 #include <stdint.h>
29 #include <math.h>
30 #include <unistd.h>
31 #include <sys/param.h>
32 #include <mach-o/ppc/reloc.h>
33 #include <mach-o/stab.h>
34 #include <mach-o/x86_64/reloc.h>
35 #ifndef S_ATTR_DEBUG
36 #define S_ATTR_DEBUG 0x02000000
37 #endif
38
39 #include <vector>
40 #include <set>
41 #include <algorithm>
42
43 #include "MachOFileAbstraction.hpp"
44 #include "Architectures.hpp"
45 #include "ObjectFile.h"
46 #include "dwarf2.h"
47 #include "debugline.h"
48
49
50 //
51 //
52 // To implement architecture xxx, you must write template specializations for the following six methods:
53 // Reader<xxx>::validFile()
54 // Reader<xxx>::validSectionType()
55 // Reader<xxx>::addRelocReference()
56 // Reference<xxx>::getDescription()
57 //
58 //
59
60
61
62 extern __attribute__((noreturn)) void throwf(const char* format, ...);
63
64 namespace mach_o {
65 namespace relocatable {
66
67
68
69 // forward reference
70 template <typename A> class Reader;
71 template <typename A> class SymbolAtomSorter;
72
73 struct AtomAndOffset
74 {
75 AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
76 AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
77 ObjectFile::Atom* atom;
78 uint32_t offset;
79 };
80
81
82 template <typename A>
83 class Reference : public ObjectFile::Reference
84 {
85 public:
86 typedef typename A::P P;
87 typedef typename A::P::uint_t pint_t;
88 typedef typename A::ReferenceKinds Kinds;
89
90 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
91 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
92 Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
93
94 virtual ~Reference() {}
95
96
97 virtual bool isTargetUnbound() const { return ( fToTarget.atom == NULL ); }
98 virtual bool isFromTargetUnbound() const { return ( fFromTarget.atom == NULL ); }
99 virtual uint8_t getKind() const { return (uint8_t)fKind; }
100 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
101 virtual const char* getTargetName() const { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); }
102 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
103 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
104 virtual bool hasFromTarget() const { return ( (fFromTarget.atom != NULL) || (fFromTargetName != NULL) ); }
105 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
106 virtual const char* getFromTargetName() const { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); }
107 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = &target; fToTarget.offset = offset; }
108 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
109 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = &target; }
110 virtual void setFromTargetName(const char* name) { fFromTargetName = name; }
111 virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; }
112 virtual const char* getDescription() const;
113 virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; }
114
115
116 private:
117 pint_t fFixUpOffsetInSrc;
118 AtomAndOffset fToTarget;
119 AtomAndOffset fFromTarget;
120 const char* fToTargetName;
121 const char* fFromTargetName;
122 Kinds fKind;
123 };
124
125
126 template <typename A>
127 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
128 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
129 fKind(kind)
130 {
131 // make reference a by-name unless:
132 // - the reference type is only used with direct references
133 // - the target is translation unit scoped
134 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn)
135 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) ) {
136 //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d\n", toTarget.atom, fToTargetName, toTarget.atom->getScope());
137 fToTargetName = toTarget.atom->getName();
138 fToTarget.atom = NULL;
139 }
140 ((class BaseAtom*)at.atom)->addReference(this);
141 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
142 }
143
144 template <typename A>
145 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
146 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
147 fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
148 {
149 // make reference a by-name where needed
150 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn)
151 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
152 && (toTarget.atom != at.atom) ) {
153 fToTargetName = toTarget.atom->getName();
154 fToTarget.atom = NULL;
155 }
156 ((class BaseAtom*)at.atom)->addReference(this);
157 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
158 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
159 }
160
161 template <typename A>
162 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
163 : fFixUpOffsetInSrc(at.offset),
164 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
165 {
166 fToTarget.offset = toOffset;
167 ((class BaseAtom*)at.atom)->addReference(this);
168 }
169
170
171 template <typename A>
172 class Segment : public ObjectFile::Segment
173 {
174 public:
175 Segment(const macho_section<typename A::P>* sect);
176 virtual const char* getName() const { return fSection->segname(); }
177 virtual bool isContentReadable() const { return true; }
178 virtual bool isContentWritable() const { return fWritable; }
179 virtual bool isContentExecutable() const { return fExecutable; }
180 private:
181 const macho_section<typename A::P>* fSection;
182 bool fWritable;
183 bool fExecutable;
184 };
185
186 template <typename A>
187 Segment<A>::Segment(const macho_section<typename A::P>* sect)
188 : fSection(sect), fWritable(true), fExecutable(false)
189 {
190 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
191 fWritable = false;
192 fExecutable = true;
193 }
194 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
195 fWritable = true;
196 fExecutable = true;
197 }
198 }
199
200
201 class DataSegment : public ObjectFile::Segment
202 {
203 public:
204 virtual const char* getName() const { return "__DATA"; }
205 virtual bool isContentReadable() const { return true; }
206 virtual bool isContentWritable() const { return true; }
207 virtual bool isContentExecutable() const { return false; }
208
209 static DataSegment fgSingleton;
210 };
211
212 DataSegment DataSegment::fgSingleton;
213
214
215 class BaseAtom : public ObjectFile::Atom
216 {
217 public:
218 BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
219
220 virtual void setSize(uint64_t size) = 0;
221 virtual void addReference(ObjectFile::Reference* ref) = 0;
222 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
223 virtual void alignAtLeast(uint8_t align) = 0;
224
225 uint32_t fStabsStartIndex;
226 uint32_t fStabsCount;
227 };
228
229
230 //
231 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
232 // pointing to it. A C function or global variable is represented by one of these atoms.
233 //
234 //
235 template <typename A>
236 class SymbolAtom : public BaseAtom
237 {
238 public:
239 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
240 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
241 { return fOwner.getTranslationUnitSource(dir, name); }
242 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
243 virtual const char* getDisplayName() const { return getName(); }
244 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
245 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
246 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
247 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
248 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
249 virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
250 virtual uint64_t getSize() const { return fSize; }
251 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
252 virtual bool mustRemainInSection() const { return true; }
253 virtual const char* getSectionName() const;
254 virtual Segment<A>& getSegment() const { return *fSegment; }
255 virtual bool requiresFollowOnAtom() const;
256 virtual ObjectFile::Atom& getFollowOnAtom() const;
257 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
258 virtual uint8_t getAlignment() const { return fAlignment; }
259 virtual void copyRawContent(uint8_t buffer[]) const;
260 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
261 virtual void setSize(uint64_t size);
262 virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
263 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
264 virtual void alignAtLeast(uint8_t align) { fAlignment = std::max(align, fAlignment); }
265
266 protected:
267 typedef typename A::P P;
268 typedef typename A::P::E E;
269 typedef typename A::P::uint_t pint_t;
270 typedef typename A::ReferenceKinds Kinds;
271 typedef typename std::vector<Reference<A>*> ReferenceVector;
272 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
273 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
274 friend class Reader<A>;
275 friend class SymbolAtomSorter<A>;
276
277 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
278 virtual ~SymbolAtom() {}
279
280 Reader<A>& fOwner;
281 const macho_nlist<P>* fSymbol;
282 pint_t fAddress;
283 pint_t fSize;
284 const macho_section<P>* fSection;
285 Segment<A>* fSegment;
286 ReferenceVector fReferences;
287 std::vector<ObjectFile::LineInfo> fLineInfo;
288 ObjectFile::Atom::Scope fScope;
289 SymbolTableInclusion fSymbolTableInclusion;
290 uint8_t fAlignment;
291 };
292
293
294 template <typename A>
295 SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
296 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fAlignment(0)
297 {
298 uint8_t type = symbol->n_type();
299 if ( (type & N_EXT) == 0 )
300 fScope = ObjectFile::Atom::scopeTranslationUnit;
301 else if ( (type & N_PEXT) != 0 )
302 fScope = ObjectFile::Atom::scopeLinkageUnit;
303 else
304 fScope = ObjectFile::Atom::scopeGlobal;
305 if ( (type & N_TYPE) == N_SECT ) {
306 // real definition
307 fSegment = new Segment<A>(fSection);
308 fAddress = fSymbol->n_value();
309 }
310 else {
311 printf("unknown symbol type: %d\n", type);
312 }
313 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
314 // support for .o files built with old ld64
315 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
316 const char* name = this->getName();
317 const int nameLen = strlen(name);
318 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
319 // switch symbol to point at name that does not have trailing $stub
320 char correctName[nameLen];
321 strncpy(correctName, name, nameLen-5);
322 correctName[nameLen-5] = '\0';
323 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
324 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
325 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
326 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
327 fSymbol = s;
328 break;
329 }
330 }
331 }
332 }
333 // support for labeled stubs
334 switch ( section->flags() & SECTION_TYPE ) {
335 case S_SYMBOL_STUBS:
336 setSize(section->reserved2());
337 break;
338 case S_LAZY_SYMBOL_POINTERS:
339 case S_NON_LAZY_SYMBOL_POINTERS:
340 setSize(sizeof(pint_t));
341 break;
342 case S_4BYTE_LITERALS:
343 setSize(4);
344 break;
345 case S_8BYTE_LITERALS:
346 setSize(8);
347 break;
348 case S_16BYTE_LITERALS:
349 setSize(16);
350 break;
351 case S_CSTRING_LITERALS:
352 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
353 break;
354 case S_REGULAR:
355 case S_ZEROFILL:
356 case S_COALESCED:
357 // size calculate later after next atom is found
358 break;
359 }
360
361 // compute whether this atom needs to be in symbol table
362 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
363 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
364 }
365 else if ( fOwner.fOptions.fForFinalLinkedImage
366 && ((section->flags() & SECTION_TYPE) == S_COALESCED)
367 && ((section->flags() & S_ATTR_NO_TOC) == S_ATTR_NO_TOC)
368 && ((section->flags() & S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS)
369 && (strcmp(section->sectname(), "__eh_frame") == 0) ) {
370 // .eh symbols exist so the linker can associate them with functions
371 // removing them from final linked images is a big space savings rdar://problem/4180168
372 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
373 }
374 else if ( fOwner.fOptions.fForFinalLinkedImage
375 && ((section->flags() & SECTION_TYPE) == S_REGULAR)
376 && (strncmp(section->sectname(), "__gcc_except_tab", 16) == 0)
377 && (strncmp(this->getName(), "GCC_except_table", 16) == 0) ) {
378 // GCC_except_table* symbols don't need to exist in final linked image
379 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
380 }
381 else {
382 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
383 }
384 }
385
386
387 template <typename A>
388 void SymbolAtom<A>::setSize(uint64_t size)
389 {
390 fSize = size;
391
392 if ( fSection->flags() & S_ATTR_SOME_INSTRUCTIONS ) {
393 // For code, the aligment is based just on the section alignment and code address
394 if ( fAddress == 0 )
395 fAlignment = fSection->align();
396 else
397 fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), (uint8_t)fSection->align());
398 }
399 else {
400 // For data, compute the alignment base on the address aligned at in object file and the size
401 uint8_t sizeAlign = __builtin_ctz(fSize);
402 uint8_t sizeAndSectAlign = std::min((uint8_t)fSection->align(), sizeAlign);
403 // If address is zero, can't figure out better alignment than section alignment and size
404 if ( fAddress == 0 )
405 fAlignment = sizeAndSectAlign;
406 else
407 fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), sizeAndSectAlign);
408 }
409 }
410
411
412 template <typename A>
413 const char* SymbolAtom<A>::getSectionName() const
414 {
415 if ( strlen(fSection->sectname()) > 15 ) {
416 static char temp[18];
417 strncpy(temp, fSection->sectname(), 16);
418 temp[17] = '\0';
419 return temp;
420 }
421 return fSection->sectname();
422 }
423
424 template <typename A>
425 bool SymbolAtom<A>::requiresFollowOnAtom() const
426 {
427 // requires follow-on if built with old compiler and not the last atom
428 if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
429 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
430 Reference<A>* ref = *it;
431 if ( ref->getKind() == A::kFollowOn )
432 return true;
433 }
434 }
435 return false;
436 }
437
438 template <typename A>
439 ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
440 {
441 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
442 Reference<A>* ref = *it;
443 if ( ref->getKind() == A::kFollowOn )
444 return ref->getTarget();
445 }
446 return *((ObjectFile::Atom*)NULL);
447 }
448
449
450
451
452 template <typename A>
453 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
454 {
455 // copy base bytes
456 if ( isZeroFill() )
457 bzero(buffer, fSize);
458 else {
459 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
460 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
461 }
462 }
463
464
465 template <typename A>
466 class SymbolAtomSorter
467 {
468 public:
469 SymbolAtomSorter(std::map<uint32_t, BaseAtom*>& map) : fMap(map) {}
470
471 typedef typename A::P::uint_t pint_t;
472
473 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
474 {
475 pint_t leftAddr = ((SymbolAtom<A>*)left)->fAddress;
476 pint_t rightAddr = ((SymbolAtom<A>*)right)->fAddress;
477 if ( leftAddr == rightAddr ) {
478 // two atoms with same address, must have been a function with multiple labels
479 // make sure we sort these so the one with real content (in map) is last
480 std::map<uint32_t, BaseAtom*>::iterator pos = fMap.find(leftAddr);
481 if ( pos != fMap.end() ) {
482 return ( pos->second == right );
483 }
484 return false;
485 }
486 else {
487 return ( leftAddr < rightAddr );
488 }
489 }
490 private:
491 std::map<uint32_t, BaseAtom*>& fMap;
492 };
493
494
495 //
496 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
497 // For instance, "int foo;" is neither a declaration or a definition and
498 // is represented by a TentativeAtom.
499 //
500 template <typename A>
501 class TentativeAtom : public BaseAtom
502 {
503 public:
504 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
505 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
506 { return fOwner.getTranslationUnitSource(dir, name); }
507 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
508 virtual const char* getDisplayName() const { return getName(); }
509 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
510 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
511 virtual bool isZeroFill() const { return true; }
512 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
513 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
514 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
515 virtual uint64_t getSize() const { return fSymbol->n_value(); }
516 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
517 virtual bool mustRemainInSection() const { return true; }
518 virtual const char* getSectionName() const { return "__common"; }
519 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
520 virtual bool requiresFollowOnAtom() const { return false; }
521 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
522 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
523 virtual uint8_t getAlignment() const;
524 virtual void copyRawContent(uint8_t buffer[]) const;
525 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
526 virtual void setSize(uint64_t size) { }
527 virtual void addReference(ObjectFile::Reference* ref) { throw "ld64: can't add references"; }
528 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld64: can't add line info to tentative definition"; }
529 virtual void alignAtLeast(uint8_t align) { }
530
531 protected:
532 typedef typename A::P P;
533 typedef typename A::P::E E;
534 typedef typename A::P::uint_t pint_t;
535 typedef typename A::ReferenceKinds Kinds;
536 friend class Reader<A>;
537
538 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
539 virtual ~TentativeAtom() {}
540
541 Reader<A>& fOwner;
542 const macho_nlist<P>* fSymbol;
543 ObjectFile::Atom::Scope fScope;
544 static std::vector<ObjectFile::Reference*> fgNoReferences;
545 };
546
547 template <typename A>
548 std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
549
550 template <typename A>
551 TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
552 : fOwner(owner), fSymbol(symbol)
553 {
554 uint8_t type = symbol->n_type();
555 if ( (type & N_EXT) == 0 )
556 fScope = ObjectFile::Atom::scopeTranslationUnit;
557 else if ( (type & N_PEXT) != 0 )
558 fScope = ObjectFile::Atom::scopeLinkageUnit;
559 else
560 fScope = ObjectFile::Atom::scopeGlobal;
561 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
562 // tentative definition
563 }
564 else {
565 printf("unknown symbol type: %d\n", type);
566 }
567 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
568 }
569
570
571 template <typename A>
572 uint8_t TentativeAtom<A>::getAlignment() const
573 {
574 // common symbols align to their size
575 // that is, a 4-byte common aligns to 4-bytes
576 // to be safe, odd size commons align to the next power-of-2 size
577 uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
578 // limit alignment of extremely large commons to 2^15 bytes (8-page)
579 if ( alignment < 15 )
580 return alignment;
581 else
582 return 15;
583 }
584
585 template <typename A>
586 void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
587 {
588 bzero(buffer, getSize());
589 }
590
591
592 //
593 // An AnonymousAtom represents compiler generated data that has no name.
594 // For instance, a literal C-string or a 64-bit floating point constant
595 // is represented by an AnonymousAtom.
596 //
597 template <typename A>
598 class AnonymousAtom : public BaseAtom
599 {
600 public:
601 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
602 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
603 virtual const char* getName() const { return fSynthesizedName; }
604 virtual const char* getDisplayName() const;
605 virtual ObjectFile::Atom::Scope getScope() const;
606 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const;
607 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
608 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
609 virtual bool isZeroFill() const;
610 virtual uint64_t getSize() const { return fSize; }
611 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
612 virtual bool mustRemainInSection() const { return true; }
613 virtual const char* getSectionName() const;
614 virtual Segment<A>& getSegment() const { return *fSegment; }
615 virtual bool requiresFollowOnAtom() const;
616 virtual ObjectFile::Atom& getFollowOnAtom() const;
617 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
618 virtual uint8_t getAlignment() const;
619 virtual void copyRawContent(uint8_t buffer[]) const;
620 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
621 virtual void setSize(uint64_t size) { fSize = size; }
622 virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
623 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fprintf(stderr, "ld64: can't add line info to anonymous symbol %s from %s\n", this->getDisplayName(), this->getFile()->getPath()); }
624 virtual void alignAtLeast(uint8_t align) { }
625 BaseAtom* redirectTo() { return fRedirect; }
626 bool isWeakImportStub() { return fWeakImportStub; }
627
628 protected:
629 typedef typename A::P P;
630 typedef typename A::P::E E;
631 typedef typename A::P::uint_t pint_t;
632 typedef typename A::ReferenceKinds Kinds;
633 typedef typename std::vector<Reference<A>*> ReferenceVector;
634 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
635 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
636 friend class Reader<A>;
637
638 AnonymousAtom(Reader<A>&, const macho_section<P>*, uint32_t addr, uint32_t size);
639 virtual ~AnonymousAtom() {}
640
641 Reader<A>& fOwner;
642 const char* fSynthesizedName;
643 const macho_section<P>* fSection;
644 uint32_t fAddress;
645 uint32_t fSize;
646 Segment<A>* fSegment;
647 ReferenceVector fReferences;
648 BaseAtom* fRedirect;
649 bool fDontDeadStrip;
650 bool fWeakImportStub;
651 bool fReallyNonLazyPointer; // HACK until compiler stops emitting anonymous non-lazy pointers
652 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
653 ObjectFile::Atom::Scope fScope;
654 };
655
656 template <typename A>
657 AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, uint32_t addr, uint32_t size)
658 : fOwner(owner), fSynthesizedName(NULL), fSection(section), fAddress(addr), fSize(size), fSegment(NULL), fDontDeadStrip(true),
659 fWeakImportStub(false), fReallyNonLazyPointer(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
660 fScope(ObjectFile::Atom::scopeTranslationUnit)
661 {
662 fSegment = new Segment<A>(fSection);
663 fRedirect = this;
664 uint8_t type = fSection->flags() & SECTION_TYPE;
665 switch ( type ) {
666 case S_ZEROFILL:
667 {
668 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
669 }
670 break;
671 case S_REGULAR:
672 if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
673 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
674 uint32_t classNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 2*sizeof(pint_t) - section->addr()));
675 const char* str = (char*)(owner.fHeader) + section->offset() + classNameAddr - section->addr();
676 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", str);
677 if ( fOwner.fOptions.fForFinalLinkedImage )
678 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
679 else
680 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
681 fScope = ObjectFile::Atom::scopeGlobal;
682 }
683 else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
684 // handle .o files created by old ld64 -r that are missing cstring section type
685 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
686 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
687 }
688 break;
689 case S_CSTRING_LITERALS:
690 {
691 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
692 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
693 fScope = ObjectFile::Atom::scopeLinkageUnit;
694 fDontDeadStrip = false;
695 }
696 break;
697 case S_4BYTE_LITERALS:
698 {
699 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
700 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
701 fScope = ObjectFile::Atom::scopeLinkageUnit;
702 fDontDeadStrip = false;
703 }
704 break;
705 case S_8BYTE_LITERALS:
706 {
707 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
708 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
709 fScope = ObjectFile::Atom::scopeLinkageUnit;
710 fDontDeadStrip = false;
711 }
712 break;
713 case S_16BYTE_LITERALS:
714 {
715 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
716 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
717 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
718 fScope = ObjectFile::Atom::scopeLinkageUnit;
719 fDontDeadStrip = false;
720 }
721 break;
722 case S_LITERAL_POINTERS:
723 {
724 uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
725 const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
726 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
727 fScope = ObjectFile::Atom::scopeLinkageUnit;
728 }
729 break;
730 case S_MOD_INIT_FUNC_POINTERS:
731 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
732 break;
733 case S_MOD_TERM_FUNC_POINTERS:
734 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
735 break;
736 case S_SYMBOL_STUBS:
737 {
738 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
739 index += fSection->reserved1();
740 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
741 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
742 uint32_t strOffset = sym->n_strx();
743 // want name to not have $stub suffix, this is what automatic stub generation expects
744 fSynthesizedName = &fOwner.fStrings[strOffset];
745 // check for weak import
746 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
747 // sometimes the compiler gets confused and generates a stub to a static function
748 // if so, we should redirect any call to the stub to be calls to the real static function atom
749 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_desc() & N_WEAK_DEF) == 0) ) {
750 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
751 if ( staticAtom != NULL )
752 fRedirect = staticAtom;
753 }
754 fScope = ObjectFile::Atom::scopeLinkageUnit;
755 }
756 break;
757 case S_LAZY_SYMBOL_POINTERS:
758 case S_NON_LAZY_SYMBOL_POINTERS:
759 {
760 fDontDeadStrip = false;
761 fScope = ObjectFile::Atom::scopeLinkageUnit;
762 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
763 index += fSection->reserved1();
764 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
765 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
766 // Silly codegen with non-lazy pointer to a local symbol
767 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
768 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
769 // All atoms not created yet, so we need to scan symbol table
770 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
771 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
772 if ( ((sym->n_type() & N_TYPE) == N_SECT)
773 && ((sym->n_type() & N_STAB) == 0)
774 && (sym->n_value() == nonLazyPtrValue) ) {
775 const char* name = &fOwner.fStrings[sym->n_strx()];
776 char* str = new char[strlen(name)+16];
777 strcpy(str, name);
778 strcat(str, "$non_lazy_ptr");
779 fSynthesizedName = str;
780 // add direct reference to target later, because its atom may not be constructed yet
781 fOwner.fLocalNonLazys.push_back(this);
782 fScope = ObjectFile::Atom::scopeTranslationUnit;
783 return;
784 }
785 }
786 throwf("malformed .o file: non-lazy-pointer at address 0x%08X with value 0x%0llX missing symbol", addr, (uint64_t)nonLazyPtrValue);
787 }
788 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
789 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
790 char* str = new char[strlen(name)+16];
791 strcpy(str, name);
792 if ( type == S_LAZY_SYMBOL_POINTERS )
793 strcat(str, "$lazy_ptr");
794 else
795 strcat(str, "$non_lazy_ptr");
796 fSynthesizedName = str;
797
798 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
799 // target is translation unit scoped, so add direct reference to target
800 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
801 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
802 }
803 else {
804 if ( fOwner.isWeakImportSymbol(targetSymbol) )
805 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
806 else
807 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
808 }
809 }
810 break;
811 default:
812 throwf("section type %d not supported with address=0x%08X", type, addr);
813 }
814 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
815 }
816
817
818 template <typename A>
819 const char* AnonymousAtom<A>::getDisplayName() const
820 {
821 if ( fSynthesizedName != NULL )
822 return fSynthesizedName;
823
824 static char temp[512];
825 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
826 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
827 sprintf(temp, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
828 }
829 else {
830 sprintf(temp, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
831 }
832 return temp;
833 }
834
835 template <typename A>
836 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
837 {
838 if ( fReallyNonLazyPointer )
839 return ObjectFile::Atom::scopeTranslationUnit;
840 else
841 return fScope;
842 }
843
844 template <typename A>
845 ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
846 {
847 if ( fReallyNonLazyPointer )
848 return ObjectFile::Atom::kRegularDefinition;
849 // in order for literals to be coalesced they must be weak
850 switch ( fSection->flags() & SECTION_TYPE ) {
851 case S_CSTRING_LITERALS:
852 case S_4BYTE_LITERALS:
853 case S_8BYTE_LITERALS:
854 case S_16BYTE_LITERALS:
855 case S_NON_LAZY_SYMBOL_POINTERS:
856 case S_LITERAL_POINTERS:
857 return ObjectFile::Atom::kWeakDefinition;
858 default:
859 return ObjectFile::Atom::kRegularDefinition;
860 }
861 }
862
863 template <typename A>
864 bool AnonymousAtom<A>::isZeroFill() const
865 {
866 return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
867 }
868
869
870 template <typename A>
871 const char* AnonymousAtom<A>::getSectionName() const
872 {
873 if ( strlen(fSection->sectname()) > 15 ) {
874 static char temp[18];
875 strncpy(temp, fSection->sectname(), 16);
876 temp[17] = '\0';
877 return temp;
878 }
879 return fSection->sectname();
880 }
881
882 template <typename A>
883 uint8_t AnonymousAtom<A>::getAlignment() const
884 {
885 if ( fReallyNonLazyPointer )
886 return (uint8_t)log2(sizeof(pint_t));
887 switch ( fSection->flags() & SECTION_TYPE ) {
888 case S_4BYTE_LITERALS:
889 return 2;
890 case S_8BYTE_LITERALS:
891 return 3;
892 case S_16BYTE_LITERALS:
893 return 4;
894 case S_NON_LAZY_SYMBOL_POINTERS:
895 return (uint8_t)log2(sizeof(pint_t));
896 default:
897 return fSection->align();
898 }
899 }
900
901 template <typename A>
902 bool AnonymousAtom<A>::requiresFollowOnAtom() const
903 {
904 // requires follow-on if built with old compiler and not the last atom
905 if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
906 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
907 Reference<A>* ref = *it;
908 if ( ref->getKind() == A::kFollowOn )
909 return true;
910 }
911 }
912 return false;
913 }
914
915 template <typename A>
916 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
917 {
918 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
919 Reference<A>* ref = *it;
920 if ( ref->getKind() == A::kFollowOn )
921 return ref->getTarget();
922 }
923 return *((ObjectFile::Atom*)NULL);
924 }
925
926 template <typename A>
927 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
928 {
929 // copy base bytes
930 if ( isZeroFill() )
931 bzero(buffer, fSize);
932 else {
933 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
934 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
935 }
936 }
937
938
939
940
941 template <typename A>
942 class Reader : public ObjectFile::Reader
943 {
944 public:
945 static bool validFile(const uint8_t* fileContent);
946 static Reader<A>* make(const uint8_t* fileContent, const char* path, time_t modTime,
947 const ObjectFile::ReaderOptions& options)
948 { return new Reader<A>(fileContent, path, modTime, options); }
949 virtual ~Reader() {}
950
951 virtual const char* getPath() { return fPath; }
952 virtual time_t getModificationTime() { return fModTime; }
953 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
954 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
955 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
956 virtual std::vector<Stab>* getStabs() { return &fStabs; }
957
958 bool getTranslationUnitSource(const char** dir, const char** name) const;
959
960 private:
961 typedef typename A::P P;
962 typedef typename A::P::E E;
963 typedef typename A::P::uint_t pint_t;
964 //typedef typename std::vector<Atom<A>*> AtomVector;
965 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
966 typedef typename A::ReferenceKinds Kinds;
967 friend class AnonymousAtom<A>;
968 friend class TentativeAtom<A>;
969 friend class SymbolAtom<A>;
970 Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options);
971 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
972 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
973 Kinds pointerDiffKindForLength_powerpc(uint8_t r_length);
974 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
975 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
976 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
977 static const char* assureFullPath(const char* path);
978 AtomAndOffset findAtomAndOffset(uint32_t addr);
979 AtomAndOffset findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr);
980 Reference<A>* makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr);
981 Reference<A>* makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr);
982 Reference<A>* makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr);
983 Reference<A>* makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr);
984 Reference<A>* makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset);
985 Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
986 Reference<A>* makeReferenceToSymbol(Kinds kind, uint32_t atAddr, const macho_nlist<P>* toSymbol, uint32_t toOffset);
987 void validSectionType(uint8_t type);
988 void handleAnonymousNonLazyPointers(const macho_section<P>* sect);
989
990 BaseAtom* findAtomByName(const char*);
991
992 const char* fPath;
993 time_t fModTime;
994 const ObjectFile::ReaderOptions& fOptions;
995 const macho_header<P>* fHeader;
996 const char* fStrings;
997 const macho_nlist<P>* fSymbols;
998 uint32_t fSymbolCount;
999 const macho_segment_command<P>* fSegment;
1000 const uint32_t* fIndirectTable;
1001 std::vector<ObjectFile::Atom*> fAtoms;
1002 std::map<uint32_t, BaseAtom*> fAddrToAtom;
1003 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
1004 ObjectFile::Reader::DebugInfoKind fDebugInfo;
1005 bool fHasUUID;
1006 const macho_section<P>* fDwarfDebugInfoSect;
1007 const macho_section<P>* fDwarfDebugAbbrevSect;
1008 const macho_section<P>* fDwarfDebugLineSect;
1009 const char* fDwarfTranslationUnitDir;
1010 const char* fDwarfTranslationUnitFile;
1011 std::map<uint32_t,const char*> fDwarfIndexToFile;
1012 std::vector<Stab> fStabs;
1013 bool fAppleObjc;
1014 };
1015
1016 // usually do nothing
1017 template <typename A> void Reader<A>::handleAnonymousNonLazyPointers(const macho_section<P>* sect) { }
1018
1019 // HACK for ppc64, need to split of anonymous non-lazy-pointers because they must be 8-byte aligned to work with ld instruction
1020 template <> void
1021 Reader<ppc64>::handleAnonymousNonLazyPointers(const macho_section<P>* dataSect) {
1022 if ( (dataSect->size() >= sizeof(pint_t))
1023 && (dataSect->align() >= log2(sizeof(pint_t)))
1024 && (strcmp(dataSect->sectname(), "__data") == 0)
1025 && (strcmp(dataSect->segname(), "__DATA") == 0) ) {
1026 std::set<uint32_t> lo14targets;
1027 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1028 const macho_section<P>* const sectionsEnd = &sectionsStart[fSegment->nsects()];
1029 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1030 if ( strncmp(sect->sectname(), "__text", 6) == 0 ) {
1031 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
1032 const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
1033 for (const macho_relocation_info<P>* r = relocs; r < relocsEnd; ++r) {
1034 if ( (r->r_address() & R_SCATTERED) != 0 ) {
1035 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)r;
1036 if ( sreloc->r_type() == PPC_RELOC_LO14_SECTDIFF ) {
1037 lo14targets.insert(sreloc->r_value());
1038 }
1039 }
1040 }
1041 }
1042 }
1043 // walk backwards so that newly created anonymous atoms do not mask misalignmented
1044 for (std::set<uint32_t>::reverse_iterator it=lo14targets.rbegin(); it != lo14targets.rend(); it++) {
1045 uint32_t targetOfLO14 = *it;
1046 AtomAndOffset found = this->findAtomAndOffset(targetOfLO14);
1047 if ( (found.offset & 0x7) != 0 ) {
1048 AnonymousAtom<ppc64>* newAtom = new AnonymousAtom<ppc64>(*this, dataSect, targetOfLO14, sizeof(pint_t));
1049 newAtom->fReallyNonLazyPointer = true;
1050 fAtoms.push_back(newAtom);
1051 fAddrToAtom[targetOfLO14] = newAtom;
1052 }
1053 }
1054 }
1055 }
1056
1057 template <typename A>
1058 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options)
1059 : fPath(strdup(path)), fModTime(modTime), fOptions(options), fHeader((const macho_header<P>*)fileContent),
1060 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
1061 fDebugInfo(kDebugInfoNone), fHasUUID(false), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL),
1062 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false)
1063 {
1064 // sanity check
1065 if ( ! validFile(fileContent) )
1066 throw "not a valid mach-o object file";
1067
1068 // cache intersting pointers
1069 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1070 const uint32_t cmd_count = header->ncmds();
1071 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
1072 const macho_load_command<P>* cmd = cmds;
1073 uint32_t undefinedStartIndex = 0;
1074 uint32_t undefinedEndIndex = 0;
1075 for (uint32_t i = 0; i < cmd_count; ++i) {
1076 switch (cmd->cmd()) {
1077 case LC_SYMTAB:
1078 {
1079 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1080 fSymbolCount = symtab->nsyms();
1081 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1082 fStrings = (char*)header + symtab->stroff();
1083 }
1084 break;
1085 case LC_DYSYMTAB:
1086 {
1087 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1088 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
1089 undefinedStartIndex = dsymtab->iundefsym();
1090 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
1091 }
1092 break;
1093 case LC_UUID:
1094 fHasUUID = true;
1095 break;
1096
1097 default:
1098 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1099 fSegment = (macho_segment_command<P>*)cmd;
1100 }
1101 break;
1102 }
1103 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
1104 }
1105 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1106 const macho_section<P>* const sectionsEnd = &sectionsStart[fSegment->nsects()];
1107
1108 // inital guess for number of atoms
1109 fAtoms.reserve(fSymbolCount);
1110
1111 // add all atoms that have entries in symbol table
1112 const macho_section<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1113 for (uint32_t i=0; i < fSymbolCount; ++i) {
1114 const macho_nlist<P>& sym = fSymbols[i];
1115 if ( (sym.n_type() & N_STAB) == 0 ) {
1116 uint8_t type = (sym.n_type() & N_TYPE);
1117 if ( type == N_SECT ) {
1118 const macho_section<P>* section = &sections[sym.n_sect()-1];
1119 bool suppress = false;
1120 // ignore atoms in debugger sections
1121 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
1122 // ignore labels for atoms in other sections
1123 switch ( section->flags() & SECTION_TYPE ) {
1124 case S_REGULAR:
1125 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
1126 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
1127 case S_ZEROFILL:
1128 case S_COALESCED:
1129 case S_4BYTE_LITERALS:
1130 case S_8BYTE_LITERALS:
1131 case S_16BYTE_LITERALS:
1132 case S_CSTRING_LITERALS:
1133 {
1134 BaseAtom* newAtom = new SymbolAtom<A>(*this, &sym, section);
1135 std::map<uint32_t, BaseAtom*>::iterator pos = fAddrToAtom.find(sym.n_value());
1136 if ( pos != fAddrToAtom.end() ) {
1137 // another label to an existing address
1138 // make this one be the real one and followed by the previous
1139 BaseAtom* existingAtom = pos->second;
1140 //fprintf(stderr, "new atom %s has same address as existing atom %s\n", newAtom->getDisplayName(), existingAtom->getDisplayName());
1141 new Reference<A>(A::kFollowOn, AtomAndOffset(newAtom), AtomAndOffset(existingAtom));
1142 newAtom->setSize(0);
1143 }
1144 else {
1145 fAddrToAtom[sym.n_value()] = newAtom;
1146 }
1147 if ( ! suppress )
1148 fAtoms.push_back(newAtom);
1149 }
1150 break;
1151 case S_SYMBOL_STUBS:
1152 case S_LAZY_SYMBOL_POINTERS:
1153 case S_NON_LAZY_SYMBOL_POINTERS:
1154 // ignore symboled stubs produces by old ld64
1155 break;
1156 default:
1157 fprintf(stderr, "ld64 warning: symbol %s found in unsupported section in %s\n",
1158 &fStrings[sym.n_strx()], this->getPath());
1159 }
1160 }
1161 }
1162 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
1163 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
1164 }
1165 else if ( (type == N_ABS) && (strncmp(&fStrings[sym.n_strx()], ".objc_class_name_", 16) == 0) ) {
1166 fAppleObjc = true;
1167 }
1168 }
1169 }
1170
1171 // sort SymbolAtoms by address
1172 std::sort(fAtoms.begin(), fAtoms.end(), SymbolAtomSorter<A>(fAddrToAtom));
1173
1174 // add all fixed size anonymous atoms from special sections
1175 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1176 uint32_t atomSize = 0;
1177 uint8_t type (sect->flags() & SECTION_TYPE);
1178 validSectionType(type);
1179 bool suppress = false;
1180 switch ( type ) {
1181 case S_SYMBOL_STUBS:
1182 suppress = true;
1183 atomSize = sect->reserved2();
1184 break;
1185 case S_LAZY_SYMBOL_POINTERS:
1186 suppress = true;
1187 atomSize = sizeof(pint_t);
1188 break;
1189 case S_NON_LAZY_SYMBOL_POINTERS:
1190 case S_LITERAL_POINTERS:
1191 case S_MOD_INIT_FUNC_POINTERS:
1192 case S_MOD_TERM_FUNC_POINTERS:
1193 atomSize = sizeof(pint_t);
1194 break;
1195 case S_INTERPOSING:
1196 atomSize = sizeof(pint_t)*2;
1197 break;
1198 case S_4BYTE_LITERALS:
1199 atomSize = 4;
1200 break;
1201 case S_8BYTE_LITERALS:
1202 atomSize = 8;
1203 break;
1204 case S_16BYTE_LITERALS:
1205 atomSize = 16;
1206 break;
1207 case S_REGULAR:
1208 // special case ObjC classes to synthesize .objc_class_name_* symbols
1209 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
1210 // gcc sometimes over aligns class structure
1211 uint32_t align = 1 << sect->align();
1212 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
1213 }
1214 break;
1215 }
1216 if ( atomSize != 0 ) {
1217 for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
1218 uint32_t atomAddr = sect->addr() + sectOffset;
1219 // add if not already an atom at that address
1220 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
1221 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
1222 if ( !suppress )
1223 fAtoms.push_back(newAtom);
1224 fAddrToAtom[atomAddr] = newAtom->redirectTo();
1225 }
1226 }
1227 }
1228 }
1229
1230 // add all c-string anonymous atoms
1231 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1232 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
1233 uint32_t stringLen;
1234 uint32_t stringAddr;
1235 BaseAtom* firstEmptyString = NULL;
1236 for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
1237 stringAddr = sect->addr() + sectOffset;
1238 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
1239 // add if not already an atom at that address
1240 if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) {
1241 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
1242 if ( stringLen == 1 ) {
1243 // because of padding it may look like there are lots of empty strings
1244 // map them all to the first empty string
1245 if ( firstEmptyString == NULL ) {
1246 firstEmptyString = newAtom;
1247 fAtoms.push_back(firstEmptyString);
1248 }
1249 fAddrToAtom[stringAddr] = firstEmptyString;
1250 }
1251 else {
1252 fAtoms.push_back(newAtom);
1253 fAddrToAtom[stringAddr] = newAtom;
1254 }
1255 }
1256 }
1257 }
1258 }
1259
1260 // create atoms to cover any non-debug ranges not handled above
1261 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1262 pint_t sectionStartAddr = sect->addr();
1263 pint_t sectionEndAddr = sect->addr() + sect->size();
1264 const bool setFollowOnAtom = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
1265 if ( sect->size() != 0 ) {
1266 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1267 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
1268 fDebugInfo = kDebugInfoDwarf;
1269 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
1270 fDwarfDebugInfoSect = sect;
1271 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
1272 fDwarfDebugAbbrevSect = sect;
1273 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
1274 fDwarfDebugLineSect = sect;
1275 }
1276 else {
1277 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
1278 throw "object file contains old DWARF debug info - rebuild with newer compiler";
1279 }
1280 uint8_t type (sect->flags() & SECTION_TYPE);
1281 switch ( type ) {
1282 case S_REGULAR:
1283 case S_ZEROFILL:
1284 case S_COALESCED:
1285 // HACK until compiler stops generated anonymous non-lazy pointers rdar://problem/4513414
1286 handleAnonymousNonLazyPointers(sect);
1287 // if there is not an atom already at the start of this section, add an anonymous one
1288 uint32_t previousAtomAddr = 0;
1289 BaseAtom* previousAtom = NULL;
1290 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
1291 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
1292 fAtoms.push_back(newAtom);
1293 fAddrToAtom[sect->addr()] = newAtom;
1294 previousAtomAddr = sectionStartAddr;
1295 previousAtom = newAtom;
1296 }
1297 // calculate size of all atoms in this section and add follow-on references
1298 for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1299 // note: this algorithm depends on the map iterator returning entries in address order
1300 if ( (it->first >= sectionStartAddr) && (it->first < sectionEndAddr) ) {
1301 //fprintf(stderr, " atom %s in section\n", it->second->getDisplayName());
1302 if ( previousAtom != NULL ) {
1303 previousAtom->setSize(it->first - previousAtomAddr);
1304 // FIX FIX: this setting of followOn atoms does not work when there are multiple
1305 // labels for the same atom
1306 if ( setFollowOnAtom && (it->second != previousAtom) )
1307 makeReference(A::kFollowOn, previousAtomAddr, it->first);
1308 }
1309 previousAtomAddr = it->first;
1310 previousAtom = it->second;
1311 }
1312 }
1313 if ( previousAtom != NULL ) {
1314 // set last atom in section
1315 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
1316 }
1317 break;
1318 }
1319 }
1320 }
1321 }
1322
1323 // add relocation based references
1324 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1325 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1326 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
1327 switch ( sect->flags() & SECTION_TYPE ) {
1328 case S_SYMBOL_STUBS:
1329 case S_LAZY_SYMBOL_POINTERS:
1330 // we ignore compiler generated stubs, so ignore those relocs too
1331 break;
1332 default:
1333 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
1334 const uint32_t relocCount = sect->nreloc();
1335 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
1336 for (uint32_t r = 0; r < relocCount; ++r) {
1337 try {
1338 if ( addRelocReference(sect, &relocs[r]) )
1339 ++r; // skip next
1340 }
1341 catch (const char* msg) {
1342 throwf("in section %s,%s reloc %u: %s\n", sect->segname(), sect->sectname(), r, msg);
1343 }
1344 }
1345 }
1346 }
1347 }
1348
1349 // check of object file that defines no classes, but uses classes
1350 if ( !fAppleObjc ) {
1351 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
1352 const macho_nlist<P>& sym = fSymbols[i];
1353 if ( (sym.n_type() & N_STAB) == 0 ) {
1354 if ( ((sym.n_type() & N_TYPE) == N_UNDF) && (strncmp(&fStrings[sym.n_strx()], ".objc_class_name_", 16) == 0) ) {
1355 fAppleObjc = true;
1356 break;
1357 }
1358 }
1359 }
1360 }
1361
1362 // add objective-c references
1363 if ( fAppleObjc ) {
1364 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1365 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1366 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
1367 // gcc sometimes over aligns class structure
1368 uint32_t align = 1 << sect->align();
1369 uint32_t classSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
1370 for (uint32_t offset = 0; offset < sect->size(); offset += classSize) {
1371 // add by-name reference to super class
1372 uint32_t superClassNameAddr = P::getP(*(pint_t*)(((uint8_t*)fHeader) + sect->offset() + offset + sizeof(pint_t)));
1373 const char* superStr = (char*)(fHeader) + sect->offset() + superClassNameAddr - sect->addr();
1374 const char* superClassName;
1375 asprintf((char**)&superClassName, ".objc_class_name_%s", superStr);
1376 makeByNameReference(A::kNoFixUp, sect->addr()+offset+sizeof(pint_t), superClassName, 0);
1377 }
1378 }
1379 else if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
1380 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
1381 // scan through __cls_refs and add by-name reference for each required class
1382 uint32_t classNameAddr = P::getP(*(pint_t*)(((uint8_t*)fHeader) + sect->offset() + offset));
1383 const char* classStr = (char*)(fHeader) + sect->offset() + classNameAddr - sect->addr();
1384 const char* className;
1385 asprintf((char**)&className, ".objc_class_name_%s", classStr);
1386 makeByNameReference(A::kNoFixUp, sect->addr()+offset, className, 0);
1387 }
1388 }
1389 }
1390 }
1391
1392 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
1393 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
1394 AnonymousAtom<A>* localNonLazy = *it;
1395 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
1396 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
1397 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
1398 }
1399
1400 // add implicit direct reference from each C++ function to its eh info
1401 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1402 if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
1403 for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1404 // note: this algorithm depens on the map iterator returning entries in address order
1405 if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) {
1406 uint32_t ehAtomAddress = it->first;
1407 BaseAtom* ehAtom = it->second;
1408 const char* ehName = ehAtom->getName();
1409 if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) )
1410 makeReferenceToEH(ehName, ehAtomAddress, sect);
1411 }
1412 }
1413 }
1414 }
1415
1416
1417 //for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1418 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
1419 //}
1420
1421 // add translation unit info from dwarf
1422 uint64_t stmtList;
1423 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1424 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
1425 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
1426 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
1427 // if can't parse dwarf, warn and give up
1428 fDwarfTranslationUnitFile = NULL;
1429 fDwarfTranslationUnitDir = NULL;
1430 fprintf(stderr, "ld64: warning can't parse dwarf compilation unit info in %s\n", this->getPath());
1431 fDebugInfo = kDebugInfoNone;
1432 }
1433 }
1434 }
1435
1436 // add line number info to atoms from dwarf
1437 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1438 // file with just data will have no __debug_line info
1439 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0) ) {
1440 // validate stmt_list
1441 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
1442 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
1443 if ( debug_line != NULL ) {
1444 struct line_reader_data* lines = line_open(&debug_line[stmtList],
1445 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
1446 struct line_info result;
1447 ObjectFile::Atom* curAtom = NULL;
1448 uint32_t curAtomOffset = 0;
1449 uint32_t curAtomAddress = 0;
1450 uint32_t curAtomSize = 0;
1451 while ( line_next (lines, &result, line_stop_pc) ) {
1452 // for performance, see if in next pc is in current atom
1453 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
1454 curAtomOffset = result.pc - curAtomAddress;
1455 }
1456 // or pc at end of current atom
1457 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
1458 curAtomOffset = result.pc - curAtomAddress;
1459 }
1460 else {
1461 // do slow look up of atom by address
1462 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
1463 curAtom = ao.atom;
1464 if ( curAtom == NULL )
1465 break; // file has line info but no functions
1466 curAtomOffset = ao.offset;
1467 curAtomAddress = result.pc - ao.offset;
1468 curAtomSize = curAtom->getSize();
1469 }
1470 const char* filename;
1471 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
1472 if ( pos == fDwarfIndexToFile.end() ) {
1473 filename = line_file(lines, result.file);
1474 fDwarfIndexToFile[result.file] = filename;
1475 }
1476 else {
1477 filename = pos->second;
1478 }
1479 ObjectFile::LineInfo info;
1480 info.atomOffset = curAtomOffset;
1481 info.fileName = filename;
1482 info.lineNumber = result.line;
1483 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
1484 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
1485 ((BaseAtom*)curAtom)->addLineInfo(info);
1486 if ( result.end_of_sequence ) {
1487 curAtom = NULL;
1488 }
1489 }
1490 line_free(lines);
1491 }
1492 else {
1493 fprintf(stderr, "ld64: warning could not parse dwarf line number info in %s\n", this->getPath());
1494 }
1495 }
1496 }
1497 }
1498
1499 // if no dwarf, try processing stabs debugging info
1500 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1501 // scan symbol table for stabs entries
1502 fStabs.reserve(fSymbolCount); // reduce re-allocations
1503 BaseAtom* currentAtom = NULL;
1504 pint_t currentAtomAddress = 0;
1505 enum { start, inBeginEnd, inFun } state = start;
1506 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
1507 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
1508 bool useStab = true;
1509 uint8_t type = sym->n_type();
1510 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
1511 if ( (type & N_STAB) != 0 ) {
1512 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
1513 Stab stab;
1514 stab.atom = NULL;
1515 stab.type = type;
1516 stab.other = sym->n_sect();
1517 stab.desc = sym->n_desc();
1518 stab.value = sym->n_value();
1519 stab.string = NULL;
1520 switch (state) {
1521 case start:
1522 switch (type) {
1523 case N_BNSYM:
1524 // beginning of function block
1525 state = inBeginEnd;
1526 // fall into case to lookup atom by addresss
1527 case N_LCSYM:
1528 case N_STSYM:
1529 currentAtomAddress = sym->n_value();
1530 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
1531 if ( currentAtom != NULL ) {
1532 stab.atom = currentAtom;
1533 stab.string = symString;
1534 }
1535 else {
1536 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s\n",
1537 (uint64_t)sym->n_value(), path);
1538 }
1539 break;
1540 case N_SO:
1541 case N_OSO:
1542 case N_OPT:
1543 case N_LSYM:
1544 // not associated with an atom, just copy
1545 stab.string = symString;
1546 break;
1547 case N_GSYM:
1548 // n_value field is NOT atom address ;-(
1549 // need to find atom by name match
1550 const char* colon = strchr(symString, ':');
1551 if ( colon != NULL ) {
1552 // build underscore leading name
1553 int nameLen = colon - symString;
1554 char symName[nameLen+2];
1555 strlcpy(&symName[1], symString, nameLen+1);
1556 symName[0] = '_';
1557 symName[nameLen+1] = '\0';
1558 currentAtom = findAtomByName(symName);
1559 if ( currentAtom != NULL ) {
1560 stab.atom = currentAtom;
1561 stab.string = symString;
1562 }
1563 }
1564 if ( stab.atom == NULL ) {
1565 fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
1566 useStab = false;
1567 }
1568 break;
1569 case N_FUN:
1570 // old style stabs without BNSYM
1571 state = inFun;
1572 currentAtomAddress = sym->n_value();
1573 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
1574 if ( currentAtom != NULL ) {
1575 stab.atom = currentAtom;
1576 stab.string = symString;
1577 }
1578 else {
1579 fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
1580 (uint64_t)currentAtomAddress, path);
1581 }
1582 break;
1583 case N_SOL:
1584 case N_SLINE:
1585 stab.string = symString;
1586 // old stabs
1587 break;
1588 case N_BINCL:
1589 case N_EINCL:
1590 case N_EXCL:
1591 stab.string = symString;
1592 // -gfull built .o file
1593 break;
1594 default:
1595 fprintf(stderr, "unknown stabs type 0x%X in %s\n", type, path);
1596 }
1597 break;
1598 case inBeginEnd:
1599 stab.atom = currentAtom;
1600 switch (type) {
1601 case N_ENSYM:
1602 state = start;
1603 currentAtom = NULL;
1604 break;
1605 case N_LCSYM:
1606 case N_STSYM:
1607 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
1608 if ( nestedAtom != NULL ) {
1609 stab.atom = nestedAtom;
1610 stab.string = symString;
1611 }
1612 else {
1613 fprintf(stderr, "can't find atom for stabs 0x%X at %08llX in %s\n",
1614 type, (uint64_t)sym->n_value(), path);
1615 }
1616 break;
1617 case N_LBRAC:
1618 case N_RBRAC:
1619 case N_SLINE:
1620 // adjust value to be offset in atom
1621 stab.value -= currentAtomAddress;
1622 default:
1623 stab.string = symString;
1624 break;
1625 }
1626 break;
1627 case inFun:
1628 switch (type) {
1629 case N_FUN:
1630 if ( sym->n_sect() != 0 ) {
1631 // found another start stab, must be really old stabs...
1632 currentAtomAddress = sym->n_value();
1633 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
1634 if ( currentAtom != NULL ) {
1635 stab.atom = currentAtom;
1636 stab.string = symString;
1637 }
1638 else {
1639 fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
1640 (uint64_t)currentAtomAddress, path);
1641 }
1642 }
1643 else {
1644 // found ending stab, switch back to start state
1645 stab.string = symString;
1646 stab.atom = currentAtom;
1647 state = start;
1648 currentAtom = NULL;
1649 }
1650 break;
1651 case N_LBRAC:
1652 case N_RBRAC:
1653 case N_SLINE:
1654 // adjust value to be offset in atom
1655 stab.value -= currentAtomAddress;
1656 stab.atom = currentAtom;
1657 break;
1658 case N_SO:
1659 stab.string = symString;
1660 state = start;
1661 break;
1662 default:
1663 stab.atom = currentAtom;
1664 stab.string = symString;
1665 break;
1666 }
1667 break;
1668 }
1669 // add to list of stabs for this .o file
1670 if ( useStab )
1671 fStabs.push_back(stab);
1672 }
1673 }
1674 }
1675
1676
1677 #if 0
1678 // special case precompiled header .o file (which has no content) to have one empty atom
1679 if ( fAtoms.size() == 0 ) {
1680 int pathLen = strlen(path);
1681 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
1682 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
1683 //phony->fSynthesizedName = ".gch.o";
1684 fAtoms.push_back(phony);
1685 }
1686 }
1687 #endif
1688 }
1689
1690 template <>
1691 void Reader<x86_64>::validSectionType(uint8_t type)
1692 {
1693 switch ( type ) {
1694 case S_SYMBOL_STUBS:
1695 throw "symbol_stub sections not valid in x86_64 object files";
1696 case S_LAZY_SYMBOL_POINTERS:
1697 throw "lazy pointer sections not valid in x86_64 object files";
1698 case S_NON_LAZY_SYMBOL_POINTERS:
1699 throw "non lazy pointer sections not valid in x86_64 object files";
1700 }
1701 }
1702
1703 template <typename A>
1704 void Reader<A>::validSectionType(uint8_t type)
1705 {
1706 }
1707
1708 template <typename A>
1709 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
1710 {
1711 if ( fDebugInfo == kDebugInfoDwarf ) {
1712 *dir = fDwarfTranslationUnitDir;
1713 *name = fDwarfTranslationUnitFile;
1714 return true;
1715 }
1716 return false;
1717 }
1718
1719 template <typename A>
1720 BaseAtom* Reader<A>::findAtomByName(const char* name)
1721 {
1722 // first search the more important atoms
1723 for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1724 const char* atomName = it->second->getName();
1725 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
1726 return it->second;
1727 }
1728 }
1729 // try all atoms, because this might have been a tentative definition
1730 for (std::vector<ObjectFile::Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
1731 BaseAtom* atom = (BaseAtom*)(*it);
1732 const char* atomName = atom->getName();
1733 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
1734 return atom;
1735 }
1736 }
1737 return NULL;
1738 }
1739
1740 template <typename A>
1741 Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr)
1742 {
1743 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
1744 }
1745
1746 template <typename A>
1747 Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr)
1748 {
1749 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
1750 }
1751
1752 template <typename A>
1753 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr)
1754 {
1755 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
1756 }
1757
1758 template <typename A>
1759 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr)
1760 {
1761 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
1762 }
1763
1764 template <typename A>
1765 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset)
1766 {
1767 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
1768 }
1769
1770 template <typename A>
1771 Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
1772 {
1773 // add a direct reference from function atom to its eh frame atom
1774 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
1775 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
1776 uint32_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
1777 return makeReference(A::kNoFixUp, funcAddr, ehAtomAddress);
1778 }
1779
1780
1781 template <>
1782 Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset)
1783 {
1784 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
1785 // instead check scope of target
1786 BaseAtom* target = findAtomByName(toName);
1787 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
1788 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
1789 else
1790 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
1791 }
1792
1793 template <>
1794 Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, uint32_t atAddr, const macho_nlist<P>* toSymbol, uint32_t toOffset)
1795 {
1796 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
1797 // instead check scope of target
1798 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && ((toSymbol->n_type() & N_EXT) == 0) )
1799 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset));
1800 else
1801 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), &fStrings[toSymbol->n_strx()], toOffset);
1802 }
1803
1804
1805 template <>
1806 Reference<x86_64>* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
1807 {
1808 // add a direct reference from function atom to its eh frame atom
1809 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
1810 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
1811 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
1812 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
1813 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
1814 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
1815 uint32_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
1816 return makeReference(x86_64::kNoFixUp, funcAddr, ehAtomAddress);
1817 }
1818 }
1819 fprintf(stderr, "ld64: warning, can't find matching function for eh symbol %s\n", ehName);
1820 return NULL;
1821 }
1822
1823
1824 template <typename A>
1825 AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t addr)
1826 {
1827 // STL has no built-in for "find largest key that is same or less than"
1828 std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.upper_bound(addr);
1829 --it; // upper_bound gets us next key, so we back up one
1830 AtomAndOffset result;
1831 result.atom = it->second;
1832 result.offset = addr - it->first;
1833 //fprintf(stderr, "findAtomAndOffset(0x%0X) ==> %s (0x%0X -> 0x%0llX)\n",
1834 // addr, result.atom->getDisplayName(), it->first, it->first+result.atom->getSize());
1835 return result;
1836 }
1837
1838 // "scattered" relocations enable you to offset into an atom past the end of it
1839 // baseAddr is the address of the target atom,
1840 // realAddr is the points into it
1841 template <typename A>
1842 AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr)
1843 {
1844 std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.find(baseAddr);
1845 if ( it != fAddrToAtom.end() ) {
1846 AtomAndOffset result;
1847 result.atom = it->second;
1848 result.offset = realAddr - it->first;
1849 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
1850 return result;
1851 }
1852 // getting here means we have a scattered relocation to an address without a label
1853 // we should never get here...
1854 // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
1855 return findAtomAndOffset(realAddr);
1856 }
1857
1858
1859 /* Skip over a LEB128 value (signed or unsigned). */
1860 static void
1861 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
1862 {
1863 while (*offset != end && **offset >= 0x80)
1864 (*offset)++;
1865 if (*offset != end)
1866 (*offset)++;
1867 }
1868
1869 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
1870 or error. On overflow, skip past the rest of the uleb128. */
1871 static uint64_t
1872 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
1873 {
1874 uint64_t result = 0;
1875 int bit = 0;
1876
1877 do {
1878 uint64_t b;
1879
1880 if (*offset == end)
1881 return (uint64_t) -1;
1882
1883 b = **offset & 0x7f;
1884
1885 if (bit >= 64 || b << bit >> bit != b)
1886 result = (uint64_t) -1;
1887 else
1888 result |= b << bit, bit += 7;
1889 } while (*(*offset)++ >= 0x80);
1890 return result;
1891 }
1892
1893
1894 /* Skip over a DWARF attribute of form FORM. */
1895 template <typename A>
1896 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
1897 uint8_t addr_size, bool dwarf64)
1898 {
1899 int64_t sz=0;
1900
1901 switch (form)
1902 {
1903 case DW_FORM_addr:
1904 sz = addr_size;
1905 break;
1906
1907 case DW_FORM_block2:
1908 if (end - *offset < 2)
1909 return false;
1910 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
1911 break;
1912
1913 case DW_FORM_block4:
1914 if (end - *offset < 4)
1915 return false;
1916 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
1917 break;
1918
1919 case DW_FORM_data2:
1920 case DW_FORM_ref2:
1921 sz = 2;
1922 break;
1923
1924 case DW_FORM_data4:
1925 case DW_FORM_ref4:
1926 sz = 4;
1927 break;
1928
1929 case DW_FORM_data8:
1930 case DW_FORM_ref8:
1931 sz = 8;
1932 break;
1933
1934 case DW_FORM_string:
1935 while (*offset != end && **offset)
1936 ++*offset;
1937 case DW_FORM_data1:
1938 case DW_FORM_flag:
1939 case DW_FORM_ref1:
1940 sz = 1;
1941 break;
1942
1943 case DW_FORM_block:
1944 sz = read_uleb128 (offset, end);
1945 break;
1946
1947 case DW_FORM_block1:
1948 if (*offset == end)
1949 return false;
1950 sz = 1 + **offset;
1951 break;
1952
1953 case DW_FORM_sdata:
1954 case DW_FORM_udata:
1955 case DW_FORM_ref_udata:
1956 skip_leb128 (offset, end);
1957 return true;
1958
1959 case DW_FORM_strp:
1960 case DW_FORM_ref_addr:
1961 sz = dwarf64 ? 8 : 4;
1962 break;
1963
1964 default:
1965 return false;
1966 }
1967 if (end - *offset < sz)
1968 return false;
1969 *offset += sz;
1970 return true;
1971 }
1972
1973 // Look at the compilation unit DIE and determine
1974 // its NAME, compilation directory (in COMP_DIR) and its
1975 // line number information offset (in STMT_LIST). NAME and COMP_DIR
1976 // may be NULL (especially COMP_DIR) if they are not in the .o file;
1977 // STMT_LIST will be (uint64_t) -1.
1978 //
1979 // At present this assumes that there's only one compilation unit DIE.
1980 //
1981 template <typename A>
1982 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
1983 uint64_t *stmt_list)
1984 {
1985 const uint8_t * debug_info;
1986 const uint8_t * debug_abbrev;
1987 const uint8_t * di;
1988 const uint8_t * da;
1989 const uint8_t * end;
1990 const uint8_t * enda;
1991 uint64_t sz;
1992 uint16_t vers;
1993 uint64_t abbrev_base;
1994 uint64_t abbrev;
1995 uint8_t address_size;
1996 bool dwarf64;
1997
1998 *name = NULL;
1999 *comp_dir = NULL;
2000 *stmt_list = (uint64_t) -1;
2001
2002 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
2003 return false;
2004
2005 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
2006 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
2007 di = debug_info;
2008
2009 if (fDwarfDebugInfoSect->size() < 12)
2010 /* Too small to be a real debug_info section. */
2011 return false;
2012 sz = A::P::E::get32(*(uint32_t*)di);
2013 di += 4;
2014 dwarf64 = sz == 0xffffffff;
2015 if (dwarf64)
2016 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
2017 else if (sz > 0xffffff00)
2018 /* Unknown dwarf format. */
2019 return false;
2020
2021 /* Verify claimed size. */
2022 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
2023 return false;
2024
2025 vers = A::P::E::get16(*(uint16_t*)di);
2026 if (vers < 2 || vers > 3)
2027 /* DWARF version wrong for this code.
2028 Chances are we could continue anyway, but we don't know for sure. */
2029 return false;
2030 di += 2;
2031
2032 /* Find the debug_abbrev section. */
2033 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
2034 di += dwarf64 ? 8 : 4;
2035
2036 if (abbrev_base > fDwarfDebugAbbrevSect->size())
2037 return false;
2038 da = debug_abbrev + abbrev_base;
2039 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
2040
2041 address_size = *di++;
2042
2043 /* Find the abbrev number we're looking for. */
2044 end = di + sz;
2045 abbrev = read_uleb128 (&di, end);
2046 if (abbrev == (uint64_t) -1)
2047 return false;
2048
2049 /* Skip through the debug_abbrev section looking for that abbrev. */
2050 for (;;)
2051 {
2052 uint64_t this_abbrev = read_uleb128 (&da, enda);
2053 uint64_t attr;
2054
2055 if (this_abbrev == abbrev)
2056 /* This is almost always taken. */
2057 break;
2058 skip_leb128 (&da, enda); /* Skip the tag. */
2059 if (da == enda)
2060 return false;
2061 da++; /* Skip the DW_CHILDREN_* value. */
2062
2063 do {
2064 attr = read_uleb128 (&da, enda);
2065 skip_leb128 (&da, enda);
2066 } while (attr != 0 && attr != (uint64_t) -1);
2067 if (attr != 0)
2068 return false;
2069 }
2070
2071 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
2072 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
2073 return false;
2074 if (da == enda)
2075 return false;
2076 da++; /* Skip the DW_CHILDREN_* value. */
2077
2078 /* Now, go through the DIE looking for DW_AT_name,
2079 DW_AT_comp_dir, and DW_AT_stmt_list. */
2080 for (;;)
2081 {
2082 uint64_t attr = read_uleb128 (&da, enda);
2083 uint64_t form = read_uleb128 (&da, enda);
2084
2085 if (attr == (uint64_t) -1)
2086 return false;
2087 else if (attr == 0)
2088 return true;
2089
2090 if (form == DW_FORM_indirect)
2091 form = read_uleb128 (&di, end);
2092
2093 if (attr == DW_AT_name && form == DW_FORM_string)
2094 *name = (const char *) di;
2095 else if (attr == DW_AT_comp_dir && form == DW_FORM_string)
2096 *comp_dir = (const char *) di;
2097 /* Really we should support DW_FORM_strp here, too, but
2098 there's usually no reason for the producer to use that form
2099 for the DW_AT_name and DW_AT_comp_dir attributes. */
2100 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
2101 *stmt_list = A::P::E::get32(*(uint32_t*)di);
2102 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
2103 *stmt_list = A::P::E::get64(*(uint64_t*)di);
2104 if (! skip_form (&di, end, form, address_size, dwarf64))
2105 return false;
2106 }
2107 }
2108
2109 template <typename A>
2110 const char* Reader<A>::assureFullPath(const char* path)
2111 {
2112 if ( path[0] == '/' )
2113 return path;
2114 char cwdbuff[MAXPATHLEN];
2115 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
2116 char* result;
2117 asprintf(&result, "%s/%s", cwdbuff, path);
2118 if ( result != NULL )
2119 return result;
2120 }
2121 return path;
2122 }
2123
2124
2125 //
2126 //
2127 // To implement architecture xxx, you must write template specializations for the following six methods:
2128 // Reader<xxx>::validFile()
2129 // Reader<xxx>::addRelocReference()
2130 // Reference<xxx>::getDescription()
2131 //
2132 //
2133
2134
2135 template <>
2136 bool Reader<ppc>::validFile(const uint8_t* fileContent)
2137 {
2138 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2139 if ( header->magic() != MH_MAGIC )
2140 return false;
2141 if ( header->cputype() != CPU_TYPE_POWERPC )
2142 return false;
2143 if ( header->filetype() != MH_OBJECT )
2144 return false;
2145 return true;
2146 }
2147
2148 template <>
2149 bool Reader<ppc64>::validFile(const uint8_t* fileContent)
2150 {
2151 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2152 if ( header->magic() != MH_MAGIC_64 )
2153 return false;
2154 if ( header->cputype() != CPU_TYPE_POWERPC64 )
2155 return false;
2156 if ( header->filetype() != MH_OBJECT )
2157 return false;
2158 return true;
2159 }
2160
2161 template <>
2162 bool Reader<x86>::validFile(const uint8_t* fileContent)
2163 {
2164 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2165 if ( header->magic() != MH_MAGIC )
2166 return false;
2167 if ( header->cputype() != CPU_TYPE_I386 )
2168 return false;
2169 if ( header->filetype() != MH_OBJECT )
2170 return false;
2171 return true;
2172 }
2173
2174 template <>
2175 bool Reader<x86_64>::validFile(const uint8_t* fileContent)
2176 {
2177 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2178 if ( header->magic() != MH_MAGIC_64 )
2179 return false;
2180 if ( header->cputype() != CPU_TYPE_X86_64 )
2181 return false;
2182 if ( header->filetype() != MH_OBJECT )
2183 return false;
2184 return true;
2185 }
2186
2187
2188 template <typename A>
2189 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
2190 {
2191 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
2192 }
2193
2194 template <>
2195 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
2196 {
2197 return addRelocReference_powerpc(sect, reloc);
2198 }
2199
2200 template <>
2201 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
2202 {
2203 return addRelocReference_powerpc(sect, reloc);
2204 }
2205
2206
2207 //
2208 // ppc and ppc64 both use the same relocations, so process them in one common routine
2209 //
2210 template <typename A>
2211 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
2212 const macho_relocation_info<typename A::P>* reloc)
2213 {
2214 uint32_t srcAddr;
2215 uint32_t dstAddr;
2216 uint32_t* fixUpPtr;
2217 int32_t displacement = 0;
2218 uint32_t instruction = 0;
2219 uint32_t offsetInTarget;
2220 int16_t lowBits;
2221 bool result = false;
2222 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2223 const macho_relocation_info<P>* nextReloc = &reloc[1];
2224 const char* targetName = NULL;
2225 bool weakImport = false;
2226 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2227 if ( reloc->r_type() != PPC_RELOC_PAIR )
2228 instruction = BigEndian::get32(*fixUpPtr);
2229 srcAddr = sect->addr() + reloc->r_address();
2230 if ( reloc->r_extern() ) {
2231 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2232 targetName = &fStrings[targetSymbol->n_strx()];
2233 weakImport = this->isWeakImportSymbol(targetSymbol);
2234 }
2235 switch ( reloc->r_type() ) {
2236 case PPC_RELOC_BR24:
2237 {
2238 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2239 displacement = (instruction & 0x03FFFFFC);
2240 if ( (displacement & 0x02000000) != 0 )
2241 displacement |= 0xFC000000;
2242 }
2243 else {
2244 printf("bad instruction for BR24 reloc");
2245 }
2246 if ( reloc->r_extern() ) {
2247 offsetInTarget = srcAddr + displacement;
2248 if ( weakImport )
2249 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
2250 else
2251 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
2252 }
2253 else {
2254 dstAddr = srcAddr + displacement;
2255 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2256 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
2257 if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
2258 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
2259 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
2260 else
2261 makeReference(A::kBranch24, srcAddr, dstAddr);
2262 }
2263 }
2264 break;
2265 case PPC_RELOC_BR14:
2266 {
2267 displacement = (instruction & 0x0000FFFC);
2268 if ( (displacement & 0x00008000) != 0 )
2269 displacement |= 0xFFFF0000;
2270 if ( reloc->r_extern() ) {
2271 offsetInTarget = srcAddr + displacement;
2272 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
2273 }
2274 else {
2275 dstAddr = srcAddr + displacement;
2276 makeReference(A::kBranch14, srcAddr, dstAddr);
2277 }
2278 }
2279 break;
2280 case PPC_RELOC_PAIR:
2281 // skip, processed by a previous look ahead
2282 break;
2283 case PPC_RELOC_LO16:
2284 {
2285 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2286 printf("PPC_RELOC_LO16 missing following pair\n");
2287 break;
2288 }
2289 result = true;
2290 lowBits = (instruction & 0xFFFF);
2291 if ( reloc->r_extern() ) {
2292 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2293 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
2294 }
2295 else {
2296 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
2297 makeReference(A::kAbsLow16, srcAddr, dstAddr);
2298 }
2299 }
2300 break;
2301 case PPC_RELOC_LO14:
2302 {
2303 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2304 printf("PPC_RELOC_LO14 missing following pair\n");
2305 break;
2306 }
2307 result = true;
2308 lowBits = (instruction & 0xFFFC);
2309 if ( reloc->r_extern() ) {
2310 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2311 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
2312 }
2313 else {
2314 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2315 Reference<A>* ref = makeReference(A::kAbsLow14, srcAddr, dstAddr);
2316 BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
2317 if ( target != NULL )
2318 target->alignAtLeast(3);
2319 }
2320 }
2321 break;
2322 case PPC_RELOC_HI16:
2323 {
2324 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2325 printf("PPC_RELOC_HI16 missing following pair\n");
2326 break;
2327 }
2328 result = true;
2329 if ( reloc->r_extern() ) {
2330 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
2331 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
2332 }
2333 else {
2334 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
2335 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
2336 }
2337 }
2338 break;
2339 case PPC_RELOC_HA16:
2340 {
2341 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2342 printf("PPC_RELOC_HA16 missing following pair\n");
2343 break;
2344 }
2345 result = true;
2346 lowBits = (nextReloc->r_address() & 0x0000FFFF);
2347 if ( reloc->r_extern() ) {
2348 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
2349 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
2350 }
2351 else {
2352 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
2353 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
2354 }
2355 }
2356 break;
2357 case PPC_RELOC_VANILLA:
2358 {
2359 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
2360 if ( reloc->r_extern() ) {
2361 if ( weakImport )
2362 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
2363 else
2364 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
2365 }
2366 else {
2367 makeReference(A::kPointer, srcAddr, pointerValue);
2368 }
2369 }
2370 break;
2371 case PPC_RELOC_JBSR:
2372 // this is from -mlong-branch codegen. We ignore the jump island
2373 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2374 printf("PPC_RELOC_JBSR missing following pair\n");
2375 break;
2376 }
2377 result = true;
2378 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
2379 break;
2380 default:
2381 printf("unknown relocation type %d\n", reloc->r_type());
2382 }
2383 }
2384 else {
2385 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2386 srcAddr = sect->addr() + sreloc->r_address();
2387 dstAddr = sreloc->r_value();
2388 uint32_t betterDstAddr;
2389 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
2390 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
2391 const macho_relocation_info<P>* nextReloc = &reloc[1];
2392 // file format allows pair to be scattered or not
2393 bool nextRelocIsPair = false;
2394 uint32_t nextRelocAddress = 0;
2395 uint32_t nextRelocValue = 0;
2396 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
2397 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
2398 nextRelocIsPair = true;
2399 nextRelocAddress = nextReloc->r_address();
2400 result = true;
2401 }
2402 }
2403 else {
2404 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
2405 nextRelocIsPair = true;
2406 nextRelocAddress = nextSReloc->r_address();
2407 nextRelocValue = nextSReloc->r_value();
2408 result = true;
2409 }
2410 }
2411 switch (sreloc->r_type()) {
2412 case PPC_RELOC_VANILLA:
2413 {
2414 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
2415 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
2416 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
2417 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
2418 }
2419 break;
2420 case PPC_RELOC_BR14:
2421 {
2422 instruction = BigEndian::get32(*fixUpPtr);
2423 displacement = (instruction & 0x0000FFFC);
2424 if ( (displacement & 0x00008000) != 0 )
2425 displacement |= 0xFFFF0000;
2426 betterDstAddr = srcAddr+displacement;
2427 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
2428 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
2429 }
2430 break;
2431 case PPC_RELOC_BR24:
2432 {
2433 instruction = BigEndian::get32(*fixUpPtr);
2434 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2435 displacement = (instruction & 0x03FFFFFC);
2436 if ( (displacement & 0x02000000) != 0 )
2437 displacement |= 0xFC000000;
2438 betterDstAddr = srcAddr+displacement;
2439 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
2440 }
2441 }
2442 break;
2443 case PPC_RELOC_LO16_SECTDIFF:
2444 {
2445 if ( ! nextRelocIsPair ) {
2446 printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
2447 break;
2448 }
2449 instruction = BigEndian::get32(*fixUpPtr);
2450 lowBits = (instruction & 0xFFFF);
2451 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2452 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
2453 }
2454 break;
2455 case PPC_RELOC_LO14_SECTDIFF:
2456 {
2457 if ( ! nextRelocIsPair ) {
2458 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
2459 break;
2460 }
2461 instruction = BigEndian::get32(*fixUpPtr);
2462 lowBits = (instruction & 0xFFFC);
2463 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2464 Reference<A>* ref = makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
2465 BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
2466 if ( target != NULL ) // can be NULL if target is turned into by-name reference
2467 target->alignAtLeast(3);
2468 }
2469 break;
2470 case PPC_RELOC_HA16_SECTDIFF:
2471 {
2472 if ( ! nextRelocIsPair ) {
2473 printf("PPC_RELOC_HA16_SECTDIFF missing following PAIR\n");
2474 break;
2475 }
2476 instruction = BigEndian::get32(*fixUpPtr);
2477 lowBits = (nextRelocAddress & 0x0000FFFF);
2478 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
2479 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
2480 }
2481 break;
2482 case PPC_RELOC_LO14:
2483 {
2484 if ( ! nextRelocIsPair ) {
2485 printf("PPC_RELOC_LO14 missing following PAIR\n");
2486 break;
2487 }
2488 instruction = BigEndian::get32(*fixUpPtr);
2489 lowBits = (instruction & 0xFFFC);
2490 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
2491 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
2492 }
2493 break;
2494 case PPC_RELOC_LO16:
2495 {
2496 if ( ! nextRelocIsPair ) {
2497 printf("PPC_RELOC_LO16 missing following PAIR\n");
2498 break;
2499 }
2500 instruction = BigEndian::get32(*fixUpPtr);
2501 lowBits = (instruction & 0xFFFF);
2502 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
2503 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
2504 }
2505 break;
2506 case PPC_RELOC_HA16:
2507 {
2508 if ( ! nextRelocIsPair ) {
2509 printf("PPC_RELOC_HA16 missing following PAIR\n");
2510 break;
2511 }
2512 instruction = BigEndian::get32(*fixUpPtr);
2513 lowBits = (nextRelocAddress & 0xFFFF);
2514 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
2515 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
2516 }
2517 break;
2518 case PPC_RELOC_SECTDIFF:
2519 case PPC_RELOC_LOCAL_SECTDIFF:
2520 {
2521 if ( ! nextRelocIsPair ) {
2522 printf("PPC_RELOC_SECTDIFF missing following pair\n");
2523 break;
2524 }
2525 makeReference(pointerDiffKindForLength_powerpc(sreloc->r_length()), srcAddr, nextRelocValue, dstAddr);
2526 }
2527 break;
2528 case PPC_RELOC_PAIR:
2529 break;
2530 case PPC_RELOC_HI16_SECTDIFF:
2531 printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
2532 break;
2533 default:
2534 printf("unknown scattered relocation type %d\n", sreloc->r_type());
2535 }
2536 }
2537 return result;
2538 }
2539
2540 template <>
2541 ppc::ReferenceKinds Reader<ppc>::pointerDiffKindForLength_powerpc(uint8_t r_length)
2542 {
2543 if ( r_length == 2 )
2544 return ppc::kPointerDiff32;
2545 else
2546 throw "bad diff relocations r_length for ppc architecture";
2547 }
2548
2549 template <>
2550 ppc64::ReferenceKinds Reader<ppc64>::pointerDiffKindForLength_powerpc(uint8_t r_length)
2551 {
2552 if ( r_length == 2 )
2553 return ppc64::kPointerDiff32;
2554 else if ( r_length == 3 )
2555 return ppc64::kPointerDiff64;
2556 else
2557 throw "bad diff relocations r_length for ppc64 architecture";
2558 }
2559
2560 template <>
2561 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
2562 {
2563 uint32_t srcAddr;
2564 uint32_t dstAddr;
2565 uint32_t* fixUpPtr;
2566 bool result = false;
2567 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2568 srcAddr = sect->addr() + reloc->r_address();
2569 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2570 switch ( reloc->r_type() ) {
2571 case GENERIC_RELOC_VANILLA:
2572 {
2573 if ( reloc->r_length() != 2 )
2574 throw "bad vanilla relocation length";
2575 x86::ReferenceKinds kind;
2576 uint32_t pointerValue = E::get32(*fixUpPtr);
2577 if ( reloc->r_pcrel() ) {
2578 kind = x86::kPCRel32;
2579 pointerValue += srcAddr + sizeof(uint32_t);
2580 }
2581 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
2582 kind = x86::kAbsolute32;
2583 }
2584 else {
2585 kind = x86::kPointer;
2586 }
2587 if ( reloc->r_extern() ) {
2588 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2589 if ( this->isWeakImportSymbol(targetSymbol) )
2590 kind = x86::kPointerWeakImport;
2591 const char* targetName = &fStrings[targetSymbol->n_strx()];
2592 makeByNameReference(kind, srcAddr, targetName, pointerValue);
2593 }
2594 else {
2595 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2596 ObjectFile::Atom* atom = findAtomAndOffset(pointerValue).atom;
2597 if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
2598 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
2599 makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
2600 else
2601 makeReference(kind, srcAddr, pointerValue);
2602 }
2603 }
2604 break;
2605 default:
2606 printf("unknown relocation type %d\n", reloc->r_type());
2607 }
2608 }
2609 else {
2610 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2611 srcAddr = sect->addr() + sreloc->r_address();
2612 dstAddr = sreloc->r_value();
2613 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
2614 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
2615 const macho_relocation_info<P>* nextReloc = &reloc[1];
2616 pint_t betterDstAddr;
2617 // file format allows pair to be scattered or not
2618 bool nextRelocIsPair = false;
2619 uint32_t nextRelocAddress = 0;
2620 uint32_t nextRelocValue = 0;
2621 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
2622 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
2623 nextRelocIsPair = true;
2624 nextRelocAddress = nextReloc->r_address();
2625 result = true;
2626 }
2627 }
2628 else {
2629 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
2630 nextRelocIsPair = true;
2631 nextRelocAddress = nextSReloc->r_address();
2632 nextRelocValue = nextSReloc->r_value();
2633 }
2634 }
2635 switch (sreloc->r_type()) {
2636 case GENERIC_RELOC_VANILLA:
2637 betterDstAddr = LittleEndian::get32(*fixUpPtr);
2638 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
2639 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
2640 if ( sreloc->r_pcrel() ) {
2641 betterDstAddr += srcAddr + 4;
2642 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
2643 }
2644 else {
2645 if ( strcmp(sect->segname(), "__TEXT") == 0 )
2646 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
2647 else
2648 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
2649 }
2650 break;
2651 case GENERIC_RELOC_SECTDIFF:
2652 case GENERIC_RELOC_LOCAL_SECTDIFF:
2653 {
2654 if ( !nextRelocIsPair ) {
2655 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
2656 break;
2657 }
2658 if ( sreloc->r_length() != 2 )
2659 throw "bad length for GENERIC_RELOC_SECTDIFF";
2660 betterDstAddr = LittleEndian::get32(*fixUpPtr);
2661 makeReferenceWithToBase(x86::kPointerDiff, srcAddr, nextRelocValue, betterDstAddr+nextRelocValue, dstAddr);
2662 }
2663 break;
2664 case GENERIC_RELOC_PAIR:
2665 // do nothing, already used via a look ahead
2666 break;
2667 default:
2668 printf("unknown scattered relocation type %d\n", sreloc->r_type());
2669 }
2670 }
2671 return result;
2672 }
2673
2674 template <>
2675 bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
2676 {
2677 uint64_t srcAddr;
2678 uint64_t dstAddr = 0;
2679 uint64_t addend;
2680 uint32_t* fixUpPtr;
2681 x86_64::ReferenceKinds kind;
2682 bool result = false;
2683 const macho_nlist<P>* targetSymbol = NULL;
2684 const char* targetName = NULL;
2685 srcAddr = sect->addr() + reloc->r_address();
2686 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2687 //fprintf(stderr, "addReloc type=%d\n", reloc->r_type());
2688 if ( reloc->r_extern() ) {
2689 targetSymbol = &fSymbols[reloc->r_symbolnum()];
2690 targetName = &fStrings[targetSymbol->n_strx()];
2691 }
2692 switch ( reloc->r_type() ) {
2693 case X86_64_RELOC_UNSIGNED:
2694 if ( reloc->r_pcrel() )
2695 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
2696 if ( reloc->r_length() != 3 )
2697 throw "length < 3 and X86_64_RELOC_UNSIGNED not supported";
2698 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
2699 if ( reloc->r_extern() )
2700 makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr);
2701 else
2702 makeReference(x86_64::kPointer, srcAddr, dstAddr);
2703 break;
2704 case X86_64_RELOC_SIGNED:
2705 case X86_64_RELOC_SIGNED_1:
2706 case X86_64_RELOC_SIGNED_2:
2707 case X86_64_RELOC_SIGNED_4:
2708 if ( ! reloc->r_pcrel() )
2709 throw "not pcrel and X86_64_RELOC_SIGNED not supported";
2710 if ( reloc->r_length() != 2 )
2711 throw "length != 2 and X86_64_RELOC_SIGNED not supported";
2712 kind = x86_64::kPCRel32;
2713 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
2714 switch ( reloc->r_type() ) {
2715 case X86_64_RELOC_SIGNED:
2716 if ( reloc->r_extern() ) {
2717 // Support older relocations
2718 if ( dstAddr == (uint64_t)(-1) ) {
2719 kind = x86_64::kPCRel32_1;
2720 dstAddr = 0;
2721 }
2722 else if ( dstAddr == (uint64_t)(-2) ) {
2723 kind = x86_64::kPCRel32_2;
2724 dstAddr = 0;
2725 }
2726 else if ( dstAddr == (uint64_t)(-4) ) {
2727 kind = x86_64::kPCRel32_4;
2728 dstAddr = 0;
2729 }
2730 }
2731 break;
2732 case X86_64_RELOC_SIGNED_1:
2733 if ( reloc->r_extern() ) {
2734 dstAddr = 0;
2735 } else {
2736 dstAddr += 1;
2737 }
2738 kind = x86_64::kPCRel32_1;
2739 break;
2740 case X86_64_RELOC_SIGNED_2:
2741 if ( reloc->r_extern() ) {
2742 dstAddr = 0;
2743 } else {
2744 dstAddr += 2;
2745 }
2746 kind = x86_64::kPCRel32_2;
2747 break;
2748 case X86_64_RELOC_SIGNED_4:
2749 if ( reloc->r_extern() ) {
2750 dstAddr = 0;
2751 } else {
2752 dstAddr += 4;
2753 }
2754 kind = x86_64::kPCRel32_4;
2755 break;
2756 default:
2757 break;
2758 }
2759 if ( reloc->r_extern() )
2760 makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
2761 else {
2762 makeReference(kind, srcAddr, srcAddr+4+dstAddr);
2763 }
2764 break;
2765 case X86_64_RELOC_BRANCH:
2766 if ( ! reloc->r_pcrel() )
2767 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
2768 if ( reloc->r_length() != 2 )
2769 throw "length != 2 and X86_64_RELOC_BRANCH not supported";
2770 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
2771 if ( reloc->r_extern() ) {
2772 if ( isWeakImportSymbol(targetSymbol) )
2773 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
2774 else
2775 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
2776 }
2777 else {
2778 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
2779 }
2780 break;
2781 case X86_64_RELOC_GOT:
2782 if ( ! reloc->r_extern() )
2783 throw "not extern and X86_64_RELOC_GOT not supported";
2784 if ( ! reloc->r_pcrel() )
2785 throw "not pcrel and X86_64_RELOC_GOT not supported";
2786 if ( reloc->r_length() != 2 )
2787 throw "length != 2 and X86_64_RELOC_GOT not supported";
2788 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
2789 if ( isWeakImportSymbol(targetSymbol) )
2790 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
2791 else
2792 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
2793 break;
2794 case X86_64_RELOC_GOT_LOAD:
2795 if ( ! reloc->r_extern() )
2796 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
2797 if ( ! reloc->r_pcrel() )
2798 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
2799 if ( reloc->r_length() != 2 )
2800 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
2801 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
2802 if ( isWeakImportSymbol(targetSymbol) )
2803 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
2804 else
2805 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
2806 break;
2807 case X86_64_RELOC_SUBTRACTOR:
2808 if ( reloc->r_pcrel() )
2809 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
2810 if ( reloc->r_length() < 2 )
2811 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
2812 if ( !reloc->r_extern() )
2813 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
2814 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
2815 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
2816 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
2817 result = true;
2818 if ( nextReloc->r_pcrel() )
2819 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
2820 if ( nextReloc->r_length() != reloc->r_length() )
2821 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
2822 Reference<x86_64>* ref;
2823 bool negativeAddend;
2824 if ( reloc->r_length() == 2 ) {
2825 kind = x86_64::kPointerDiff32;
2826 dstAddr = E::get32(*fixUpPtr); // addend is in content
2827 negativeAddend = ((dstAddr & 0x80000000) != 0);
2828 }
2829 else {
2830 kind = x86_64::kPointerDiff;
2831 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
2832 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
2833 }
2834 ObjectFile::Atom* inAtom = this->findAtomAndOffset(srcAddr).atom;
2835 // create reference with "to" target
2836 if ( nextReloc->r_extern() ) {
2837 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
2838 const char* targetName = &fStrings[targetSymbol->n_strx()];
2839 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
2840 // if "to" is in this atom, change by-name to a direct reference
2841 if ( strcmp(targetName, inAtom->getName()) == 0 )
2842 ref->setTarget(*inAtom, 0);
2843 }
2844 else {
2845 ref = makeReference(kind, srcAddr, dstAddr);
2846 }
2847 // add in "from" target
2848 if ( reloc->r_extern() ) {
2849 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
2850 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
2851 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
2852 // from target is translation unit scoped, so use a direct reference
2853 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
2854 }
2855 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
2856 // if "from" is in this atom, change by-name to a direct reference
2857 ref->setFromTarget(*inAtom);
2858 }
2859 else {
2860 // some non-static other atom
2861 ref->setFromTargetName(fromTargetName);
2862 }
2863 }
2864 // addend goes in from side iff negative
2865 if ( negativeAddend )
2866 ref->setFromTargetOffset(-dstAddr);
2867 else
2868 ref->setToTargetOffset(dstAddr);
2869 break;
2870 default:
2871 fprintf(stderr, "unknown relocation type %d\n", reloc->r_type());
2872 }
2873 return result;
2874 }
2875
2876
2877 template <>
2878 const char* Reference<x86>::getDescription() const
2879 {
2880 static char temp[2048];
2881 switch( fKind ) {
2882 case x86::kNoFixUp:
2883 sprintf(temp, "reference to ");
2884 break;
2885 case x86::kFollowOn:
2886 sprintf(temp, "followed by ");
2887 break;
2888 case x86::kPointerWeakImport:
2889 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
2890 break;
2891 case x86::kPointer:
2892 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
2893 break;
2894 case x86::kPointerDiff:
2895 {
2896 // by-name references have quoted names
2897 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
2898 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
2899 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
2900 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
2901 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
2902 return temp;
2903 }
2904 break;
2905 case x86::kPCRel32WeakImport:
2906 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
2907 break;
2908 case x86::kPCRel32:
2909 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
2910 break;
2911 case x86::kAbsolute32:
2912 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
2913 break;
2914 }
2915 // always quote by-name references
2916 if ( fToTargetName != NULL ) {
2917 strcat(temp, "\"");
2918 strcat(temp, fToTargetName);
2919 strcat(temp, "\"");
2920 }
2921 else if ( fToTarget.atom != NULL ) {
2922 strcat(temp, fToTarget.atom->getDisplayName());
2923 }
2924 else {
2925 strcat(temp, "NULL target");
2926 }
2927 if ( fToTarget.offset != 0 )
2928 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
2929
2930 return temp;
2931 }
2932
2933
2934 template <>
2935 const char* Reference<ppc>::getDescription() const
2936 {
2937 static char temp[2048];
2938 switch( fKind ) {
2939 case ppc::kNoFixUp:
2940 sprintf(temp, "reference to ");
2941 break;
2942 case ppc::kFollowOn:
2943 sprintf(temp, "followed by ");
2944 break;
2945 case ppc::kPointerWeakImport:
2946 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
2947 break;
2948 case ppc::kPointer:
2949 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
2950 break;
2951 case ppc::kPointerDiff32:
2952 {
2953 // by-name references have quoted names
2954 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
2955 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
2956 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
2957 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
2958 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
2959 return temp;
2960 }
2961 case ppc::kPointerDiff64:
2962 throw "unsupported refrence kind";
2963 break;
2964 case ppc::kBranch24WeakImport:
2965 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
2966 break;
2967 case ppc::kBranch24:
2968 case ppc::kBranch14:
2969 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
2970 break;
2971 case ppc::kPICBaseLow16:
2972 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2973 break;
2974 case ppc::kPICBaseLow14:
2975 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2976 break;
2977 case ppc::kPICBaseHigh16:
2978 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2979 break;
2980 case ppc::kAbsLow16:
2981 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2982 break;
2983 case ppc::kAbsLow14:
2984 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
2985 break;
2986 case ppc::kAbsHigh16:
2987 sprintf(temp, "offset 0x%04X, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2988 break;
2989 case ppc::kAbsHigh16AddLow:
2990 sprintf(temp, "offset 0x%04X, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2991 break;
2992 }
2993 // always quote by-name references
2994 if ( fToTargetName != NULL ) {
2995 strcat(temp, "\"");
2996 strcat(temp, fToTargetName);
2997 strcat(temp, "\"");
2998 }
2999 else if ( fToTarget.atom != NULL ) {
3000 strcat(temp, fToTarget.atom->getDisplayName());
3001 }
3002 else {
3003 strcat(temp, "NULL target");
3004 }
3005 if ( fToTarget.offset != 0 )
3006 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
3007
3008 return temp;
3009 }
3010
3011 template <>
3012 const char* Reference<ppc64>::getDescription() const
3013 {
3014 static char temp[2048];
3015 switch( fKind ) {
3016 case ppc64::kNoFixUp:
3017 sprintf(temp, "reference to ");
3018 break;
3019 case ppc64::kFollowOn:
3020 sprintf(temp, "followed by ");
3021 break;
3022 case ppc64::kPointerWeakImport:
3023 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
3024 break;
3025 case ppc64::kPointer:
3026 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
3027 break;
3028 case ppc64::kPointerDiff64:
3029 {
3030 // by-name references have quoted names
3031 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
3032 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
3033 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
3034 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
3035 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
3036 return temp;
3037 }
3038 case ppc64::kPointerDiff32:
3039 {
3040 // by-name references have quoted names
3041 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
3042 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
3043 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
3044 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
3045 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
3046 return temp;
3047 }
3048 case ppc64::kBranch24WeakImport:
3049 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
3050 break;
3051 case ppc64::kBranch24:
3052 case ppc64::kBranch14:
3053 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
3054 break;
3055 case ppc64::kPICBaseLow16:
3056 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
3057 break;
3058 case ppc64::kPICBaseLow14:
3059 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
3060 break;
3061 case ppc64::kPICBaseHigh16:
3062 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
3063 break;
3064 case ppc64::kAbsLow16:
3065 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
3066 break;
3067 case ppc64::kAbsLow14:
3068 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
3069 break;
3070 case ppc64::kAbsHigh16:
3071 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
3072 break;
3073 case ppc64::kAbsHigh16AddLow:
3074 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
3075 break;
3076 }
3077 // always quote by-name references
3078 if ( fToTargetName != NULL ) {
3079 strcat(temp, "\"");
3080 strcat(temp, fToTargetName);
3081 strcat(temp, "\"");
3082 }
3083 else if ( fToTarget.atom != NULL ) {
3084 strcat(temp, fToTarget.atom->getDisplayName());
3085 }
3086 else {
3087 strcat(temp, "NULL target");
3088 }
3089 if ( fToTarget.offset != 0 )
3090 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
3091
3092 return temp;
3093 }
3094
3095
3096 template <>
3097 const char* Reference<x86_64>::getDescription() const
3098 {
3099 static char temp[2048];
3100 switch( fKind ) {
3101 case x86_64::kNoFixUp:
3102 sprintf(temp, "reference to ");
3103 break;
3104 case x86_64::kFollowOn:
3105 sprintf(temp, "followed by ");
3106 break;
3107 case x86_64::kPointerWeakImport:
3108 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
3109 break;
3110 case x86_64::kPointer:
3111 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
3112 break;
3113 case x86_64::kPointerDiff32:
3114 case x86_64::kPointerDiff:
3115 {
3116 // by-name references have quoted names
3117 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
3118 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
3119 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
3120 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
3121 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
3122 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
3123 return temp;
3124 }
3125 break;
3126 case x86_64::kPCRel32:
3127 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
3128 break;
3129 case x86_64::kPCRel32_1:
3130 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
3131 break;
3132 case x86_64::kPCRel32_2:
3133 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
3134 break;
3135 case x86_64::kPCRel32_4:
3136 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
3137 break;
3138 case x86_64::kBranchPCRel32:
3139 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
3140 break;
3141 case x86_64::kBranchPCRel32WeakImport:
3142 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
3143 break;
3144 case x86_64::kPCRel32GOT:
3145 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
3146 break;
3147 case x86_64::kPCRel32GOTWeakImport:
3148 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
3149 break;
3150 case x86_64::kPCRel32GOTLoad:
3151 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
3152 break;
3153 case x86_64::kPCRel32GOTLoadWeakImport:
3154 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
3155 break;
3156 }
3157 // always quote by-name references
3158 if ( fToTargetName != NULL ) {
3159 strcat(temp, "\"");
3160 strcat(temp, fToTargetName);
3161 strcat(temp, "\"");
3162 }
3163 else if ( fToTarget.atom != NULL ) {
3164 strcat(temp, fToTarget.atom->getDisplayName());
3165 }
3166 else {
3167 strcat(temp, "NULL target");
3168 }
3169 if ( fToTarget.offset != 0 )
3170 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
3171
3172 return temp;
3173 }
3174
3175
3176
3177 }; // namespace relocatable
3178 }; // namespace mach_o
3179
3180 #endif // __OBJECT_FILE_MACH_O__