1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __OBJECT_FILE_MACH_O__
26 #define __OBJECT_FILE_MACH_O__
31 #include <sys/param.h>
37 #include "MachOFileAbstraction.hpp"
38 #include "Architectures.hpp"
39 #include "ObjectFile.h"
41 #include "debugline.h"
46 // To implement architecture xxx, you must write template specializations for the following six methods:
47 // Reader<xxx>::validFile()
48 // Reader<xxx>::validSectionType()
49 // Reader<xxx>::addRelocReference()
50 // Reference<xxx>::getDescription()
56 extern __attribute__((noreturn)) void throwf(const char* format, ...);
57 extern void warning(const char* format, ...);
60 namespace relocatable {
67 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
69 return ( left->getFixUpOffset() < right->getFixUpOffset() );
75 template <typename A> class Reader;
79 AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
80 AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
81 ObjectFile::Atom* atom;
87 class Reference : public ObjectFile::Reference
90 typedef typename A::P P;
91 typedef typename A::P::uint_t pint_t;
92 typedef typename A::ReferenceKinds Kinds;
94 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
95 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
96 Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
98 virtual ~Reference() {}
101 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const;
102 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const;
103 virtual uint8_t getKind() const { return (uint8_t)fKind; }
104 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
105 virtual const char* getTargetName() const { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); }
106 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
107 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
108 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
109 virtual const char* getFromTargetName() const { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); }
110 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = ⌖ fToTarget.offset = offset; }
111 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
112 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = ⌖ }
113 virtual void setFromTargetName(const char* name) { fFromTargetName = name; }
114 virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; }
115 virtual const char* getDescription() const;
116 virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; }
118 static bool fgForFinalLinkedImage;
121 pint_t fFixUpOffsetInSrc;
122 AtomAndOffset fToTarget;
123 AtomAndOffset fFromTarget;
124 const char* fToTargetName;
125 const char* fFromTargetName;
130 template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
132 template <typename A>
133 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
134 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
137 // make reference a by-name unless:
138 // - the reference type is only used with direct references
139 // - the target is translation unit scoped
140 // - the target kind is not regular (is weak or tentative)
141 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
142 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
143 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) ) {
144 fToTargetName = toTarget.atom->getName();
145 //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d, target section=%s\n", toTarget.atom, fToTargetName, toTarget.atom->getScope(), toTarget.atom->getSectionName());
146 fToTarget.atom = NULL;
148 ((class BaseAtom*)at.atom)->addReference(this);
149 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
152 template <typename A>
153 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
154 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
155 fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
157 // make reference a by-name where needed
158 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
159 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
160 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
161 && (toTarget.atom != at.atom) ) {
162 fToTargetName = toTarget.atom->getName();
163 fToTarget.atom = NULL;
165 ((class BaseAtom*)at.atom)->addReference(this);
166 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
167 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
170 template <typename A>
171 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
172 : fFixUpOffsetInSrc(at.offset),
173 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
175 fToTarget.offset = toOffset;
176 ((class BaseAtom*)at.atom)->addReference(this);
179 template <typename A>
180 ObjectFile::Reference::TargetBinding Reference<A>::getTargetBinding() const
182 if ( fgForFinalLinkedImage ) {
183 if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) )
184 return ObjectFile::Reference::kDontBind;
186 if ( fToTarget.atom == NULL )
187 return ObjectFile::Reference::kUnboundByName;
188 if ( fToTargetName == NULL )
189 return ObjectFile::Reference::kBoundDirectly;
191 return ObjectFile::Reference::kBoundByName;
194 template <typename A>
195 ObjectFile::Reference::TargetBinding Reference<A>::getFromTargetBinding() const
197 if ( fFromTarget.atom == NULL ) {
198 if ( fFromTargetName == NULL )
199 return ObjectFile::Reference::kDontBind;
201 return ObjectFile::Reference::kUnboundByName;
204 if ( fFromTargetName == NULL )
205 return ObjectFile::Reference::kBoundDirectly;
207 return ObjectFile::Reference::kBoundByName;
213 template <typename A>
214 class Segment : public ObjectFile::Segment
217 Segment(const macho_section<typename A::P>* sect);
218 virtual const char* getName() const { return fSection->segname(); }
219 virtual bool isContentReadable() const { return true; }
220 virtual bool isContentWritable() const { return fWritable; }
221 virtual bool isContentExecutable() const { return fExecutable; }
223 const macho_section<typename A::P>* fSection;
228 template <typename A>
229 Segment<A>::Segment(const macho_section<typename A::P>* sect)
230 : fSection(sect), fWritable(true), fExecutable(false)
232 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
236 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
243 class DataSegment : public ObjectFile::Segment
246 virtual const char* getName() const { return "__DATA"; }
247 virtual bool isContentReadable() const { return true; }
248 virtual bool isContentWritable() const { return true; }
249 virtual bool isContentExecutable() const { return false; }
251 static DataSegment fgSingleton;
254 DataSegment DataSegment::fgSingleton;
256 class LinkEditSegment : public ObjectFile::Segment
259 virtual const char* getName() const { return "__LINKEDIT"; }
260 virtual bool isContentReadable() const { return true; }
261 virtual bool isContentWritable() const { return false; }
262 virtual bool isContentExecutable() const { return false; }
264 static LinkEditSegment fgSingleton;
267 LinkEditSegment LinkEditSegment::fgSingleton;
269 class BaseAtom : public ObjectFile::Atom
272 BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
274 virtual void setSize(uint64_t size) = 0;
275 virtual void addReference(ObjectFile::Reference* ref) = 0;
276 virtual void sortReferences() = 0;
277 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
278 virtual uint64_t getObjectAddress() const = 0;
279 virtual uint32_t getOrdinal() const { return fOrdinal; }
280 virtual void setOrdinal(uint32_t value) { fOrdinal = value; }
281 virtual const void* getSectionRecord() const = 0;
282 virtual bool isAlias() const { return false; }
284 uint32_t fStabsStartIndex;
285 uint32_t fStabsCount;
292 bool operator()(const class BaseAtom* left, const class BaseAtom* right) {
295 uint64_t leftAddr = left->getObjectAddress();
296 uint64_t rightAddr = right->getObjectAddress();
297 if ( leftAddr < rightAddr ) {
300 else if ( leftAddr > rightAddr ) {
304 // if they have same address, one might be the end of a section and the other the start of the next section
305 const void* leftSection = left->getSectionRecord();
306 const void* rightSection = right->getSectionRecord();
307 if ( leftSection != rightSection ) {
308 return ( leftSection < rightSection );
310 // if they have same address and section, one might be an alias
311 bool leftAlias = left->isAlias();
312 bool rightAlias = right->isAlias();
313 if ( leftAlias && rightAlias ) {
314 // sort multiple aliases for same address first by scope
315 ObjectFile::Atom::Scope leftScope = left->getScope();
316 ObjectFile::Atom::Scope rightScope = right->getScope();
317 if ( leftScope != rightScope ) {
318 return ( leftScope < rightScope );
320 // sort multiple aliases for same address then by name
321 return ( strcmp(left->getName(), right->getName()) < 0 );
323 else if ( leftAlias ) {
326 else if ( rightAlias ) {
330 // they must be tentative defintions
331 switch ( left->getDefinitionKind() ) {
332 case ObjectFile::Atom::kTentativeDefinition:
333 // sort tentative definitions by name
334 return ( strcmp(left->getName(), right->getName()) < 0 );
335 case ObjectFile::Atom::kAbsoluteSymbol:
336 // sort absolute symbols with same address by name
337 return ( strcmp(left->getName(), right->getName()) < 0 );
339 // hack for rdar://problem/5102873
340 if ( !left->isZeroFill() || !right->isZeroFill() )
341 warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath());
352 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
353 // pointing to it. A C function or global variable is represented by one of these atoms.
356 template <typename A>
357 class SymbolAtom : public BaseAtom
360 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
361 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
362 { return fOwner.getTranslationUnitSource(dir, name); }
363 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
364 virtual const char* getDisplayName() const { return getName(); }
365 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
366 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
367 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
368 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
369 virtual bool dontDeadStrip() const;
370 virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
371 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
372 virtual uint64_t getSize() const { return fSize; }
373 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
374 virtual bool mustRemainInSection() const { return true; }
375 virtual const char* getSectionName() const;
376 virtual Segment<A>& getSegment() const { return *fSegment; }
377 virtual ObjectFile::Atom& getFollowOnAtom() const;
378 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
379 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
380 virtual void copyRawContent(uint8_t buffer[]) const;
381 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
382 virtual void setSize(uint64_t size);
383 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
384 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
385 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
386 virtual uint64_t getObjectAddress() const { return fAddress; }
387 virtual const void* getSectionRecord() const { return (const void*)fSection; }
390 typedef typename A::P P;
391 typedef typename A::P::E E;
392 typedef typename A::P::uint_t pint_t;
393 typedef typename A::ReferenceKinds Kinds;
394 typedef typename std::vector<Reference<A>*> ReferenceVector;
395 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
396 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
397 friend class Reader<A>;
399 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
400 virtual ~SymbolAtom() {}
403 const macho_nlist<P>* fSymbol;
406 const macho_section<P>* fSection;
407 Segment<A>* fSegment;
408 ReferenceVector fReferences;
409 std::vector<ObjectFile::LineInfo> fLineInfo;
410 ObjectFile::Atom::Scope fScope;
411 SymbolTableInclusion fSymbolTableInclusion;
412 ObjectFile::Alignment fAlignment;
416 template <typename A>
417 SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
418 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fAlignment(0)
420 uint8_t type = symbol->n_type();
421 if ( (type & N_EXT) == 0 )
422 fScope = ObjectFile::Atom::scopeTranslationUnit;
423 else if ( (type & N_PEXT) != 0 )
424 fScope = ObjectFile::Atom::scopeLinkageUnit;
426 fScope = ObjectFile::Atom::scopeGlobal;
427 if ( (type & N_TYPE) == N_SECT ) {
429 fSegment = new Segment<A>(fSection);
430 fAddress = fSymbol->n_value();
431 pint_t sectionStartAddr = section->addr();
432 pint_t sectionEndAddr = section->addr()+section->size();
433 if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) {
434 throwf("malformed .o file, symbol %s with address 0x%0llX is not with section %d (%s,%s) address range of 0x%0llX to 0x%0llX",
435 this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(),
436 (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) );
440 warning("unknown symbol type: %d", type);
443 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
444 // support for .o files built with old ld64
445 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
446 const char* name = this->getName();
447 const int nameLen = strlen(name);
448 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
449 // switch symbol to point at name that does not have trailing $stub
450 char correctName[nameLen];
451 strncpy(correctName, name, nameLen-5);
452 correctName[nameLen-5] = '\0';
453 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
454 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
455 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
456 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
463 // support for labeled stubs
464 switch ( section->flags() & SECTION_TYPE ) {
466 setSize(section->reserved2());
468 case S_LAZY_SYMBOL_POINTERS:
469 case S_NON_LAZY_SYMBOL_POINTERS:
470 setSize(sizeof(pint_t));
472 case S_4BYTE_LITERALS:
475 case S_8BYTE_LITERALS:
478 case S_16BYTE_LITERALS:
481 case S_CSTRING_LITERALS:
482 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
487 // size calculate later after next atom is found
491 // compute whether this atom needs to be in symbol table
492 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
493 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
495 else if ( fOwner.fOptions.fForFinalLinkedImage
496 && ((section->flags() & SECTION_TYPE) == S_COALESCED)
497 && ((section->flags() & S_ATTR_NO_TOC) == S_ATTR_NO_TOC)
498 && ((section->flags() & S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS)
499 && (strcmp(section->sectname(), "__eh_frame") == 0) ) {
500 // .eh symbols exist so the linker can associate them with functions
501 // removing them from final linked images is a big space savings rdar://problem/4180168
502 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
504 else if ( fOwner.fOptions.fForFinalLinkedImage
505 && ((section->flags() & SECTION_TYPE) == S_REGULAR)
506 && (strncmp(section->sectname(), "__gcc_except_tab", 16) == 0)
507 && (strncmp(this->getName(), "GCC_except_table", 16) == 0) ) {
508 // GCC_except_table* symbols don't need to exist in final linked image
509 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
511 else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) {
512 // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
513 // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
514 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
517 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
520 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
522 // work around malformed icc generated .o files <rdar://problem/5349847>
523 // if section starts with a symbol and that symbol address does not match section alignment, then force it to
524 if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) )
525 fAlignment.modulus = 0;
528 template <typename A>
529 bool SymbolAtom<A>::dontDeadStrip() const
531 // the symbol can have a no-dead-strip bit
532 if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 )
534 // or the section can have a no-dead-strip bit
535 return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP );
539 template <typename A>
540 const char* SymbolAtom<A>::getSectionName() const
542 if ( fOwner.fOptions.fForFinalLinkedImage && (strcmp(fSection->sectname(), "__textcoal_nt") == 0) )
545 if ( strlen(fSection->sectname()) > 15 ) {
546 static char temp[18];
547 strncpy(temp, fSection->sectname(), 16);
551 return fSection->sectname();
554 template <typename A>
555 ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
557 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
558 Reference<A>* ref = *it;
559 if ( ref->getKind() == A::kFollowOn )
560 return ref->getTarget();
562 return *((ObjectFile::Atom*)NULL);
569 Beyond(uint64_t offset) : fOffset(offset) {}
570 bool operator()(ObjectFile::Reference* ref) const {
571 return ( ref->getFixUpOffset() >= fOffset );
578 template <typename A>
579 void SymbolAtom<A>::setSize(uint64_t size)
581 // when resizing, any references beyond the new size are tossed
582 if ( (fSize != 0) && (fReferences.size() > 0) )
583 fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end());
588 template <typename A>
589 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
593 bzero(buffer, fSize);
595 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
596 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
601 // A SymbolAliasAtom represents an alternate name for a SymbolAtom
604 template <typename A>
605 class SymbolAliasAtom : public BaseAtom
608 virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); }
609 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
610 { return fAliasOf.getTranslationUnitSource(dir, name); }
611 virtual const char* getName() const { return fName; }
612 virtual const char* getDisplayName() const { return fName; }
613 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
614 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); }
615 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); }
616 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
617 virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); }
618 virtual bool isThumb() const { return fAliasOf.isThumb(); }
619 virtual uint64_t getSize() const { return 0; }
620 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
621 virtual bool mustRemainInSection() const { return true; }
622 virtual const char* getSectionName() const { return fAliasOf.getSectionName(); }
623 virtual Segment<A>& getSegment() const { return (Segment<A>&)fAliasOf.getSegment(); }
624 virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; }
625 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
626 virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); }
627 virtual void copyRawContent(uint8_t buffer[]) const {}
628 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
629 virtual void setSize(uint64_t size) { }
630 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
631 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
632 virtual void addLineInfo(const ObjectFile::LineInfo& info) { }
633 virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); }
634 virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); }
635 virtual bool isAlias() const { return true; }
638 typedef typename A::P P;
639 typedef typename std::vector<Reference<A>*> ReferenceVector;
640 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
641 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
642 friend class Reader<A>;
644 SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
645 virtual ~SymbolAliasAtom() {}
648 const BaseAtom& fAliasOf;
649 ObjectFile::Atom::Scope fScope;
651 ReferenceVector fReferences;
655 template <typename A>
656 SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
657 : fName(name), fAliasOf(aliasOf)
659 //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
660 if ( symbol != NULL ) {
661 uint8_t type = symbol->n_type();
662 if ( (type & N_EXT) == 0 )
663 fScope = ObjectFile::Atom::scopeTranslationUnit;
664 else if ( (type & N_PEXT) != 0 )
665 fScope = ObjectFile::Atom::scopeLinkageUnit;
667 fScope = ObjectFile::Atom::scopeGlobal;
668 fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
671 // aliases defined on the command line are initially global scope
672 fScope = ObjectFile::Atom::scopeGlobal;
673 fDontDeadStrip = false;
675 // add follow-on reference to real atom
676 new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
681 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
682 // For instance, "int foo;" is neither a declaration or a definition and
683 // is represented by a TentativeAtom.
685 template <typename A>
686 class TentativeAtom : public BaseAtom
689 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
690 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
691 { return fOwner.getTranslationUnitSource(dir, name); }
692 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
693 virtual const char* getDisplayName() const { return getName(); }
694 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
695 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
696 virtual bool isZeroFill() const { return true; }
697 virtual bool isThumb() const { return false; }
698 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
699 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
700 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
701 virtual uint64_t getSize() const { return fSymbol->n_value(); }
702 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
703 virtual bool mustRemainInSection() const { return true; }
704 virtual const char* getSectionName() const;
705 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
706 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
707 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
708 virtual ObjectFile::Alignment getAlignment() const;
709 virtual void copyRawContent(uint8_t buffer[]) const;
710 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
711 virtual void setSize(uint64_t size) { }
712 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
713 virtual void sortReferences() { }
714 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
715 virtual uint64_t getObjectAddress() const { return ULLONG_MAX; }
716 virtual const void* getSectionRecord() const { return NULL; }
719 typedef typename A::P P;
720 typedef typename A::P::E E;
721 typedef typename A::P::uint_t pint_t;
722 typedef typename A::ReferenceKinds Kinds;
723 friend class Reader<A>;
725 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
726 virtual ~TentativeAtom() {}
729 const macho_nlist<P>* fSymbol;
730 ObjectFile::Atom::Scope fScope;
731 static std::vector<ObjectFile::Reference*> fgNoReferences;
734 template <typename A>
735 std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
737 template <typename A>
738 TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
739 : fOwner(owner), fSymbol(symbol)
741 uint8_t type = symbol->n_type();
742 if ( (type & N_EXT) == 0 )
743 fScope = ObjectFile::Atom::scopeTranslationUnit;
744 else if ( (type & N_PEXT) != 0 )
745 fScope = ObjectFile::Atom::scopeLinkageUnit;
747 fScope = ObjectFile::Atom::scopeGlobal;
748 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
749 // tentative definition
752 warning("unknown symbol type: %d", type);
754 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
758 template <typename A>
759 ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
761 uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc());
762 if ( alignment == 0 ) {
763 // common symbols align to their size
764 // that is, a 4-byte common aligns to 4-bytes
765 // if this size is not a power of two,
766 // then round up to the next power of two
767 uint64_t size = this->getSize();
768 alignment = 63 - (uint8_t)__builtin_clzll(size);
769 if ( size != (1ULL << alignment) )
772 // limit alignment of extremely large commons to 2^15 bytes (8-page)
773 if ( alignment < 12 )
774 return ObjectFile::Alignment(alignment);
776 return ObjectFile::Alignment(12);
779 template <typename A>
780 const char* TentativeAtom<A>::getSectionName() const
782 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
789 template <typename A>
790 void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
792 bzero(buffer, getSize());
797 // An AnonymousAtom represents compiler generated data that has no name.
798 // For instance, a literal C-string or a 64-bit floating point constant
799 // is represented by an AnonymousAtom.
801 template <typename A>
802 class AnonymousAtom : public BaseAtom
805 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
806 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
807 virtual const char* getName() const { return fSynthesizedName; }
808 virtual const char* getDisplayName() const;
809 virtual ObjectFile::Atom::Scope getScope() const;
810 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; }
811 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
812 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
813 virtual bool isZeroFill() const;
814 virtual bool isThumb() const { return false; }
815 virtual uint64_t getSize() const { return fSize; }
816 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
817 virtual bool mustRemainInSection() const { return true; }
818 virtual const char* getSectionName() const;
819 virtual Segment<A>& getSegment() const { return *fSegment; }
820 virtual ObjectFile::Atom& getFollowOnAtom() const;
821 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
822 virtual ObjectFile::Alignment getAlignment() const;
823 virtual void copyRawContent(uint8_t buffer[]) const;
824 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
825 virtual void setSize(uint64_t size) { fSize = size; }
826 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
827 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
828 virtual void addLineInfo(const ObjectFile::LineInfo& info) { warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); }
829 virtual uint64_t getObjectAddress() const { return fAddress; }
830 virtual const void* getSectionRecord() const { return (const void*)fSection; }
831 BaseAtom* redirectTo() { return fRedirect; }
832 bool isWeakImportStub() { return fWeakImportStub; }
836 typedef typename A::P P;
837 typedef typename A::P::E E;
838 typedef typename A::P::uint_t pint_t;
839 typedef typename A::ReferenceKinds Kinds;
840 typedef typename std::vector<Reference<A>*> ReferenceVector;
841 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
842 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
843 friend class Reader<A>;
845 AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
846 virtual ~AnonymousAtom() {}
847 static bool cstringsHaveLabels();
850 const char* fSynthesizedName;
851 const char* fDisplayName;
852 const macho_section<P>* fSection;
855 Segment<A>* fSegment;
856 ReferenceVector fReferences;
859 bool fWeakImportStub;
860 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
861 ObjectFile::Atom::Scope fScope;
862 ObjectFile::Atom::DefinitionKind fKind;
865 template <typename A>
866 AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
867 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
868 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
869 fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition)
871 fSegment = new Segment<A>(fSection);
873 uint8_t type = fSection->flags() & SECTION_TYPE;
874 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
878 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
883 if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
884 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
885 fSynthesizedName = ".objc_class_name_PENDING";
886 owner.fAtomsPendingAName.push_back(this);
887 owner.fSectionsWithAtomsPendingAName.insert(fSection);
888 if ( fOwner.fOptions.fForFinalLinkedImage )
889 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
891 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
892 fScope = ObjectFile::Atom::scopeGlobal;
894 else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
895 // handle .o files created by old ld64 -r that are missing cstring section type
896 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
897 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
899 else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) {
900 fSynthesizedName = "cfstring-pointer-name-PENDING";
901 fScope = ObjectFile::Atom::scopeLinkageUnit;
902 owner.fAtomsPendingAName.push_back(this);
903 owner.fSectionsWithAtomsPendingAName.insert(fSection);
904 fDontDeadStrip = false;
905 fKind = ObjectFile::Atom::kWeakDefinition;
908 case S_CSTRING_LITERALS:
910 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
911 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
912 fScope = ObjectFile::Atom::scopeLinkageUnit;
913 fKind = ObjectFile::Atom::kWeakDefinition;
914 fDontDeadStrip = false;
915 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
916 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
919 case S_4BYTE_LITERALS:
921 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
922 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
923 fScope = ObjectFile::Atom::scopeLinkageUnit;
924 fKind = ObjectFile::Atom::kWeakDefinition;
925 fDontDeadStrip = false;
928 case S_8BYTE_LITERALS:
930 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
931 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
932 fScope = ObjectFile::Atom::scopeLinkageUnit;
933 fKind = ObjectFile::Atom::kWeakDefinition;
934 fDontDeadStrip = false;
937 case S_16BYTE_LITERALS:
939 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
940 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
941 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
942 fScope = ObjectFile::Atom::scopeLinkageUnit;
943 fKind = ObjectFile::Atom::kWeakDefinition;
944 fDontDeadStrip = false;
947 case S_LITERAL_POINTERS:
949 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
950 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
951 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
952 fSynthesizedName = "literal-pointer-name-PENDING";
953 fScope = ObjectFile::Atom::scopeLinkageUnit;
954 fKind = ObjectFile::Atom::kWeakDefinition;
955 fDontDeadStrip = false;
956 owner.fAtomsPendingAName.push_back(this);
957 owner.fSectionsWithAtomsPendingAName.insert(fSection);
960 case S_MOD_INIT_FUNC_POINTERS:
961 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
963 case S_MOD_TERM_FUNC_POINTERS:
964 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
968 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
969 index += fSection->reserved1();
970 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
971 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
972 uint32_t strOffset = sym->n_strx();
973 // want name to not have $stub suffix, this is what automatic stub generation expects
974 fSynthesizedName = &fOwner.fStrings[strOffset];
975 // check for weak import
976 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
977 // sometimes the compiler gets confused and generates a stub to a static function
978 // if so, we should redirect any call to the stub to be calls to the real static function atom
979 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
980 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
981 if ( staticAtom != NULL )
982 fRedirect = staticAtom;
984 fKind = ObjectFile::Atom::kWeakDefinition;
985 // might be a spurious stub for a static function, make stub static too
986 if ( (sym->n_type() & N_EXT) == 0 )
987 fScope = ObjectFile::Atom::scopeTranslationUnit;
989 fScope = ObjectFile::Atom::scopeLinkageUnit;
992 case S_LAZY_SYMBOL_POINTERS:
993 case S_NON_LAZY_SYMBOL_POINTERS:
995 fDontDeadStrip = false;
996 fScope = ObjectFile::Atom::scopeLinkageUnit;
997 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
998 index += fSection->reserved1();
999 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1000 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1001 // Silly codegen with non-lazy pointer to a local symbol
1002 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1003 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
1004 // All atoms not created yet, so we need to scan symbol table
1005 const macho_nlist<P>* closestSym = NULL;
1006 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1007 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
1008 if ( ((sym->n_type() & N_TYPE) == N_SECT)
1009 && ((sym->n_type() & N_STAB) == 0) ) {
1010 if ( sym->n_value() == nonLazyPtrValue ) {
1011 const char* name = &fOwner.fStrings[sym->n_strx()];
1012 char* str = new char[strlen(name)+16];
1014 strcat(str, "$non_lazy_ptr");
1015 fSynthesizedName = str;
1016 // add direct reference to target later, because its atom may not be constructed yet
1017 fOwner.fLocalNonLazys.push_back(this);
1018 fScope = ObjectFile::Atom::scopeTranslationUnit;
1021 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1026 // add direct reference to target later, because its atom may not be constructed yet
1027 if ( closestSym != NULL ) {
1028 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1030 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1031 fSynthesizedName = str;
1034 fSynthesizedName = "$interior$non_lazy_ptr";
1036 fScope = ObjectFile::Atom::scopeTranslationUnit;
1037 fOwner.fLocalNonLazys.push_back(this);
1040 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1041 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1042 char* str = new char[strlen(name)+16];
1044 if ( type == S_LAZY_SYMBOL_POINTERS )
1045 strcat(str, "$lazy_ptr");
1047 strcat(str, "$non_lazy_ptr");
1048 fSynthesizedName = str;
1050 // optimize __IMPORT segment out of i386 dyld or if -slow_stubs is used
1051 if ( (fOwner.fOptions.fForDyld || fOwner.fOptions.fSlowx86Stubs) && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
1052 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1053 dummySection->set_segname("__DATA");
1054 dummySection->set_sectname("__nl_symbol_ptr");
1055 fSection = dummySection;
1056 fSegment = new Segment<A>(fSection);
1059 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1060 fKind = ObjectFile::Atom::kWeakDefinition;
1062 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1063 // target is translation unit scoped, so add direct reference to target
1064 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1065 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1068 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1069 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1071 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1076 throwf("section type %d not supported with address=0x%08X", type, addr);
1078 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1081 // x86_64 uses L labels on cstrings to allow relocs with addends
1082 template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1083 template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1086 template <typename A>
1087 void AnonymousAtom<A>::resolveName()
1089 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1090 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1091 // references are not yet sorted, so scan the vector
1092 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1093 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1094 const char* superStr = (*rit)->getTargetName();
1095 if ( strncmp(superStr, "cstring=", 8) == 0 ) {
1096 const char* superClassName;
1097 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1098 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1103 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1104 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1105 const char* classStr = (*rit)->getTargetName();
1106 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
1107 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1113 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
1114 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1115 if ( references.size() < 1 )
1116 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1117 ObjectFile::Reference* ref = references[0];
1118 const char* str = ref->getTargetName();
1119 if ( strncmp(str, "cstring=", 8) == 0 ) {
1120 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1123 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1124 // references are not yet sorted, so scan the vector
1125 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1126 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1127 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1128 const char* superStr = (*rit)->getTargetName();
1129 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1130 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1133 // compiled with -fwritable-strings or a non-ASCII string
1134 ObjectFile::Atom& stringDataAtom = (*rit)->getTarget();
1135 uint8_t buffer[stringDataAtom.getSize()];
1136 stringDataAtom.copyRawContent(buffer);
1137 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1138 fScope = ObjectFile::Atom::scopeTranslationUnit;
1139 fSynthesizedName = "cfstring-not-coalesable";
1148 template <typename A>
1149 const char* AnonymousAtom<A>::getDisplayName() const
1151 if ( fSynthesizedName != NULL )
1152 return fSynthesizedName;
1154 if ( fDisplayName != NULL )
1155 return fDisplayName;
1157 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1158 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1159 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
1162 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
1164 return fDisplayName;
1168 template <typename A>
1169 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1175 template <typename A>
1176 bool AnonymousAtom<A>::isZeroFill() const
1178 return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
1182 template <typename A>
1183 const char* AnonymousAtom<A>::getSectionName() const
1185 if ( strlen(fSection->sectname()) > 15 ) {
1186 static char temp[18];
1187 strncpy(temp, fSection->sectname(), 16);
1191 return fSection->sectname();
1194 template <typename A>
1195 ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
1197 switch ( fSection->flags() & SECTION_TYPE ) {
1198 case S_4BYTE_LITERALS:
1199 return ObjectFile::Alignment(2);
1200 case S_8BYTE_LITERALS:
1201 return ObjectFile::Alignment(3);
1202 case S_16BYTE_LITERALS:
1203 return ObjectFile::Alignment(4);
1204 case S_NON_LAZY_SYMBOL_POINTERS:
1205 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
1206 case S_CSTRING_LITERALS:
1207 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1208 return ObjectFile::Alignment(fSection->align());
1210 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
1215 template <typename A>
1216 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1218 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1219 Reference<A>* ref = *it;
1220 if ( ref->getKind() == A::kFollowOn )
1221 return ref->getTarget();
1223 return *((ObjectFile::Atom*)NULL);
1226 template <typename A>
1227 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1231 bzero(buffer, fSize);
1233 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1234 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1240 // An AbsoluteAtom represents an N_ABS symbol which can only be created in
1241 // assembly language and usable by static executables such as the kernel/
1243 template <typename A>
1244 class AbsoluteAtom : public BaseAtom
1247 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1248 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1249 { return fOwner.getTranslationUnitSource(dir, name); }
1250 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1251 virtual const char* getDisplayName() const { return getName(); }
1252 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1253 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1254 virtual bool isZeroFill() const { return false; }
1255 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
1256 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1257 virtual bool dontDeadStrip() const { return false; }
1258 virtual uint64_t getSize() const { return 0; }
1259 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1260 virtual bool mustRemainInSection() const { return true; }
1261 virtual const char* getSectionName() const { return "._absolute"; }
1262 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1263 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1264 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1265 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1266 virtual void copyRawContent(uint8_t buffer[]) const { }
1267 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1268 virtual void setSize(uint64_t size) { }
1269 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1270 virtual void sortReferences() { }
1271 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1272 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1273 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1274 virtual const void* getSectionRecord() const { return NULL; }
1277 typedef typename A::P P;
1278 typedef typename A::P::E E;
1279 typedef typename A::P::uint_t pint_t;
1280 typedef typename A::ReferenceKinds Kinds;
1281 friend class Reader<A>;
1283 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1284 virtual ~AbsoluteAtom() {}
1287 const macho_nlist<P>* fSymbol;
1288 ObjectFile::Atom::Scope fScope;
1289 static std::vector<ObjectFile::Reference*> fgNoReferences;
1292 template <typename A>
1293 std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1295 template <typename A>
1296 AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1297 : fOwner(owner), fSymbol(symbol)
1299 // store absolute adress in fSectionOffset
1300 fSectionOffset = symbol->n_value();
1302 uint8_t type = symbol->n_type();
1303 if ( (type & N_EXT) == 0 )
1304 fScope = ObjectFile::Atom::scopeTranslationUnit;
1305 else if ( (type & N_PEXT) != 0 )
1306 fScope = ObjectFile::Atom::scopeLinkageUnit;
1308 fScope = ObjectFile::Atom::scopeGlobal;
1309 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1314 template <typename A>
1315 class Reader : public ObjectFile::Reader
1318 static bool validFile(const uint8_t* fileContent);
1319 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1320 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
1321 virtual ~Reader() {}
1323 virtual const char* getPath() { return fPath; }
1324 virtual time_t getModificationTime() { return fModTime; }
1325 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1326 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1327 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1328 virtual std::vector<Stab>* getStabs() { return &fStabs; }
1329 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
1330 virtual uint32_t updateCpuConstraint(uint32_t current);
1331 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1332 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
1333 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
1335 bool getTranslationUnitSource(const char** dir, const char** name) const;
1338 typedef typename A::P P;
1339 typedef typename A::P::E E;
1340 typedef typename A::P::uint_t pint_t;
1341 //typedef typename std::vector<Atom<A>*> AtomVector;
1342 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1343 typedef typename A::ReferenceKinds Kinds;
1344 friend class AnonymousAtom<A>;
1345 friend class TentativeAtom<A>;
1346 friend class AbsoluteAtom<A>;
1347 friend class SymbolAtom<A>;
1348 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
1350 void addReferencesForSection(const macho_section<P>* sect);
1351 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1352 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1353 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1354 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1355 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1356 static const char* assureFullPath(const char* path);
1357 AtomAndOffset findAtomAndOffset(pint_t addr);
1358 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1359 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1360 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1361 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1362 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1363 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
1364 Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
1365 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
1366 void validSectionType(uint8_t type);
1367 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1368 void setCpuConstraint(uint32_t cpusubtype);
1370 BaseAtom* findAtomByName(const char*);
1374 uint32_t fOrdinalBase;
1375 const ObjectFile::ReaderOptions& fOptions;
1376 const macho_header<P>* fHeader;
1377 const char* fStrings;
1378 const macho_nlist<P>* fSymbols;
1379 uint32_t fSymbolCount;
1380 const macho_segment_command<P>* fSegment;
1381 const uint32_t* fIndirectTable;
1382 std::vector<BaseAtom*> fAtoms;
1383 AddrToAtomMap fAddrToAtom;
1384 AddrToAtomMap fAddrToAbsoluteAtom;
1385 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
1386 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1387 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1388 std::vector<const char*> fDtraceProviderInfo;
1389 ObjectFile::Reader::DebugInfoKind fDebugInfo;
1391 const macho_section<P>* fDwarfDebugInfoSect;
1392 const macho_section<P>* fDwarfDebugAbbrevSect;
1393 const macho_section<P>* fDwarfDebugLineSect;
1394 const char* fDwarfTranslationUnitDir;
1395 const char* fDwarfTranslationUnitFile;
1396 std::map<uint32_t,const char*> fDwarfIndexToFile;
1397 std::vector<Stab> fStabs;
1399 bool fHasDTraceProbes;
1400 bool fHaveIndirectSymbols;
1401 bool fReplacementClasses;
1402 bool fHasLongBranchStubs;
1403 ObjectFile::Reader::ObjcConstraint fObjConstraint;
1404 uint32_t fCpuConstraint;
1407 template <typename A>
1408 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1409 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
1410 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
1411 fDebugInfo(kDebugInfoNone), fHasUUID(false), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
1412 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
1413 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
1414 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny)
1417 if ( ! validFile(fileContent) )
1418 throw "not a valid mach-o object file";
1420 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1422 // write out path for -t or -whatsloaded option
1423 if ( options.fLogObjectFiles || options.fLogAllFiles )
1424 printf("%s\n", path);
1426 // cache intersting pointers
1427 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1428 this->setCpuConstraint(header->cpusubtype());
1429 const uint32_t cmd_count = header->ncmds();
1430 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
1431 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
1432 const macho_load_command<P>* cmd = cmds;
1433 uint32_t undefinedStartIndex = 0;
1434 uint32_t undefinedEndIndex = 0;
1435 for (uint32_t i = 0; i < cmd_count; ++i) {
1436 switch (cmd->cmd()) {
1439 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1440 fSymbolCount = symtab->nsyms();
1441 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1442 fStrings = (char*)header + symtab->stroff();
1443 if ( undefinedEndIndex == 0 ) {
1444 undefinedStartIndex = 0;
1445 undefinedEndIndex = symtab->nsyms();
1451 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1452 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
1453 undefinedStartIndex = dsymtab->iundefsym();
1454 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
1462 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1463 fSegment = (macho_segment_command<P>*)cmd;
1467 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
1468 if ( cmd > cmdsEnd )
1469 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
1472 // if there are no load commands, then this file has no content, so no atoms
1473 if ( header->ncmds() < 1 )
1476 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1477 const macho_section<P>* const sectionsEnd = §ionsStart[fSegment->nsects()];
1479 // inital guess for number of atoms
1480 fAtoms.reserve(fSymbolCount);
1482 // add all atoms that have entries in symbol table
1483 const macho_section<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1484 for (int i=fSymbolCount-1; i >= 0 ; --i) {
1485 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the reaal name
1486 const macho_nlist<P>& sym = fSymbols[i];
1487 if ( (sym.n_type() & N_STAB) == 0 ) {
1488 uint8_t type = (sym.n_type() & N_TYPE);
1489 if ( type == N_SECT ) {
1490 const macho_section<P>* section = §ions[sym.n_sect()-1];
1491 pint_t sectionEndAddr = section->addr() + section->size();
1492 bool suppress = false;
1493 // ignore atoms in debugger sections
1494 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
1495 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
1496 // ignore dtrace probe labels
1497 fHasDTraceProbes = true;
1499 else if ( fStrings[sym.n_strx()] == 'L' ) {
1500 // ignore L labels, <rdar://problem/3962731>
1503 // ignore labels for atoms in other sections
1504 switch ( section->flags() & SECTION_TYPE ) {
1506 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
1507 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
1510 case S_4BYTE_LITERALS:
1511 case S_8BYTE_LITERALS:
1512 case S_16BYTE_LITERALS:
1513 case S_CSTRING_LITERALS:
1516 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
1517 if ( (pos != fAddrToAtom.end()) && (strcmp(pos->second->getSectionName(), section->sectname())==0) ) {
1518 // another label to an existing address in the same section, make this an alias
1519 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
1522 // make SymbolAtom atom for this address
1523 newAtom = new SymbolAtom<A>(*this, &sym, section);
1524 // don't add symbols at end of section to addr->atom map
1525 if ( sym.n_value() != sectionEndAddr )
1526 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
1529 fAtoms.push_back(newAtom);
1532 case S_SYMBOL_STUBS:
1533 case S_LAZY_SYMBOL_POINTERS:
1534 case S_NON_LAZY_SYMBOL_POINTERS:
1535 // ignore symboled stubs produces by old ld64
1538 warning("symbol %s found in unsupported section in %s",
1539 &fStrings[sym.n_strx()], this->getPath());
1544 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
1545 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
1547 else if ( type == N_ABS ) {
1548 const char* symName = &fStrings[sym.n_strx()];
1549 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
1550 // ignore .objc_class_name_* symbols
1553 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
1554 // ignore empty *.eh symbols
1557 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
1558 fAtoms.push_back(abAtom);
1559 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
1562 else if ( type == N_INDR ) {
1563 fHaveIndirectSymbols = true;
1568 // add all fixed size anonymous atoms from special sections
1569 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1570 pint_t atomSize = 0;
1571 uint8_t type (sect->flags() & SECTION_TYPE);
1572 validSectionType(type);
1573 bool suppress = false;
1575 case S_SYMBOL_STUBS:
1577 atomSize = sect->reserved2();
1579 case S_LAZY_SYMBOL_POINTERS:
1581 atomSize = sizeof(pint_t);
1583 case S_NON_LAZY_SYMBOL_POINTERS:
1584 case S_LITERAL_POINTERS:
1585 case S_MOD_INIT_FUNC_POINTERS:
1586 case S_MOD_TERM_FUNC_POINTERS:
1587 atomSize = sizeof(pint_t);
1590 atomSize = sizeof(pint_t)*2;
1592 case S_4BYTE_LITERALS:
1595 case S_8BYTE_LITERALS:
1598 case S_16BYTE_LITERALS:
1602 // special case ObjC classes to synthesize .objc_class_name_* symbols
1603 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
1604 // gcc sometimes over aligns class structure
1605 uint32_t align = 1 << sect->align();
1606 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
1608 // get objc Garbage Collection info
1609 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
1610 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
1611 // struct objc_image_info {
1612 // uint32_t version; // initially 0
1615 // #define OBJC_IMAGE_SUPPORTS_GC 2
1616 // #define OBJC_IMAGE_GC_ONLY 4
1618 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
1619 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
1620 uint32_t flags = E::get32(contents[1]);
1621 if ( (flags & 4) == 4 )
1622 fObjConstraint = ObjectFile::Reader::kObjcGC;
1623 else if ( (flags & 2) == 2 )
1624 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
1626 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
1627 if ( (flags & 1) == 1 )
1628 fReplacementClasses = true;
1629 // don't make atom for this section
1630 atomSize = sect->size();
1634 warning("can't parse __OBJC/__image_info section in %s", fPath);
1637 // special case constant NS/CFString literals and make an atom out of each one
1638 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
1639 atomSize = 4 * sizeof(pint_t);
1643 if ( atomSize != 0 ) {
1644 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
1645 pint_t atomAddr = sect->addr() + sectOffset;
1646 // add if not already an atom at that address
1647 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
1648 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
1650 fAtoms.push_back(newAtom);
1651 fAddrToAtom[atomAddr] = newAtom->redirectTo();
1657 // add all c-string anonymous atoms
1658 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1659 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
1662 BaseAtom* mostAlignedEmptyString = NULL;
1663 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
1664 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
1665 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
1666 stringAddr = sect->addr() + sectOffset;
1667 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
1668 // add if not already an atom at that address
1669 if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) {
1670 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
1671 if ( stringLen == 1 ) {
1672 // because of padding it may look like there are lots of empty strings, keep track of all
1673 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
1674 // record empty string with greatest alignment requirement
1675 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
1676 if ( (mostAlignedEmptyString == NULL)
1677 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
1678 mostAlignedEmptyString = newAtom;
1679 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
1683 fAtoms.push_back(newAtom);
1684 fAddrToAtom[stringAddr] = newAtom;
1688 // map all uses of empty strings to the most aligned one
1689 if ( mostAlignedEmptyString != NULL ) {
1690 // make most aligned atom a real atom
1691 fAtoms.push_back(mostAlignedEmptyString);
1692 // map all other empty atoms to this one
1693 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
1694 fAddrToAtom[it->first] = mostAlignedEmptyString;
1700 // sort all atoms so far by address and section
1701 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
1703 //fprintf(stderr, "sorted atoms:\n");
1704 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
1705 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
1707 // create atoms to cover any non-debug ranges not handled above
1708 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1709 pint_t sectionStartAddr = sect->addr();
1710 pint_t sectionEndAddr = sect->addr() + sect->size();
1711 const bool setFollowOnAtom = ! this->canScatterAtoms();
1712 if ( sect->size() != 0 ) {
1713 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1714 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
1715 fDebugInfo = kDebugInfoDwarf;
1716 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
1717 fDwarfDebugInfoSect = sect;
1718 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
1719 fDwarfDebugAbbrevSect = sect;
1720 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
1721 fDwarfDebugLineSect = sect;
1724 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
1725 throw "object file contains old DWARF debug info - rebuild with newer compiler";
1727 uint8_t type (sect->flags() & SECTION_TYPE);
1732 // if there is not an atom already at the start of this section, add an anonymous one
1733 pint_t previousAtomAddr = 0;
1734 BaseAtom* previousAtom = NULL;
1735 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
1736 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
1737 fAddrToAtom[sect->addr()] = newAtom;
1738 fAtoms.push_back(newAtom);
1739 previousAtomAddr = sectionStartAddr;
1740 previousAtom = newAtom;
1741 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
1743 // calculate size of all atoms in this section and add follow-on references
1744 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
1745 BaseAtom* atom = (BaseAtom*)(*it);
1746 pint_t atomAddr = atom->getObjectAddress();
1747 if ( atom->getSectionRecord() == sect ) {
1748 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
1749 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
1750 previousAtom->setSize(atomAddr - previousAtomAddr);
1751 if ( setFollowOnAtom && (atom != previousAtom) )
1752 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
1754 previousAtomAddr = atomAddr;
1755 previousAtom = atom;
1758 if ( previousAtom != NULL ) {
1759 // set last atom in section
1760 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
1768 // check for object file that defines no objc classes, but uses objc classes
1769 // check for dtrace provider info
1770 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
1771 const macho_nlist<P>& sym = fSymbols[i];
1772 if ( (sym.n_type() & N_STAB) == 0 ) {
1773 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
1774 const char* undefinedName = &fStrings[sym.n_strx()];
1775 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
1778 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
1779 if ( strchr(undefinedName, '$') != NULL ) {
1780 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
1781 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
1782 // is extra provider info
1783 fDtraceProviderInfo.push_back(undefinedName);
1791 // add relocation based references to sections that have atoms with pending names
1792 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1793 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
1794 addReferencesForSection(sect);
1797 // update any anonymous atoms that need references built in order to name themselves
1798 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
1799 (*it)->resolveName();
1802 // add relocation based references to other sections
1803 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1804 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
1805 addReferencesForSection(sect);
1808 // add objective-c references
1810 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1811 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
1812 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
1813 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
1814 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
1815 if ( classRef->getFixUpOffset() == 0 ) {
1816 const char* classStr = classRef->getTargetName();
1817 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
1818 const char* className;
1819 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
1820 new Reference<A>(A::kNoFixUp, ao, className, 0);
1828 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
1829 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
1830 AnonymousAtom<A>* localNonLazy = *it;
1831 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
1832 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
1833 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
1836 // add implicit direct reference from each C++ function to its eh info
1837 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1838 if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
1839 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1840 // note: this algorithm depens on the map iterator returning entries in address order
1841 if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) {
1842 pint_t ehAtomAddress = it->first;
1843 BaseAtom* ehAtom = it->second;
1844 const char* ehName = ehAtom->getName();
1845 if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) ) {
1846 makeReferenceToEH(ehName, ehAtomAddress, sect);
1847 // make EH symbol static so linker does not try to coalesce
1848 if ( fOptions.fForFinalLinkedImage )
1849 ehAtom->setScope(ObjectFile::Atom::scopeTranslationUnit);
1850 // if it has a reference to a LSDA, add a group reference
1851 std::vector<class ObjectFile::Reference*>& ehrefs = ehAtom->getReferences();
1852 // all FDE's have at least 2 references (to CIE and to function)
1853 if ( ehrefs.size() > 2 ) {
1854 // a third reference means there is a LSDA
1855 ObjectFile::Atom* lsdaAtom = NULL;
1856 for (std::vector<ObjectFile::Reference*>::iterator rit=ehrefs.begin(); rit != ehrefs.end(); rit++) {
1857 ObjectFile::Reference* ref = *rit;
1858 switch ( ref->getFixUpOffset() ) {
1861 // these are CIE and function references
1864 // this is LSDA reference
1865 lsdaAtom = &ref->getTarget();
1868 if ( lsdaAtom != NULL ) {
1869 new Reference<A>(A::kGroupSubordinate, AtomAndOffset(ehAtom), AtomAndOffset(lsdaAtom));
1878 // add command line aliases
1879 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
1880 BaseAtom* target = this->findAtomByName(it->realName);
1881 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
1882 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
1885 // add dtrace probe locations
1886 if ( fHasDTraceProbes ) {
1887 for (uint32_t i=0; i < fSymbolCount; ++i) {
1888 const macho_nlist<P>& sym = fSymbols[i];
1889 if ( (sym.n_type() & N_STAB) == 0 ) {
1890 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
1891 const char* symbolName = &fStrings[sym.n_strx()];
1892 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
1893 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
1894 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
1901 // turn indirect symbols int SymbolAliasAtom
1902 if ( fHaveIndirectSymbols ) {
1903 for (uint32_t i=0; i < fSymbolCount; ++i) {
1904 const macho_nlist<P>& sym = fSymbols[i];
1905 if ( (sym.n_type() & N_STAB) == 0 ) {
1906 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
1907 const char* aliasName = &fStrings[sym.n_strx()];
1908 const char* targetName = &fStrings[sym.n_value()];
1909 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
1910 BaseAtom* target = this->findAtomByName(targetName);
1911 // only currently support N_INDR based aliases to something in the same .o file
1912 if ( target != NULL ) {
1913 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
1914 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
1921 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1922 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
1925 // add translation unit info from dwarf
1927 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1928 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
1929 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
1930 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
1931 // if can't parse dwarf, warn and give up
1932 fDwarfTranslationUnitFile = NULL;
1933 fDwarfTranslationUnitDir = NULL;
1934 warning("can't parse dwarf compilation unit info in %s", this->getPath());
1935 fDebugInfo = kDebugInfoNone;
1940 // add line number info to atoms from dwarf
1941 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1942 // file with just data will have no __debug_line info
1943 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
1944 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
1945 // validate stmt_list
1946 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
1947 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
1948 if ( debug_line != NULL ) {
1949 struct line_reader_data* lines = line_open(&debug_line[stmtList],
1950 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
1951 struct line_info result;
1952 ObjectFile::Atom* curAtom = NULL;
1953 uint32_t curAtomOffset = 0;
1954 uint32_t curAtomAddress = 0;
1955 uint32_t curAtomSize = 0;
1956 while ( line_next (lines, &result, line_stop_pc) ) {
1957 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
1958 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
1959 // work around weird debug line table compiler generates if no functions in __text section
1960 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
1962 // for performance, see if in next pc is in current atom
1963 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
1964 curAtomOffset = result.pc - curAtomAddress;
1966 // or pc at end of current atom
1967 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
1968 curAtomOffset = result.pc - curAtomAddress;
1971 // do slow look up of atom by address
1972 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
1974 if ( curAtom == NULL )
1975 break; // file has line info but no functions
1976 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
1977 // a one line function can be returned by line_next() as one entry with pc at end of blob
1978 // look for alt atom starting at end of previous atom
1979 uint32_t previousEnd = curAtomAddress+curAtomSize;
1980 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
1981 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
1983 curAtomOffset = alt.offset;
1984 curAtomAddress = previousEnd - alt.offset;
1985 curAtomSize = curAtom->getSize();
1988 curAtomOffset = ao.offset;
1989 curAtomAddress = result.pc - ao.offset;
1990 curAtomSize = curAtom->getSize();
1994 curAtomOffset = ao.offset;
1995 curAtomAddress = result.pc - ao.offset;
1996 curAtomSize = curAtom->getSize();
1999 const char* filename;
2000 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2001 if ( pos == fDwarfIndexToFile.end() ) {
2002 filename = line_file(lines, result.file);
2003 fDwarfIndexToFile[result.file] = filename;
2006 filename = pos->second;
2008 ObjectFile::LineInfo info;
2009 info.atomOffset = curAtomOffset;
2010 info.fileName = filename;
2011 info.lineNumber = result.line;
2012 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2013 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2014 ((BaseAtom*)curAtom)->addLineInfo(info);
2015 if ( result.end_of_sequence ) {
2022 warning("could not parse dwarf line number info in %s", this->getPath());
2028 // if no dwarf, try processing stabs debugging info
2029 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2030 // scan symbol table for stabs entries
2031 fStabs.reserve(fSymbolCount); // reduce re-allocations
2032 BaseAtom* currentAtom = NULL;
2033 pint_t currentAtomAddress = 0;
2034 enum { start, inBeginEnd, inFun } state = start;
2035 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2036 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2037 bool useStab = true;
2038 uint8_t type = sym->n_type();
2039 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2040 if ( (type & N_STAB) != 0 ) {
2041 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
2045 stab.other = sym->n_sect();
2046 stab.desc = sym->n_desc();
2047 stab.value = sym->n_value();
2053 // beginning of function block
2055 // fall into case to lookup atom by addresss
2058 currentAtomAddress = sym->n_value();
2059 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2060 if ( currentAtom != NULL ) {
2061 stab.atom = currentAtom;
2062 stab.string = symString;
2065 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
2066 (uint64_t)sym->n_value(), path);
2075 // not associated with an atom, just copy
2076 stab.string = symString;
2080 // n_value field is NOT atom address ;-(
2081 // need to find atom by name match
2082 const char* colon = strchr(symString, ':');
2083 if ( colon != NULL ) {
2084 // build underscore leading name
2085 int nameLen = colon - symString;
2086 char symName[nameLen+2];
2087 strlcpy(&symName[1], symString, nameLen+1);
2089 symName[nameLen+1] = '\0';
2090 currentAtom = findAtomByName(symName);
2091 if ( currentAtom != NULL ) {
2092 stab.atom = currentAtom;
2093 stab.string = symString;
2097 // might be a debug-note without trailing :G()
2098 currentAtom = findAtomByName(symString);
2099 if ( currentAtom != NULL ) {
2100 stab.atom = currentAtom;
2101 stab.string = symString;
2104 if ( stab.atom == NULL ) {
2105 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
2111 // old style stabs without BNSYM
2113 currentAtomAddress = sym->n_value();
2114 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2115 if ( currentAtom != NULL ) {
2116 stab.atom = currentAtom;
2117 stab.string = symString;
2120 warning("can't find atom for stabs FUN at %08llX in %s",
2121 (uint64_t)currentAtomAddress, path);
2126 stab.string = symString;
2132 stab.string = symString;
2133 // -gfull built .o file
2136 warning("unknown stabs type 0x%X in %s", type, path);
2140 stab.atom = currentAtom;
2149 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2150 if ( nestedAtom != NULL ) {
2151 stab.atom = nestedAtom;
2152 stab.string = symString;
2155 warning("can't find atom for stabs 0x%X at %08llX in %s",
2156 type, (uint64_t)sym->n_value(), path);
2163 // adjust value to be offset in atom
2164 stab.value -= currentAtomAddress;
2166 stab.string = symString;
2173 if ( sym->n_sect() != 0 ) {
2174 // found another start stab, must be really old stabs...
2175 currentAtomAddress = sym->n_value();
2176 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2177 if ( currentAtom != NULL ) {
2178 stab.atom = currentAtom;
2179 stab.string = symString;
2182 warning("can't find atom for stabs FUN at %08llX in %s",
2183 (uint64_t)currentAtomAddress, path);
2187 // found ending stab, switch back to start state
2188 stab.string = symString;
2189 stab.atom = currentAtom;
2197 // adjust value to be offset in atom
2198 stab.value -= currentAtomAddress;
2199 stab.atom = currentAtom;
2202 stab.string = symString;
2206 stab.atom = currentAtom;
2207 stab.string = symString;
2212 // add to list of stabs for this .o file
2214 fStabs.push_back(stab);
2220 // special case precompiled header .o file (which has no content) to have one empty atom
2221 if ( fAtoms.size() == 0 ) {
2222 int pathLen = strlen(path);
2223 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2224 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2225 //phony->fSynthesizedName = ".gch.o";
2226 fAtoms.push_back(phony);
2231 // sort all atoms by address
2232 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2234 // set ordinal and sort references in each atom
2235 uint32_t index = fOrdinalBase;
2236 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2237 BaseAtom* atom = (BaseAtom*)(*it);
2238 atom->setOrdinal(index++);
2239 atom->sortReferences();
2246 void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
2248 switch (cpusubtype) {
2249 case CPU_SUBTYPE_POWERPC_ALL:
2250 case CPU_SUBTYPE_POWERPC_750:
2251 case CPU_SUBTYPE_POWERPC_7400:
2252 case CPU_SUBTYPE_POWERPC_7450:
2253 case CPU_SUBTYPE_POWERPC_970:
2254 fCpuConstraint = cpusubtype;
2257 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
2258 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
2264 void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
2266 switch (cpusubtype) {
2267 case CPU_SUBTYPE_ARM_ALL:
2268 case CPU_SUBTYPE_ARM_V4T:
2269 case CPU_SUBTYPE_ARM_V5TEJ:
2270 case CPU_SUBTYPE_ARM_V6:
2271 case CPU_SUBTYPE_ARM_XSCALE:
2272 fCpuConstraint = cpusubtype;
2275 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
2276 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
2281 template <typename A>
2282 void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
2284 // no cpu sub types for this architecture
2288 uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
2290 switch ( previous ) {
2291 case CPU_SUBTYPE_POWERPC_ALL:
2292 return fCpuConstraint;
2294 case CPU_SUBTYPE_POWERPC_750:
2295 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
2296 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
2297 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
2298 return fCpuConstraint;
2300 case CPU_SUBTYPE_POWERPC_7400:
2301 case CPU_SUBTYPE_POWERPC_7450:
2302 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
2303 return fCpuConstraint;
2305 case CPU_SUBTYPE_POWERPC_970:
2306 // G5 can run everything
2309 throw "Unhandled PPC cpu subtype!";
2318 uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
2321 case CPU_SUBTYPE_ARM_ALL:
2322 return fCpuConstraint;
2324 case CPU_SUBTYPE_ARM_V5TEJ:
2325 // v6 and xscale are more constrained than previous file (v5), so use it
2326 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
2327 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
2328 return fCpuConstraint;
2330 case CPU_SUBTYPE_ARM_V4T:
2331 // v5, v6, and xscale are more constrained than previous file (v4t), so use it
2332 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
2333 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
2334 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
2335 return fCpuConstraint;
2337 case CPU_SUBTYPE_ARM_V6:
2338 // v6 can run everything except xscale
2339 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
2340 throw "can't mix xscale and v6 code";
2342 case CPU_SUBTYPE_ARM_XSCALE:
2343 // xscale can run everything except v6
2344 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
2345 throw "can't mix xscale and v6 code";
2348 throw "Unhandled ARM cpu subtype!";
2353 template <typename A>
2354 uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
2356 // no cpu sub types for this architecture
2360 template <typename A>
2361 void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
2363 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
2364 // a matching provider name, add a by-name kDtraceTypeReference at probe site
2365 const char* dollar = strchr(providerName, '$');
2366 if ( dollar != NULL ) {
2367 int providerNameLen = dollar-providerName+1;
2368 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
2369 const char* typeDollar = strchr(*it, '$');
2370 if ( typeDollar != NULL ) {
2371 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
2372 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
2381 void Reader<x86_64>::validSectionType(uint8_t type)
2384 case S_SYMBOL_STUBS:
2385 throw "symbol_stub sections not valid in x86_64 object files";
2386 case S_LAZY_SYMBOL_POINTERS:
2387 throw "lazy pointer sections not valid in x86_64 object files";
2388 case S_NON_LAZY_SYMBOL_POINTERS:
2389 throw "non lazy pointer sections not valid in x86_64 object files";
2393 template <typename A>
2394 void Reader<A>::validSectionType(uint8_t type)
2398 template <typename A>
2399 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
2401 if ( fDebugInfo == kDebugInfoDwarf ) {
2402 *dir = fDwarfTranslationUnitDir;
2403 *name = fDwarfTranslationUnitFile;
2404 return (fDwarfTranslationUnitFile != NULL);
2409 template <typename A>
2410 BaseAtom* Reader<A>::findAtomByName(const char* name)
2412 // first search the more important atoms
2413 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
2414 const char* atomName = it->second->getName();
2415 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
2419 // try all atoms, because this might have been a tentative definition
2420 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2421 BaseAtom* atom = (BaseAtom*)(*it);
2422 const char* atomName = atom->getName();
2423 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
2430 template <typename A>
2431 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
2433 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
2436 template <typename A>
2437 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
2439 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
2442 template <typename A>
2443 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
2445 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
2448 template <typename A>
2449 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
2451 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
2454 template <typename A>
2455 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
2457 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
2460 template <typename A>
2461 Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
2463 // add a direct reference from function atom to its eh frame atom
2464 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
2465 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
2466 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
2467 return makeReference(A::kGroupSubordinate, funcAddr, ehAtomAddress);
2472 Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
2474 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
2475 // instead check scope of target
2476 BaseAtom* target = findAtomByName(toName);
2477 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
2478 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
2480 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
2484 Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
2486 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
2487 // instead check scope of target
2488 const char* symbolName = &fStrings[toSymbol->n_strx()];
2489 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) )
2490 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset));
2492 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
2497 Reference<x86_64>* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
2499 // add a direct reference from function atom to its eh frame atom
2500 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
2501 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
2502 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
2503 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
2504 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2505 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
2506 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
2507 return makeReference(x86_64::kGroupSubordinate, funcAddr, ehAtomAddress);
2510 warning("can't find matching function for eh symbol %s", ehName);
2515 template <typename A>
2516 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
2518 // STL has no built-in for "find largest key that is same or less than"
2519 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
2520 // if no atoms up to this address return none found
2521 if ( it == fAddrToAtom.begin() )
2522 return AtomAndOffset(NULL);
2523 // otherwise upper_bound gets us next key, so we back up one
2525 AtomAndOffset result;
2526 result.atom = it->second;
2527 result.offset = addr - it->first;
2528 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
2529 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
2533 // "scattered" relocations enable you to offset into an atom past the end of it
2534 // baseAddr is the address of the target atom,
2535 // realAddr is the points into it
2536 template <typename A>
2537 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
2539 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
2540 if ( it != fAddrToAtom.end() ) {
2541 AtomAndOffset result;
2542 result.atom = it->second;
2543 result.offset = realAddr - it->first;
2544 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
2547 // getting here means we have a scattered relocation to an address without a label
2548 // we should never get here...
2549 // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
2550 return findAtomAndOffset(realAddr);
2554 /* Skip over a LEB128 value (signed or unsigned). */
2556 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
2558 while (*offset != end && **offset >= 0x80)
2564 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
2565 or error. On overflow, skip past the rest of the uleb128. */
2567 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
2569 uint64_t result = 0;
2576 return (uint64_t) -1;
2578 b = **offset & 0x7f;
2580 if (bit >= 64 || b << bit >> bit != b)
2581 result = (uint64_t) -1;
2583 result |= b << bit, bit += 7;
2584 } while (*(*offset)++ >= 0x80);
2589 /* Skip over a DWARF attribute of form FORM. */
2590 template <typename A>
2591 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
2592 uint8_t addr_size, bool dwarf64)
2602 case DW_FORM_block2:
2603 if (end - *offset < 2)
2605 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
2608 case DW_FORM_block4:
2609 if (end - *offset < 4)
2611 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
2629 case DW_FORM_string:
2630 while (*offset != end && **offset)
2639 sz = read_uleb128 (offset, end);
2642 case DW_FORM_block1:
2650 case DW_FORM_ref_udata:
2651 skip_leb128 (offset, end);
2655 case DW_FORM_ref_addr:
2656 sz = dwarf64 ? 8 : 4;
2662 if (end - *offset < sz)
2668 // Look at the compilation unit DIE and determine
2669 // its NAME, compilation directory (in COMP_DIR) and its
2670 // line number information offset (in STMT_LIST). NAME and COMP_DIR
2671 // may be NULL (especially COMP_DIR) if they are not in the .o file;
2672 // STMT_LIST will be (uint64_t) -1.
2674 // At present this assumes that there's only one compilation unit DIE.
2676 template <typename A>
2677 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
2678 uint64_t *stmt_list)
2680 const uint8_t * debug_info;
2681 const uint8_t * debug_abbrev;
2684 const uint8_t * end;
2685 const uint8_t * enda;
2688 uint64_t abbrev_base;
2690 uint8_t address_size;
2695 *stmt_list = (uint64_t) -1;
2697 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
2700 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
2701 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
2704 if (fDwarfDebugInfoSect->size() < 12)
2705 /* Too small to be a real debug_info section. */
2707 sz = A::P::E::get32(*(uint32_t*)di);
2709 dwarf64 = sz == 0xffffffff;
2711 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
2712 else if (sz > 0xffffff00)
2713 /* Unknown dwarf format. */
2716 /* Verify claimed size. */
2717 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
2720 vers = A::P::E::get16(*(uint16_t*)di);
2721 if (vers < 2 || vers > 3)
2722 /* DWARF version wrong for this code.
2723 Chances are we could continue anyway, but we don't know for sure. */
2727 /* Find the debug_abbrev section. */
2728 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
2729 di += dwarf64 ? 8 : 4;
2731 if (abbrev_base > fDwarfDebugAbbrevSect->size())
2733 da = debug_abbrev + abbrev_base;
2734 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
2736 address_size = *di++;
2738 /* Find the abbrev number we're looking for. */
2740 abbrev = read_uleb128 (&di, end);
2741 if (abbrev == (uint64_t) -1)
2744 /* Skip through the debug_abbrev section looking for that abbrev. */
2747 uint64_t this_abbrev = read_uleb128 (&da, enda);
2750 if (this_abbrev == abbrev)
2751 /* This is almost always taken. */
2753 skip_leb128 (&da, enda); /* Skip the tag. */
2756 da++; /* Skip the DW_CHILDREN_* value. */
2759 attr = read_uleb128 (&da, enda);
2760 skip_leb128 (&da, enda);
2761 } while (attr != 0 && attr != (uint64_t) -1);
2766 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
2767 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
2771 da++; /* Skip the DW_CHILDREN_* value. */
2773 /* Now, go through the DIE looking for DW_AT_name,
2774 DW_AT_comp_dir, and DW_AT_stmt_list. */
2777 uint64_t attr = read_uleb128 (&da, enda);
2778 uint64_t form = read_uleb128 (&da, enda);
2780 if (attr == (uint64_t) -1)
2785 if (form == DW_FORM_indirect)
2786 form = read_uleb128 (&di, end);
2788 if (attr == DW_AT_name && form == DW_FORM_string)
2789 *name = (const char *) di;
2790 else if (attr == DW_AT_comp_dir && form == DW_FORM_string)
2791 *comp_dir = (const char *) di;
2792 /* Really we should support DW_FORM_strp here, too, but
2793 there's usually no reason for the producer to use that form
2794 for the DW_AT_name and DW_AT_comp_dir attributes. */
2795 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
2796 *stmt_list = A::P::E::get32(*(uint32_t*)di);
2797 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
2798 *stmt_list = A::P::E::get64(*(uint64_t*)di);
2799 if (! skip_form (&di, end, form, address_size, dwarf64))
2804 template <typename A>
2805 const char* Reader<A>::assureFullPath(const char* path)
2807 if ( path[0] == '/' )
2809 char cwdbuff[MAXPATHLEN];
2810 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
2812 asprintf(&result, "%s/%s", cwdbuff, path);
2813 if ( result != NULL )
2822 // To implement architecture xxx, you must write template specializations for the following six methods:
2823 // Reader<xxx>::validFile()
2824 // Reader<xxx>::addRelocReference()
2825 // Reference<xxx>::getDescription()
2831 bool Reader<ppc>::validFile(const uint8_t* fileContent)
2833 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2834 if ( header->magic() != MH_MAGIC )
2836 if ( header->cputype() != CPU_TYPE_POWERPC )
2838 if ( header->filetype() != MH_OBJECT )
2844 bool Reader<ppc64>::validFile(const uint8_t* fileContent)
2846 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2847 if ( header->magic() != MH_MAGIC_64 )
2849 if ( header->cputype() != CPU_TYPE_POWERPC64 )
2851 if ( header->filetype() != MH_OBJECT )
2857 bool Reader<x86>::validFile(const uint8_t* fileContent)
2859 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2860 if ( header->magic() != MH_MAGIC )
2862 if ( header->cputype() != CPU_TYPE_I386 )
2864 if ( header->filetype() != MH_OBJECT )
2870 bool Reader<x86_64>::validFile(const uint8_t* fileContent)
2872 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2873 if ( header->magic() != MH_MAGIC_64 )
2875 if ( header->cputype() != CPU_TYPE_X86_64 )
2877 if ( header->filetype() != MH_OBJECT )
2883 bool Reader<arm>::validFile(const uint8_t* fileContent)
2885 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2886 if ( header->magic() != MH_MAGIC )
2888 if ( header->cputype() != CPU_TYPE_ARM )
2890 if ( header->filetype() != MH_OBJECT )
2895 template <typename A>
2896 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
2898 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
2902 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
2904 return addRelocReference_powerpc(sect, reloc);
2908 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
2910 return addRelocReference_powerpc(sect, reloc);
2915 // ppc and ppc64 both use the same relocations, so process them in one common routine
2917 template <typename A>
2918 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
2919 const macho_relocation_info<typename A::P>* reloc)
2924 int32_t displacement = 0;
2925 uint32_t instruction = 0;
2926 uint32_t offsetInTarget;
2928 bool result = false;
2929 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2930 const macho_relocation_info<P>* nextReloc = &reloc[1];
2931 const char* targetName = NULL;
2932 bool weakImport = false;
2933 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2934 if ( reloc->r_type() != PPC_RELOC_PAIR )
2935 instruction = BigEndian::get32(*fixUpPtr);
2936 srcAddr = sect->addr() + reloc->r_address();
2937 if ( reloc->r_extern() ) {
2938 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2939 targetName = &fStrings[targetSymbol->n_strx()];
2940 weakImport = this->isWeakImportSymbol(targetSymbol);
2942 switch ( reloc->r_type() ) {
2943 case PPC_RELOC_BR24:
2945 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2946 displacement = (instruction & 0x03FFFFFC);
2947 if ( (displacement & 0x02000000) != 0 )
2948 displacement |= 0xFC000000;
2951 printf("bad instruction for BR24 reloc");
2953 if ( reloc->r_extern() ) {
2954 offsetInTarget = srcAddr + displacement;
2955 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
2956 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
2957 addDtraceExtraInfos(srcAddr, &targetName[16]);
2959 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
2960 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
2961 addDtraceExtraInfos(srcAddr, &targetName[20]);
2963 else if ( weakImport )
2964 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
2966 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
2969 dstAddr = srcAddr + displacement;
2970 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2971 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
2972 targetName = atom->getName();
2973 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
2974 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
2975 addDtraceExtraInfos(srcAddr, &targetName[16]);
2977 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
2978 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
2979 addDtraceExtraInfos(srcAddr, &targetName[20]);
2981 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
2982 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
2983 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
2985 makeReference(A::kBranch24, srcAddr, dstAddr);
2989 case PPC_RELOC_BR14:
2991 displacement = (instruction & 0x0000FFFC);
2992 if ( (displacement & 0x00008000) != 0 )
2993 displacement |= 0xFFFF0000;
2994 if ( reloc->r_extern() ) {
2995 offsetInTarget = srcAddr + displacement;
2996 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
2999 dstAddr = srcAddr + displacement;
3000 makeReference(A::kBranch14, srcAddr, dstAddr);
3004 case PPC_RELOC_PAIR:
3005 // skip, processed by a previous look ahead
3007 case PPC_RELOC_LO16:
3009 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3010 warning("PPC_RELOC_LO16 missing following pair");
3014 lowBits = (instruction & 0xFFFF);
3015 if ( reloc->r_extern() ) {
3016 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3017 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
3020 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3021 if ( reloc->r_symbolnum() == R_ABS ) {
3022 // find absolute symbol that corresponds to pointerValue
3023 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3024 if ( pos != fAddrToAbsoluteAtom.end() )
3025 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
3027 makeReference(A::kAbsLow16, srcAddr, dstAddr);
3030 makeReference(A::kAbsLow16, srcAddr, dstAddr);
3035 case PPC_RELOC_LO14:
3037 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3038 warning("PPC_RELOC_LO14 missing following pair");
3042 lowBits = (instruction & 0xFFFC);
3043 if ( reloc->r_extern() ) {
3044 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3045 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
3048 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3049 if ( reloc->r_symbolnum() == R_ABS ) {
3050 // find absolute symbol that corresponds to pointerValue
3051 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3052 if ( pos != fAddrToAbsoluteAtom.end() )
3053 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
3055 makeReference(A::kAbsLow14, srcAddr, dstAddr);
3058 makeReference(A::kAbsLow14, srcAddr, dstAddr);
3063 case PPC_RELOC_HI16:
3065 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3066 warning("PPC_RELOC_HI16 missing following pair");
3070 if ( reloc->r_extern() ) {
3071 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
3072 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
3075 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
3076 if ( reloc->r_symbolnum() == R_ABS ) {
3077 // find absolute symbol that corresponds to pointerValue
3078 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3079 if ( pos != fAddrToAbsoluteAtom.end() )
3080 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
3082 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
3085 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
3090 case PPC_RELOC_HA16:
3092 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3093 warning("PPC_RELOC_HA16 missing following pair");
3097 lowBits = (nextReloc->r_address() & 0x0000FFFF);
3098 if ( reloc->r_extern() ) {
3099 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3100 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
3103 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3104 if ( reloc->r_symbolnum() == R_ABS ) {
3105 // find absolute symbol that corresponds to pointerValue
3106 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3107 if ( pos != fAddrToAbsoluteAtom.end() )
3108 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
3110 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
3113 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
3118 case PPC_RELOC_VANILLA:
3120 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
3121 if ( reloc->r_extern() ) {
3123 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
3125 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
3128 makeReference(A::kPointer, srcAddr, pointerValue);
3132 case PPC_RELOC_JBSR:
3133 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
3134 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
3135 warning("PPC_RELOC_JBSR missing following pair");
3138 fHasLongBranchStubs = true;
3140 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
3141 if ( (instruction & 0x4C000000) == 0x48000000 ) {
3142 displacement = (instruction & 0x03FFFFFC);
3143 if ( (displacement & 0x02000000) != 0 )
3144 displacement |= 0xFC000000;
3147 fprintf(stderr, "bad instruction for BR24 reloc");
3149 if ( reloc->r_extern() ) {
3150 fprintf(stderr, "PPC_RELOC_JBSR should not be using an external relocation");
3154 warning("unknown relocation type %d", reloc->r_type());
3158 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3159 srcAddr = sect->addr() + sreloc->r_address();
3160 dstAddr = sreloc->r_value();
3161 uint32_t betterDstAddr;
3162 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3163 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3164 const macho_relocation_info<P>* nextReloc = &reloc[1];
3165 // file format allows pair to be scattered or not
3166 bool nextRelocIsPair = false;
3167 uint32_t nextRelocAddress = 0;
3168 uint32_t nextRelocValue = 0;
3169 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
3170 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
3171 nextRelocIsPair = true;
3172 nextRelocAddress = nextReloc->r_address();
3177 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
3178 nextRelocIsPair = true;
3179 nextRelocAddress = nextSReloc->r_address();
3180 nextRelocValue = nextSReloc->r_value();
3184 switch (sreloc->r_type()) {
3185 case PPC_RELOC_VANILLA:
3187 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
3188 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
3189 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3190 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
3193 case PPC_RELOC_BR14:
3195 instruction = BigEndian::get32(*fixUpPtr);
3196 displacement = (instruction & 0x0000FFFC);
3197 if ( (displacement & 0x00008000) != 0 )
3198 displacement |= 0xFFFF0000;
3199 betterDstAddr = srcAddr+displacement;
3200 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
3201 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
3204 case PPC_RELOC_BR24:
3206 instruction = BigEndian::get32(*fixUpPtr);
3207 if ( (instruction & 0x4C000000) == 0x48000000 ) {
3208 displacement = (instruction & 0x03FFFFFC);
3209 if ( (displacement & 0x02000000) != 0 )
3210 displacement |= 0xFC000000;
3211 betterDstAddr = srcAddr+displacement;
3212 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
3216 case PPC_RELOC_LO16_SECTDIFF:
3218 if ( ! nextRelocIsPair ) {
3219 warning("PPC_RELOC_LO16_SECTDIFF missing following PAIR");
3222 instruction = BigEndian::get32(*fixUpPtr);
3223 lowBits = (instruction & 0xFFFF);
3224 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3225 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3228 case PPC_RELOC_LO14_SECTDIFF:
3230 if ( ! nextRelocIsPair ) {
3231 warning("PPC_RELOC_LO14_SECTDIFF missing following PAIR");
3234 instruction = BigEndian::get32(*fixUpPtr);
3235 lowBits = (instruction & 0xFFFC);
3236 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3237 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3240 case PPC_RELOC_HA16_SECTDIFF:
3242 if ( ! nextRelocIsPair ) {
3243 warning("PPC_RELOC_HA16_SECTDIFF missing following PAIR");
3246 instruction = BigEndian::get32(*fixUpPtr);
3247 lowBits = (nextRelocAddress & 0x0000FFFF);
3248 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3249 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3252 case PPC_RELOC_LO14:
3254 if ( ! nextRelocIsPair ) {
3255 warning("PPC_RELOC_LO14 missing following PAIR");
3258 instruction = BigEndian::get32(*fixUpPtr);
3259 lowBits = (instruction & 0xFFFC);
3260 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3261 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
3264 case PPC_RELOC_LO16:
3266 if ( ! nextRelocIsPair ) {
3267 warning("PPC_RELOC_LO16 missing following PAIR");
3270 instruction = BigEndian::get32(*fixUpPtr);
3271 lowBits = (instruction & 0xFFFF);
3272 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3273 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
3276 case PPC_RELOC_HA16:
3278 if ( ! nextRelocIsPair ) {
3279 warning("PPC_RELOC_HA16 missing following PAIR");
3282 instruction = BigEndian::get32(*fixUpPtr);
3283 lowBits = (nextRelocAddress & 0xFFFF);
3284 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
3285 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
3288 case PPC_RELOC_HI16:
3290 if ( ! nextRelocIsPair ) {
3291 warning("PPC_RELOC_HI16 missing following PAIR");
3294 instruction = BigEndian::get32(*fixUpPtr);
3295 lowBits = (nextRelocAddress & 0xFFFF);
3296 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
3297 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
3300 case PPC_RELOC_SECTDIFF:
3301 case PPC_RELOC_LOCAL_SECTDIFF:
3303 if ( ! nextRelocIsPair ) {
3304 warning("PPC_RELOC_SECTDIFF missing following pair");
3307 Kinds kind = A::kPointerDiff32;;
3308 uint32_t contentAddr = 0;
3309 switch ( sreloc->r_length() ) {
3311 throw "bad diff relocations r_length (0) for ppc architecture";
3313 kind = A::kPointerDiff16;
3314 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
3317 kind = A::kPointerDiff32;
3318 contentAddr = BigEndian::get32(*fixUpPtr);
3321 kind = A::kPointerDiff64;
3322 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
3325 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
3326 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
3327 AtomAndOffset toao = findAtomAndOffset(dstAddr);
3328 // check for addend encoded in the section content
3329 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
3330 // dstAddr, nextRelocValue, contentAddr);
3331 if ( (dstAddr - nextRelocValue) != contentAddr ) {
3332 if ( toao.atom == srcao.atom )
3333 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3334 else if ( fromao.atom == srcao.atom )
3335 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3337 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
3339 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
3340 // srcao.atom->getDisplayName(), srcao.offset,
3341 // fromao.atom->getDisplayName(), fromao.offset,
3342 // toao.atom->getDisplayName(), toao.offset);
3343 new Reference<A>(kind, srcao, fromao, toao);
3346 case PPC_RELOC_PAIR:
3348 case PPC_RELOC_HI16_SECTDIFF:
3349 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
3352 warning("unknown scattered relocation type %d", sreloc->r_type());
3360 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
3365 bool result = false;
3366 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3367 srcAddr = sect->addr() + reloc->r_address();
3368 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3369 switch ( reloc->r_type() ) {
3370 case GENERIC_RELOC_VANILLA:
3372 x86::ReferenceKinds kind = x86::kPointer;
3373 uint32_t pointerValue = E::get32(*fixUpPtr);
3374 if ( reloc->r_pcrel() ) {
3375 switch( reloc->r_length() ) {
3377 kind = x86::kPCRel8;
3378 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
3381 kind = x86::kPCRel16;
3382 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
3385 kind = x86::kPCRel32;
3386 pointerValue += srcAddr + sizeof(uint32_t);
3389 throw "bad pc-rel vanilla relocation length";
3392 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
3393 kind = x86::kAbsolute32;
3394 if ( reloc->r_length() != 2 )
3395 throw "bad vanilla relocation length";
3398 kind = x86::kPointer;
3399 if ( reloc->r_length() != 2 )
3400 throw "bad vanilla relocation length";
3402 if ( reloc->r_extern() ) {
3403 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
3404 if ( this->isWeakImportSymbol(targetSymbol) ) {
3405 if ( reloc->r_pcrel() )
3406 kind = x86::kPCRel32WeakImport;
3408 kind = x86::kPointerWeakImport;
3410 const char* targetName = &fStrings[targetSymbol->n_strx()];
3411 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3412 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
3413 addDtraceExtraInfos(srcAddr, &targetName[16]);
3415 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3416 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3417 addDtraceExtraInfos(srcAddr, &targetName[20]);
3420 makeByNameReference(kind, srcAddr, targetName, pointerValue);
3423 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
3424 ObjectFile::Atom* atom = findAtomAndOffset(pointerValue).atom;
3425 const char* targetName = atom->getName();
3426 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3427 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
3428 addDtraceExtraInfos(srcAddr, &targetName[16]);
3430 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3431 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3432 addDtraceExtraInfos(srcAddr, &targetName[20]);
3434 else if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3435 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3436 makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
3437 else if ( reloc->r_symbolnum() != R_ABS )
3438 makeReference(kind, srcAddr, pointerValue);
3440 // find absolute symbol that corresponds to pointerValue
3441 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
3442 if ( pos != fAddrToAbsoluteAtom.end() )
3443 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
3445 throwf("R_ABS reloc but no absolute symbol at target address");
3451 warning("unknown relocation type %d", reloc->r_type());
3455 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3456 srcAddr = sect->addr() + sreloc->r_address();
3457 dstAddr = sreloc->r_value();
3458 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3459 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3460 const macho_relocation_info<P>* nextReloc = &reloc[1];
3461 pint_t betterDstAddr;
3462 // file format allows pair to be scattered or not
3463 bool nextRelocIsPair = false;
3464 uint32_t nextRelocAddress = 0;
3465 uint32_t nextRelocValue = 0;
3466 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
3467 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
3468 nextRelocIsPair = true;
3469 nextRelocAddress = nextReloc->r_address();
3474 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
3475 nextRelocIsPair = true;
3476 nextRelocAddress = nextSReloc->r_address();
3477 nextRelocValue = nextSReloc->r_value();
3480 switch (sreloc->r_type()) {
3481 case GENERIC_RELOC_VANILLA:
3482 betterDstAddr = LittleEndian::get32(*fixUpPtr);
3483 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
3484 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3485 if ( sreloc->r_pcrel() ) {
3486 betterDstAddr += srcAddr + 4;
3487 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
3490 if ( strcmp(sect->segname(), "__TEXT") == 0 )
3491 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
3493 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
3496 case GENERIC_RELOC_SECTDIFF:
3497 case GENERIC_RELOC_LOCAL_SECTDIFF:
3499 if ( !nextRelocIsPair ) {
3500 warning("GENERIC_RELOC_SECTDIFF missing following pair");
3503 x86::ReferenceKinds kind = x86::kPointerDiff;
3504 uint32_t contentAddr = 0;
3505 switch ( sreloc->r_length() ) {
3508 throw "bad length for GENERIC_RELOC_SECTDIFF";
3510 kind = x86::kPointerDiff16;
3511 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
3514 kind = x86::kPointerDiff;
3515 contentAddr = LittleEndian::get32(*fixUpPtr);
3518 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
3519 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
3520 AtomAndOffset toao = findAtomAndOffset(dstAddr);
3521 // check for addend encoded in the section content
3522 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
3523 // dstAddr, nextRelocValue, contentAddr);
3524 if ( (dstAddr - nextRelocValue) != contentAddr ) {
3525 if ( toao.atom == srcao.atom )
3526 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3527 else if ( fromao.atom == srcao.atom )
3528 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3530 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
3532 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
3533 // srcao.atom->getDisplayName(), srcao.offset,
3534 // fromao.atom->getDisplayName(), fromao.offset,
3535 // toao.atom->getDisplayName(), toao.offset);
3536 new Reference<x86>(kind, srcao, fromao, toao);
3539 case GENERIC_RELOC_PAIR:
3540 // do nothing, already used via a look ahead
3543 warning("unknown scattered relocation type %d", sreloc->r_type());
3550 bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
3553 uint64_t dstAddr = 0;
3556 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
3557 bool result = false;
3558 const macho_nlist<P>* targetSymbol = NULL;
3559 const char* targetName = NULL;
3560 srcAddr = sect->addr() + reloc->r_address();
3561 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3562 //fprintf(stderr, "addReloc type=%d\n", reloc->r_type());
3563 if ( reloc->r_extern() ) {
3564 targetSymbol = &fSymbols[reloc->r_symbolnum()];
3565 targetName = &fStrings[targetSymbol->n_strx()];
3567 switch ( reloc->r_type() ) {
3568 case X86_64_RELOC_UNSIGNED:
3569 if ( reloc->r_pcrel() )
3570 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
3571 if ( reloc->r_length() != 3 )
3572 throw "length < 3 and X86_64_RELOC_UNSIGNED not supported";
3573 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
3574 if ( reloc->r_extern() ) {
3575 makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr);
3578 makeReference(x86_64::kPointer, srcAddr, dstAddr);
3579 // verify that dstAddr is in the section being targeted
3580 int sectNum = reloc->r_symbolnum();
3581 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
3582 const macho_section<P>* const targetSection = §ionsStart[sectNum-1];
3583 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
3584 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
3585 srcAddr, sect->sectname(), targetSection->sectname());
3589 case X86_64_RELOC_SIGNED:
3590 case X86_64_RELOC_SIGNED_1:
3591 case X86_64_RELOC_SIGNED_2:
3592 case X86_64_RELOC_SIGNED_4:
3593 if ( ! reloc->r_pcrel() )
3594 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
3595 if ( reloc->r_length() != 2 )
3596 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
3597 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3598 if ( reloc->r_extern() ) {
3599 switch ( reloc->r_type() ) {
3600 case X86_64_RELOC_SIGNED:
3601 kind = x86_64::kPCRel32;
3602 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
3603 if ( addend == (uint64_t)(-1) ) {
3605 kind = x86_64::kPCRel32_1;
3607 else if ( addend == (uint64_t)(-2) ) {
3609 kind = x86_64::kPCRel32_2;
3611 else if ( addend == (uint64_t)(-4) ) {
3613 kind = x86_64::kPCRel32_4;
3616 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
3617 case X86_64_RELOC_SIGNED_1:
3618 kind = x86_64::kPCRel32_1;
3621 case X86_64_RELOC_SIGNED_2:
3622 kind = x86_64::kPCRel32_2;
3625 case X86_64_RELOC_SIGNED_4:
3626 kind = x86_64::kPCRel32_4;
3630 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
3633 uint64_t ripRelativeOffset = addend;
3634 switch ( reloc->r_type() ) {
3635 case X86_64_RELOC_SIGNED:
3636 dstAddr = srcAddr + 4 + ripRelativeOffset;
3637 kind = x86_64::kPCRel32;
3639 case X86_64_RELOC_SIGNED_1:
3640 dstAddr = srcAddr + 5 + ripRelativeOffset;
3641 kind = x86_64::kPCRel32_1;
3643 case X86_64_RELOC_SIGNED_2:
3644 dstAddr = srcAddr + 6 + ripRelativeOffset;
3645 kind = x86_64::kPCRel32_2;
3647 case X86_64_RELOC_SIGNED_4:
3648 dstAddr = srcAddr + 8 + ripRelativeOffset;
3649 kind = x86_64::kPCRel32_4;
3652 makeReference(kind, srcAddr, dstAddr);
3653 // verify that dstAddr is in the section being targeted
3654 int sectNum = reloc->r_symbolnum();
3655 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
3656 const macho_section<P>* const targetSection = §ionsStart[sectNum-1];
3657 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
3658 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
3659 srcAddr, sect->sectname(), targetSection->sectname());
3663 case X86_64_RELOC_BRANCH:
3664 if ( ! reloc->r_pcrel() )
3665 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
3666 if ( reloc->r_length() == 2 ) {
3667 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3668 if ( reloc->r_extern() ) {
3669 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3670 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
3671 addDtraceExtraInfos(srcAddr, &targetName[16]);
3673 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3674 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3675 addDtraceExtraInfos(srcAddr, &targetName[16]);
3677 else if ( isWeakImportSymbol(targetSymbol) )
3678 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
3680 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
3683 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
3686 else if ( reloc->r_length() == 0 ) {
3687 dstAddr = *((int8_t*)fixUpPtr);
3688 if ( reloc->r_extern() ) {
3689 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
3692 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
3696 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
3699 case X86_64_RELOC_GOT:
3700 if ( ! reloc->r_extern() )
3701 throw "not extern and X86_64_RELOC_GOT not supported";
3702 if ( ! reloc->r_pcrel() )
3703 throw "not pcrel and X86_64_RELOC_GOT not supported";
3704 if ( reloc->r_length() != 2 )
3705 throw "length != 2 and X86_64_RELOC_GOT not supported";
3706 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3707 if ( isWeakImportSymbol(targetSymbol) )
3708 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
3710 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
3712 case X86_64_RELOC_GOT_LOAD:
3713 if ( ! reloc->r_extern() )
3714 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
3715 if ( ! reloc->r_pcrel() )
3716 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
3717 if ( reloc->r_length() != 2 )
3718 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
3719 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3720 if ( isWeakImportSymbol(targetSymbol) )
3721 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
3723 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
3725 case X86_64_RELOC_SUBTRACTOR:
3727 if ( reloc->r_pcrel() )
3728 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
3729 if ( reloc->r_length() < 2 )
3730 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
3731 if ( !reloc->r_extern() )
3732 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
3733 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
3734 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
3735 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
3737 if ( nextReloc->r_pcrel() )
3738 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
3739 if ( nextReloc->r_length() != reloc->r_length() )
3740 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
3741 Reference<x86_64>* ref;
3742 bool negativeAddend;
3743 if ( reloc->r_length() == 2 ) {
3744 kind = x86_64::kPointerDiff32;
3745 dstAddr = E::get32(*fixUpPtr); // addend is in content
3746 negativeAddend = ((dstAddr & 0x80000000) != 0);
3749 kind = x86_64::kPointerDiff;
3750 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
3751 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
3753 ObjectFile::Atom* inAtom = this->findAtomAndOffset(srcAddr).atom;
3754 // create reference with "to" target
3755 if ( nextReloc->r_extern() ) {
3756 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
3757 const char* targetName = &fStrings[targetSymbol->n_strx()];
3758 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
3759 // if "to" is in this atom, change by-name to a direct reference
3760 if ( strcmp(targetName, inAtom->getName()) == 0 )
3761 ref->setTarget(*inAtom, 0);
3764 ref = makeReference(kind, srcAddr, dstAddr);
3766 // add in "from" target
3767 if ( reloc->r_extern() ) {
3768 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
3769 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
3770 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
3771 // from target is translation unit scoped, so use a direct reference
3772 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
3774 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
3775 // if "from" is in this atom, change by-name to a direct reference
3776 ref->setFromTarget(*inAtom);
3779 // some non-static other atom
3780 ref->setFromTargetName(fromTargetName);
3783 // addend goes in from side iff negative
3784 if ( negativeAddend )
3785 ref->setFromTargetOffset(-dstAddr);
3787 ref->setToTargetOffset(dstAddr);
3791 warning("unknown relocation type %d", reloc->r_type());
3797 /// Reader<arm>::addRelocReference -
3798 /// turns arm relocation entries into references. Returns true if the next
3799 /// relocation should be skipped, false otherwise.
3801 bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
3802 const macho_relocation_info<arm::P>* reloc)
3804 uint32_t * fixUpPtr;
3805 int32_t displacement;
3806 uint32_t instruction = 0;
3807 bool result = false;
3810 uint32_t pointerValue;
3812 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3813 // non-scattered relocation
3814 const char* targetName = NULL;
3815 bool weakImport = false;
3817 srcAddr = sect->addr() + reloc->r_address();
3818 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3819 if ( reloc->r_type() != ARM_RELOC_PAIR )
3820 instruction = LittleEndian::get32(*fixUpPtr);
3822 if ( reloc->r_extern() ) {
3823 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
3824 targetName = &fStrings[targetSymbol->n_strx()];
3825 weakImport = this->isWeakImportSymbol(targetSymbol);
3828 switch ( reloc->r_type() ) {
3829 case ARM_RELOC_BR24:
3830 // Sign-extend displacement
3831 displacement = (instruction & 0x00FFFFFF) << 2;
3832 if ( (displacement & 0x02000000) != 0 )
3833 displacement |= 0xFC000000;
3834 // The pc added will be +8 from the pc
3836 // If this is BLX add H << 1
3837 if ((instruction & 0xFE000000) == 0xFA000000)
3838 displacement += ((instruction & 0x01000000) >> 23);
3840 if ( reloc->r_extern() ) {
3841 uint32_t offsetInTarget = srcAddr + displacement;
3842 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3843 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3844 addDtraceExtraInfos(srcAddr, &targetName[16]);
3846 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3847 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3848 addDtraceExtraInfos(srcAddr, &targetName[20]);
3850 else if ( weakImport )
3851 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
3853 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
3856 dstAddr = srcAddr + displacement;
3857 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
3858 // check for dtrace probes and weak_import stubs
3859 const char* targetName = atom->getName();
3860 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3861 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3862 addDtraceExtraInfos(srcAddr, &targetName[16]);
3864 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3865 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3866 addDtraceExtraInfos(srcAddr, &targetName[20]);
3868 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3869 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3870 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
3871 else if ( reloc->r_symbolnum() != R_ABS )
3872 makeReference(arm::kBranch24, srcAddr, dstAddr);
3874 // find absolute symbol that corresponds to pointerValue
3875 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3876 if ( pos != fAddrToAbsoluteAtom.end() )
3877 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
3879 throwf("R_ABS reloc but no absolute symbol at target address");
3884 case ARM_THUMB_RELOC_BR22:
3885 // First instruction has upper 11 bits of the displacement.
3886 displacement = (instruction & 0x7FF) << 12;
3887 if ( (displacement & 0x400000) != 0 )
3888 displacement |= 0xFF800000;
3889 // Second instruction has lower eleven bits of the displacement.
3890 displacement += ((instruction >> 16) & 0x7FF) << 1;
3891 // The pc added will be +4 from the pc
3893 // If the instruction was blx, force the low 2 bits to be clear
3894 dstAddr = srcAddr + displacement;
3895 if ((instruction & 0xF8000000) == 0xE8000000)
3896 dstAddr &= 0xFFFFFFFC;
3898 if ( reloc->r_extern() ) {
3899 uint32_t offsetInTarget = dstAddr;
3900 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3901 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3902 addDtraceExtraInfos(srcAddr, &targetName[16]);
3904 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3905 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3906 addDtraceExtraInfos(srcAddr, &targetName[20]);
3908 else if ( weakImport )
3909 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
3911 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
3914 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
3915 // check for dtrace probes and weak_import stubs
3916 const char* targetName = atom->getName();
3917 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3918 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3919 addDtraceExtraInfos(srcAddr, &targetName[16]);
3921 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3922 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3923 addDtraceExtraInfos(srcAddr, &targetName[20]);
3925 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3926 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3927 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
3928 else if ( reloc->r_symbolnum() != R_ABS )
3929 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
3931 // find absolute symbol that corresponds to pointerValue
3932 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3933 if ( pos != fAddrToAbsoluteAtom.end() )
3934 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
3936 throwf("R_ABS reloc but no absolute symbol at target address");
3941 case ARM_RELOC_VANILLA:
3942 if ( reloc->r_length() != 2 )
3943 throw "bad length for ARM_RELOC_VANILLA";
3945 pointerValue = instruction;
3946 if ( reloc->r_extern() ) {
3948 makeByNameReference(arm::kPointerWeakImport, srcAddr, targetName, pointerValue);
3950 makeByNameReference(arm::kPointer, srcAddr, targetName, pointerValue);
3953 makeReference(arm::kPointer, srcAddr, pointerValue);
3958 warning("unexpected relocation type %u", reloc->r_type());
3963 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3964 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3965 srcAddr = sect->addr() + sreloc->r_address();
3966 dstAddr = sreloc->r_value();
3967 uint32_t betterDstAddr;
3968 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3969 instruction = LittleEndian::get32(*fixUpPtr);
3971 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
3972 // relocation types, and it is an error to see one otherwise.
3973 bool nextRelocIsPair = false;
3974 uint32_t nextRelocAddress = 0;
3975 uint32_t nextRelocValue = 0;
3976 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
3977 nextRelocIsPair = true;
3978 nextRelocAddress = nextSReloc->r_address();
3979 nextRelocValue = nextSReloc->r_value();
3983 switch (sreloc->r_type()) {
3984 case ARM_RELOC_VANILLA:
3985 if ( sreloc->r_length() != 2 )
3986 throw "bad length for ARM_RELOC_VANILLA";
3988 betterDstAddr = LittleEndian::get32(*fixUpPtr);
3989 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
3990 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3991 makeReferenceWithToBase(arm::kPointer, srcAddr, betterDstAddr, dstAddr);
3994 case ARM_RELOC_BR24:
3995 // Sign-extend displacement
3996 displacement = (instruction & 0x00FFFFFF) << 2;
3997 if ( (displacement & 0x02000000) != 0 )
3998 displacement |= 0xFC000000;
3999 // The pc added will be +8 from the pc
4001 // If this is BLX add H << 1
4002 if ((instruction & 0xFE000000) == 0xFA000000)
4003 displacement += ((instruction & 0x01000000) >> 23);
4004 betterDstAddr = srcAddr+displacement;
4005 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
4008 case ARM_THUMB_RELOC_BR22:
4009 // First instruction has upper 11 bits of the displacement.
4010 displacement = (instruction & 0x7FF) << 12;
4011 if ( (displacement & 0x400000) != 0 )
4012 displacement |= 0xFF800000;
4013 // Second instruction has lower eleven bits of the displacement.
4014 displacement += ((instruction >> 16) & 0x7FF) << 1;
4015 // The pc added will be +4 from the pc
4017 betterDstAddr = srcAddr+displacement;
4018 // If the instruction was blx, force the low 2 bits to be clear
4019 if ((instruction & 0xF8000000) == 0xE8000000)
4020 betterDstAddr &= 0xFFFFFFFC;
4021 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
4024 case ARM_RELOC_SECTDIFF:
4025 case ARM_RELOC_LOCAL_SECTDIFF:
4026 if ( !nextRelocIsPair ) {
4027 warning("ARM_RELOC_SECTDIFF missing following pair");
4030 if ( sreloc->r_length() != 2 )
4031 throw "bad length for ARM_RELOC_SECTDIFF";
4033 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4034 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4035 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4036 // check for addend encoded in the section content
4037 pointerValue = LittleEndian::get32(*fixUpPtr);
4038 if ( (dstAddr - nextRelocValue) != pointerValue ) {
4039 if ( toao.atom == srcao.atom )
4040 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
4041 else if ( fromao.atom == srcao.atom )
4042 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
4044 fromao.offset += (dstAddr - pointerValue) - nextRelocValue;
4046 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
4051 warning("unexpected srelocation type %u", sreloc->r_type());
4058 template <typename A>
4059 void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
4061 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
4062 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
4063 switch ( sect->flags() & SECTION_TYPE ) {
4064 case S_SYMBOL_STUBS:
4065 case S_LAZY_SYMBOL_POINTERS:
4066 // we ignore compiler generated stubs, so ignore those relocs too
4069 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
4070 const uint32_t relocCount = sect->nreloc();
4071 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
4072 for (uint32_t r = 0; r < relocCount; ++r) {
4074 if ( addRelocReference(sect, &relocs[r]) )
4077 catch (const char* msg) {
4078 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
4087 const char* Reference<x86>::getDescription() const
4089 static char temp[2048];
4092 sprintf(temp, "reference to ");
4094 case x86::kFollowOn:
4095 sprintf(temp, "followed by ");
4097 case x86::kGroupSubordinate:
4098 sprintf(temp, "group subordinate ");
4100 case x86::kPointerWeakImport:
4101 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4104 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4106 case x86::kPointerDiff:
4108 // by-name references have quoted names
4109 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4110 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4111 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4112 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4113 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4117 case x86::kPointerDiff16:
4119 // by-name references have quoted names
4120 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4121 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4122 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4123 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4124 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4128 case x86::kPCRel32WeakImport:
4129 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
4132 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
4135 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
4138 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
4140 case x86::kAbsolute32:
4141 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
4143 case x86::kDtraceProbe:
4144 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4146 case x86::kDtraceProbeSite:
4147 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4149 case x86::kDtraceIsEnabledSite:
4150 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4152 case x86::kDtraceTypeReference:
4153 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4156 // always quote by-name references
4157 if ( fToTargetName != NULL ) {
4159 strcat(temp, fToTargetName);
4162 else if ( fToTarget.atom != NULL ) {
4163 strcat(temp, fToTarget.atom->getDisplayName());
4166 strcat(temp, "NULL target");
4168 if ( fToTarget.offset != 0 )
4169 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4176 const char* Reference<ppc>::getDescription() const
4178 static char temp[2048];
4181 sprintf(temp, "reference to ");
4183 case ppc::kFollowOn:
4184 sprintf(temp, "followed by ");
4186 case ppc::kGroupSubordinate:
4187 sprintf(temp, "group subordinate ");
4189 case ppc::kPointerWeakImport:
4190 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4193 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4195 case ppc::kPointerDiff16:
4197 // by-name references have quoted names
4198 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4199 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4200 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4201 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4202 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4205 case ppc::kPointerDiff32:
4207 // by-name references have quoted names
4208 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4209 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4210 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4211 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4212 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4215 case ppc::kPointerDiff64:
4216 throw "unsupported refrence kind";
4218 case ppc::kBranch24WeakImport:
4219 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4221 case ppc::kBranch24:
4222 case ppc::kBranch14:
4223 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4225 case ppc::kPICBaseLow16:
4226 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
4228 case ppc::kPICBaseLow14:
4229 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
4231 case ppc::kPICBaseHigh16:
4232 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
4234 case ppc::kAbsLow16:
4235 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
4237 case ppc::kAbsLow14:
4238 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
4240 case ppc::kAbsHigh16:
4241 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
4243 case ppc::kAbsHigh16AddLow:
4244 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
4246 case ppc::kDtraceProbe:
4247 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4249 case ppc::kDtraceProbeSite:
4250 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4252 case ppc::kDtraceIsEnabledSite:
4253 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4255 case ppc::kDtraceTypeReference:
4256 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4259 // always quote by-name references
4260 if ( fToTargetName != NULL ) {
4262 strcat(temp, fToTargetName);
4265 else if ( fToTarget.atom != NULL ) {
4266 strcat(temp, fToTarget.atom->getDisplayName());
4269 strcat(temp, "NULL target");
4271 if ( fToTarget.offset != 0 )
4272 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4278 const char* Reference<ppc64>::getDescription() const
4280 static char temp[2048];
4282 case ppc64::kNoFixUp:
4283 sprintf(temp, "reference to ");
4285 case ppc64::kFollowOn:
4286 sprintf(temp, "followed by ");
4288 case ppc64::kGroupSubordinate:
4289 sprintf(temp, "group subordinate ");
4291 case ppc64::kPointerWeakImport:
4292 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
4294 case ppc64::kPointer:
4295 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
4297 case ppc64::kPointerDiff64:
4299 // by-name references have quoted names
4300 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4301 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4302 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4303 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4304 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4307 case ppc64::kPointerDiff32:
4309 // by-name references have quoted names
4310 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4311 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4312 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4313 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4314 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4317 case ppc64::kPointerDiff16:
4319 // by-name references have quoted names
4320 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4321 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4322 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4323 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4324 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4327 case ppc64::kBranch24WeakImport:
4328 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4330 case ppc64::kBranch24:
4331 case ppc64::kBranch14:
4332 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4334 case ppc64::kPICBaseLow16:
4335 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4337 case ppc64::kPICBaseLow14:
4338 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4340 case ppc64::kPICBaseHigh16:
4341 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4343 case ppc64::kAbsLow16:
4344 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
4346 case ppc64::kAbsLow14:
4347 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
4349 case ppc64::kAbsHigh16:
4350 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
4352 case ppc64::kAbsHigh16AddLow:
4353 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
4355 case ppc64::kDtraceProbe:
4356 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
4358 case ppc64::kDtraceProbeSite:
4359 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
4361 case ppc64::kDtraceIsEnabledSite:
4362 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4364 case ppc64::kDtraceTypeReference:
4365 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
4368 // always quote by-name references
4369 if ( fToTargetName != NULL ) {
4371 strcat(temp, fToTargetName);
4374 else if ( fToTarget.atom != NULL ) {
4375 strcat(temp, fToTarget.atom->getDisplayName());
4378 strcat(temp, "NULL target");
4380 if ( fToTarget.offset != 0 )
4381 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
4388 const char* Reference<x86_64>::getDescription() const
4390 static char temp[2048];
4392 case x86_64::kNoFixUp:
4393 sprintf(temp, "reference to ");
4395 case x86_64::kFollowOn:
4396 sprintf(temp, "followed by ");
4398 case x86_64::kGroupSubordinate:
4399 sprintf(temp, "group subordinate ");
4401 case x86_64::kPointerWeakImport:
4402 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
4404 case x86_64::kPointer:
4405 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
4407 case x86_64::kPointerDiff32:
4408 case x86_64::kPointerDiff:
4410 // by-name references have quoted names
4411 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4412 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4413 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
4414 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4415 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4416 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4420 case x86_64::kPCRel32:
4421 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
4423 case x86_64::kPCRel32_1:
4424 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
4426 case x86_64::kPCRel32_2:
4427 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
4429 case x86_64::kPCRel32_4:
4430 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
4432 case x86_64::kBranchPCRel32:
4433 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
4435 case x86_64::kBranchPCRel32WeakImport:
4436 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
4438 case x86_64::kPCRel32GOT:
4439 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
4441 case x86_64::kPCRel32GOTWeakImport:
4442 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
4444 case x86_64::kPCRel32GOTLoad:
4445 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
4447 case x86_64::kPCRel32GOTLoadWeakImport:
4448 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
4450 case x86_64::kBranchPCRel8:
4451 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
4453 case x86_64::kDtraceProbe:
4454 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
4456 case x86_64::kDtraceProbeSite:
4457 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
4459 case x86_64::kDtraceIsEnabledSite:
4460 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4462 case x86_64::kDtraceTypeReference:
4463 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
4466 // always quote by-name references
4467 if ( fToTargetName != NULL ) {
4469 strcat(temp, fToTargetName);
4472 else if ( fToTarget.atom != NULL ) {
4473 strcat(temp, fToTarget.atom->getDisplayName());
4476 strcat(temp, "NULL target");
4478 if ( fToTarget.offset != 0 )
4479 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
4485 const char* Reference<arm>::getDescription() const
4487 static char temp[2048];
4490 sprintf(temp, "reference to ");
4492 case arm::kFollowOn:
4493 sprintf(temp, "followed by ");
4495 case arm::kGroupSubordinate:
4496 sprintf(temp, "group subordinate ");
4499 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4501 case arm::kPointerWeakImport:
4502 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4504 case arm::kPointerDiff:
4506 // by-name references have quoted names
4507 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4508 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4509 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4510 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4511 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4514 case arm::kBranch24:
4515 case arm::kThumbBranch22:
4516 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4518 case arm::kBranch24WeakImport:
4519 case arm::kThumbBranch22WeakImport:
4520 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4522 case arm::kDtraceProbe:
4523 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4525 case arm::kDtraceProbeSite:
4526 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4528 case arm::kDtraceIsEnabledSite:
4529 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4531 case arm::kDtraceTypeReference:
4532 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4535 // always quote by-name references
4536 if ( fToTargetName != NULL ) {
4538 strcat(temp, fToTargetName);
4541 else if ( fToTarget.atom != NULL ) {
4542 strcat(temp, fToTarget.atom->getDisplayName());
4545 strcat(temp, "NULL target");
4547 if ( fToTarget.offset != 0 )
4548 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4553 }; // namespace relocatable
4554 }; // namespace mach_o
4556 #endif // __OBJECT_FILE_MACH_O__